summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt17
-rw-r--r--src/Makefile.am65
-rw-r--r--src/animatedsprite.cpp1
-rw-r--r--src/animationparticle.cpp1
-rw-r--r--src/being.cpp249
-rw-r--r--src/being.h89
-rw-r--r--src/beingmanager.cpp21
-rw-r--r--src/beingmanager.h39
-rw-r--r--src/configlistener.h1
-rw-r--r--src/configuration.cpp6
-rw-r--r--src/configuration.h6
-rw-r--r--src/effectmanager.cpp106
-rw-r--r--src/effectmanager.h66
-rw-r--r--src/emoteshortcut.cpp77
-rw-r--r--src/emoteshortcut.h125
-rw-r--r--src/engine.cpp41
-rw-r--r--src/equipment.cpp8
-rw-r--r--src/extensions.h34
-rw-r--r--src/floor_item.cpp1
-rw-r--r--src/floor_item.h18
-rw-r--r--src/flooritemmanager.cpp3
-rw-r--r--src/game.cpp330
-rw-r--r--src/game.h48
-rw-r--r--src/graphics.cpp22
-rw-r--r--src/graphics.h20
-rw-r--r--src/gui/browserbox.cpp86
-rw-r--r--src/gui/browserbox.h1
-rw-r--r--src/gui/buddywindow.cpp83
-rw-r--r--src/gui/button.cpp3
-rw-r--r--src/gui/button.h2
-rw-r--r--src/gui/buttonbox.cpp43
-rw-r--r--src/gui/buttonbox.h69
-rw-r--r--src/gui/buy.cpp5
-rw-r--r--src/gui/buy.h6
-rw-r--r--src/gui/buysell.cpp3
-rw-r--r--src/gui/buysell.h2
-rw-r--r--src/gui/char_select.cpp195
-rw-r--r--src/gui/char_select.h9
-rw-r--r--src/gui/char_server.cpp13
-rw-r--r--src/gui/chat.cpp533
-rw-r--r--src/gui/chat.h61
-rw-r--r--src/gui/chatinput.h4
-rw-r--r--src/gui/checkbox.h2
-rw-r--r--src/gui/colour.cpp139
-rw-r--r--src/gui/colour.h133
-rw-r--r--src/gui/confirm_dialog.cpp56
-rw-r--r--src/gui/confirm_dialog.h11
-rw-r--r--src/gui/connection.cpp3
-rw-r--r--src/gui/debugwindow.cpp3
-rw-r--r--src/gui/emotecontainer.cpp172
-rw-r--r--src/gui/emotecontainer.h138
-rw-r--r--src/gui/emoteshortcutcontainer.cpp195
-rw-r--r--src/gui/emoteshortcutcontainer.h81
-rw-r--r--src/gui/emotewindow.cpp82
-rw-r--r--src/gui/emotewindow.h68
-rw-r--r--src/gui/equipmentwindow.cpp144
-rw-r--r--src/gui/equipmentwindow.h43
-rw-r--r--src/gui/focushandler.cpp1
-rw-r--r--src/gui/gccontainer.h2
-rw-r--r--src/gui/gui.cpp27
-rw-r--r--src/gui/gui.h7
-rw-r--r--src/gui/help.cpp15
-rw-r--r--src/gui/help.h2
-rw-r--r--src/gui/inttextfield.cpp1
-rw-r--r--src/gui/inttextfield.h5
-rw-r--r--src/gui/inventorywindow.cpp210
-rw-r--r--src/gui/inventorywindow.h35
-rw-r--r--src/gui/item_amount.cpp3
-rw-r--r--src/gui/itemcontainer.cpp76
-rw-r--r--src/gui/itemcontainer.h32
-rw-r--r--src/gui/itemlinkhandler.cpp63
-rw-r--r--src/gui/itemlinkhandler.h40
-rw-r--r--src/gui/itempopup.cpp176
-rw-r--r--src/gui/itempopup.h (renamed from src/gui/buddywindow.h)45
-rw-r--r--src/gui/itemshortcutcontainer.cpp157
-rw-r--r--src/gui/itemshortcutcontainer.h45
-rw-r--r--src/gui/listbox.cpp9
-rw-r--r--src/gui/listbox.h2
-rw-r--r--src/gui/login.cpp216
-rw-r--r--src/gui/login.h59
-rw-r--r--src/gui/menuwindow.cpp45
-rw-r--r--src/gui/minimap.cpp71
-rw-r--r--src/gui/minimap.h14
-rw-r--r--src/gui/ministatus.cpp23
-rw-r--r--src/gui/npc_text.cpp38
-rw-r--r--src/gui/npc_text.h9
-rw-r--r--src/gui/npcintegerdialog.cpp1
-rw-r--r--src/gui/npclistdialog.cpp47
-rw-r--r--src/gui/npclistdialog.h9
-rw-r--r--src/gui/npcstringdialog.cpp5
-rw-r--r--src/gui/ok_dialog.cpp58
-rw-r--r--src/gui/ok_dialog.h12
-rw-r--r--src/gui/passwordfield.h5
-rw-r--r--src/gui/playerbox.cpp13
-rw-r--r--src/gui/playerbox.h5
-rw-r--r--src/gui/popupmenu.cpp194
-rw-r--r--src/gui/popupmenu.h3
-rw-r--r--src/gui/progressbar.cpp3
-rw-r--r--src/gui/progressbar.h7
-rw-r--r--src/gui/radiobutton.h3
-rw-r--r--src/gui/register.cpp54
-rw-r--r--src/gui/register.h21
-rw-r--r--src/gui/scrollarea.cpp21
-rw-r--r--src/gui/scrollarea.h2
-rw-r--r--src/gui/sell.cpp8
-rw-r--r--src/gui/setup.cpp27
-rw-r--r--src/gui/setup.h5
-rw-r--r--src/gui/setup_audio.cpp3
-rw-r--r--src/gui/setup_audio.h4
-rw-r--r--src/gui/setup_colours.cpp226
-rw-r--r--src/gui/setup_colours.h73
-rw-r--r--src/gui/setup_joystick.cpp13
-rw-r--r--src/gui/setup_joystick.h4
-rw-r--r--src/gui/setup_keyboard.cpp7
-rw-r--r--src/gui/setup_keyboard.h8
-rw-r--r--src/gui/setup_players.cpp13
-rw-r--r--src/gui/setup_players.h7
-rw-r--r--src/gui/setup_video.cpp142
-rw-r--r--src/gui/setup_video.h10
-rw-r--r--src/gui/shop.h5
-rw-r--r--src/gui/shoplistbox.cpp10
-rw-r--r--src/gui/shoplistbox.h2
-rw-r--r--src/gui/shortcutcontainer.cpp76
-rw-r--r--src/gui/shortcutcontainer.h107
-rw-r--r--src/gui/shortcutwindow.cpp (renamed from src/gui/itemshortcutwindow.cpp)26
-rw-r--r--src/gui/shortcutwindow.h (renamed from src/gui/itemshortcutwindow.h)20
-rw-r--r--src/gui/skill.cpp77
-rw-r--r--src/gui/skill.h5
-rw-r--r--src/gui/slider.h3
-rw-r--r--src/gui/speechbubble.cpp111
-rw-r--r--src/gui/speechbubble.h48
-rw-r--r--src/gui/status.cpp16
-rw-r--r--src/gui/status.h1
-rw-r--r--src/gui/table.cpp9
-rw-r--r--src/gui/table.h1
-rw-r--r--src/gui/table_model.cpp53
-rw-r--r--src/gui/table_model.h42
-rw-r--r--src/gui/textbox.cpp41
-rw-r--r--src/gui/textbox.h15
-rw-r--r--src/gui/textfield.cpp45
-rw-r--r--src/gui/textfield.h43
-rw-r--r--src/gui/trade.cpp180
-rw-r--r--src/gui/trade.h2
-rw-r--r--src/gui/truetypefont.cpp5
-rw-r--r--src/gui/updatewindow.cpp64
-rw-r--r--src/gui/updatewindow.h1
-rw-r--r--src/gui/viewport.cpp235
-rw-r--r--src/gui/viewport.h76
-rw-r--r--src/gui/widgets/dropdown.cpp167
-rw-r--r--src/gui/widgets/dropdown.h86
-rw-r--r--src/gui/widgets/resizegrip.cpp11
-rw-r--r--src/gui/widgets/resizegrip.h4
-rw-r--r--src/gui/window.cpp249
-rw-r--r--src/gui/window.h38
-rw-r--r--src/gui/windowcontainer.h2
-rw-r--r--src/imageparticle.cpp3
-rw-r--r--src/inventory.cpp38
-rw-r--r--src/inventory.h8
-rw-r--r--src/item.h36
-rw-r--r--src/itemshortcut.cpp3
-rw-r--r--src/itemshortcut.h2
-rw-r--r--src/joystick.cpp3
-rw-r--r--src/joystick.h4
-rw-r--r--src/keyboardconfig.cpp53
-rw-r--r--src/keyboardconfig.h29
-rw-r--r--src/localplayer.cpp241
-rw-r--r--src/localplayer.h68
-rw-r--r--src/main.cpp367
-rw-r--r--src/main.h4
-rw-r--r--src/map.cpp23
-rw-r--r--src/map.h26
-rw-r--r--src/monster.cpp70
-rw-r--r--src/monster.h5
-rw-r--r--src/net/beinghandler.cpp91
-rw-r--r--src/net/beinghandler.h2
-rw-r--r--src/net/buysellhandler.cpp5
-rw-r--r--src/net/charserverhandler.cpp19
-rw-r--r--src/net/chathandler.cpp3
-rw-r--r--src/net/equipmenthandler.cpp44
-rw-r--r--src/net/inventoryhandler.cpp126
-rw-r--r--src/net/itemhandler.cpp1
-rw-r--r--src/net/loginhandler.cpp5
-rw-r--r--src/net/loginhandler.h2
-rw-r--r--src/net/maploginhandler.cpp1
-rw-r--r--src/net/messagehandler.cpp3
-rw-r--r--src/net/messagein.cpp26
-rw-r--r--src/net/messagein.h22
-rw-r--r--src/net/messageout.cpp5
-rw-r--r--src/net/network.cpp8
-rw-r--r--src/net/network.h54
-rw-r--r--src/net/npchandler.cpp11
-rw-r--r--src/net/partyhandler.cpp123
-rw-r--r--src/net/partyhandler.h39
-rw-r--r--src/net/playerhandler.cpp94
-rw-r--r--src/net/protocol.h42
-rw-r--r--src/net/skillhandler.cpp3
-rw-r--r--src/net/tradehandler.cpp47
-rw-r--r--src/npc.cpp54
-rw-r--r--src/npc.h9
-rw-r--r--src/openglgraphics.cpp26
-rw-r--r--src/particle.cpp7
-rw-r--r--src/particle.h2
-rw-r--r--src/particlecontainer.cpp1
-rw-r--r--src/particleemitter.cpp38
-rw-r--r--src/particleemitter.h5
-rw-r--r--src/particleemitterprop.h2
-rw-r--r--src/party.cpp221
-rw-r--r--src/party.h73
-rw-r--r--src/player.cpp44
-rw-r--r--src/player.h18
-rw-r--r--src/player_relations.cpp64
-rw-r--r--src/player_relations.h11
-rw-r--r--src/properties.h2
-rw-r--r--src/recorder.cpp114
-rw-r--r--src/recorder.h48
-rw-r--r--src/resources/action.cpp2
-rw-r--r--src/resources/action.h6
-rw-r--r--src/resources/ambientoverlay.cpp1
-rw-r--r--src/resources/animation.cpp13
-rw-r--r--src/resources/animation.h18
-rw-r--r--src/resources/buddylist.cpp6
-rw-r--r--src/resources/buddylist.h2
-rw-r--r--src/resources/colordb.cpp125
-rw-r--r--src/resources/colordb.h52
-rw-r--r--src/resources/dye.h5
-rw-r--r--src/resources/emotedb.cpp143
-rw-r--r--src/resources/emotedb.h60
-rw-r--r--src/resources/image.cpp3
-rw-r--r--src/resources/image.h5
-rw-r--r--src/resources/imageloader.cpp4
-rw-r--r--src/resources/imageset.cpp6
-rw-r--r--src/resources/imageset.h1
-rw-r--r--src/resources/imagewriter.cpp6
-rw-r--r--src/resources/imagewriter.h2
-rw-r--r--src/resources/itemdb.cpp72
-rw-r--r--src/resources/itemdb.h7
-rw-r--r--src/resources/iteminfo.cpp13
-rw-r--r--src/resources/iteminfo.h7
-rw-r--r--src/resources/mapreader.cpp37
-rw-r--r--src/resources/mapreader.h2
-rw-r--r--src/resources/monsterdb.cpp25
-rw-r--r--src/resources/monsterdb.h6
-rw-r--r--src/resources/monsterinfo.cpp6
-rw-r--r--src/resources/monsterinfo.h43
-rw-r--r--src/resources/music.cpp6
-rw-r--r--src/resources/music.h6
-rw-r--r--src/resources/npcdb.cpp18
-rw-r--r--src/resources/npcdb.h8
-rw-r--r--src/resources/resource.cpp7
-rw-r--r--src/resources/resource.h6
-rw-r--r--src/resources/resourcemanager.cpp17
-rw-r--r--src/resources/resourcemanager.h4
-rw-r--r--src/resources/soundeffect.cpp3
-rw-r--r--src/resources/soundeffect.h3
-rw-r--r--src/resources/spritedef.cpp3
-rw-r--r--src/resources/spritedef.h6
-rw-r--r--src/simpleanimation.cpp6
-rw-r--r--src/sound.cpp4
-rw-r--r--src/sound.h1
-rw-r--r--src/sprite.h12
-rw-r--r--src/text.cpp7
-rw-r--r--src/text.h9
-rw-r--r--src/textmanager.cpp1
-rw-r--r--src/textmanager.h1
-rw-r--r--src/textparticle.cpp3
-rw-r--r--src/textparticle.h3
-rw-r--r--src/utils/base64.cpp2
-rw-r--r--src/utils/strprintf.cpp1
-rw-r--r--src/utils/xml.cpp2
269 files changed, 8597 insertions, 2817 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 70a58272..fc98ae64 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -49,6 +49,8 @@ MARK_AS_ADVANCED(SDL_INCLUDE_DIR)
MARK_AS_ADVANCED(SDL_LIBRARY)
SET(SRCS
+ gui/widgets/dropdown.cpp
+ gui/widgets/dropdown.h
gui/widgets/resizegrip.cpp
gui/widgets/resizegrip.h
gui/widgets/layout.cpp
@@ -101,6 +103,10 @@ SET(SRCS
gui/inventorywindow.h
gui/itemcontainer.cpp
gui/itemcontainer.h
+ gui/itemlinkhandler.cpp
+ gui/itemlinkhandler.h
+ gui/itempopup.cpp
+ gui/itempopup.h
gui/itemshortcutcontainer.cpp
gui/itemshortcutcontainer.h
gui/itemshortcutwindow.cpp
@@ -167,6 +173,8 @@ SET(SRCS
gui/skill.h
gui/slider.cpp
gui/slider.h
+ gui/speechbubble.cpp
+ gui/speechbubble.h
gui/status.cpp
gui/status.h
gui/table.cpp
@@ -231,8 +239,12 @@ SET(SRCS
resources/animation.h
resources/buddylist.cpp
resources/buddylist.h
+ resources/colordb.cpp
+ resources/colordb.h
resources/dye.cpp
resources/dye.h
+ resources/emotedb.cpp
+ resources/emotedb.h
resources/image.cpp
resources/image.h
resources/imageloader.cpp
@@ -285,10 +297,13 @@ SET(SRCS
configlistener.h
configuration.cpp
configuration.h
+ effectmanager.cpp
+ effectmanager.h
engine.cpp
engine.h
equipment.cpp
equipment.h
+ extensions.h
floor_item.cpp
floor_item.h
flooritemmanager.cpp
@@ -338,6 +353,8 @@ SET(SRCS
position.cpp
position.h
properties.h
+ sdltruetypefont.cpp
+ sdltruetypefont.hpp
serverinfo.h
shopitem.cpp
shopitem.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 358b0b61..a1085d0a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,9 @@
AUTOMAKE_OPTIONS = subdir-objects
bin_PROGRAMS = tmw
-tmw_SOURCES = gui/widgets/layout.cpp \
+tmw_SOURCES = gui/widgets/dropdown.cpp \
+ gui/widgets/dropdown.h \
+ gui/widgets/layout.cpp \
gui/widgets/layout.h \
gui/widgets/layouthelper.cpp \
gui/widgets/layouthelper.h \
@@ -13,30 +15,38 @@ tmw_SOURCES = gui/widgets/layout.cpp \
gui/widgets/tabbedarea.h \
gui/browserbox.cpp \
gui/browserbox.h \
- gui/buddywindow.cpp \
- gui/buddywindow.h \
gui/button.cpp \
gui/button.h \
+ gui/buttonbox.cpp \
+ gui/buttonbox.h \
gui/buy.cpp \
gui/buy.h \
gui/buysell.cpp \
gui/buysell.h \
- gui/char_server.cpp \
- gui/char_server.h \
gui/char_select.cpp \
gui/char_select.h \
+ gui/char_server.cpp \
+ gui/char_server.h \
gui/chat.cpp \
gui/chat.h \
gui/chatinput.cpp \
gui/chatinput.h \
gui/checkbox.cpp \
gui/checkbox.h \
+ gui/colour.cpp \
+ gui/colour.h \
gui/confirm_dialog.cpp \
gui/confirm_dialog.h \
gui/connection.cpp \
gui/connection.h \
gui/debugwindow.cpp \
gui/debugwindow.h \
+ gui/emotecontainer.cpp \
+ gui/emotecontainer.h \
+ gui/emoteshortcutcontainer.cpp \
+ gui/emoteshortcutcontainer.h \
+ gui/emotewindow.cpp \
+ gui/emotewindow.h \
gui/equipmentwindow.cpp \
gui/equipmentwindow.h \
gui/focushandler.cpp \
@@ -53,10 +63,12 @@ tmw_SOURCES = gui/widgets/layout.cpp \
gui/inventorywindow.h \
gui/itemcontainer.cpp \
gui/itemcontainer.h \
+ gui/itemlinkhandler.cpp \
+ gui/itemlinkhandler.h \
+ gui/itempopup.cpp \
+ gui/itempopup.h \
gui/itemshortcutcontainer.cpp \
gui/itemshortcutcontainer.h \
- gui/itemshortcutwindow.cpp \
- gui/itemshortcutwindow.h \
gui/item_amount.cpp \
gui/item_amount.h \
gui/linkhandler.h \
@@ -100,10 +112,12 @@ tmw_SOURCES = gui/widgets/layout.cpp \
gui/sdlinput.h \
gui/sell.cpp \
gui/sell.h \
- gui/setup_audio.cpp \
- gui/setup_audio.h \
gui/setup.cpp \
gui/setup.h \
+ gui/setup_audio.cpp \
+ gui/setup_audio.h \
+ gui/setup_colours.cpp \
+ gui/setup_colours.h \
gui/setup_joystick.cpp \
gui/setup_joystick.h \
gui/setup_keyboard.cpp \
@@ -117,16 +131,22 @@ tmw_SOURCES = gui/widgets/layout.cpp \
gui/shop.h \
gui/shoplistbox.cpp \
gui/shoplistbox.h \
+ gui/shortcutwindow.cpp \
+ gui/shortcutwindow.h \
+ gui/shortcutcontainer.cpp \
+ gui/shortcutcontainer.h \
gui/skill.cpp \
gui/skill.h \
gui/slider.cpp \
gui/slider.h \
+ gui/speechbubble.cpp \
+ gui/speechbubble.h \
gui/status.cpp \
gui/status.h \
- gui/table.h \
gui/table.cpp \
- gui/table_model.h \
+ gui/table.h \
gui/table_model.cpp \
+ gui/table_model.h \
gui/textbox.cpp \
gui/textbox.h \
gui/textfield.cpp \
@@ -169,6 +189,8 @@ tmw_SOURCES = gui/widgets/layout.cpp \
net/network.h \
net/npchandler.cpp \
net/npchandler.h \
+ net/partyhandler.cpp \
+ net/partyhandler.h \
net/playerhandler.cpp \
net/playerhandler.h \
net/protocol.cpp \
@@ -183,8 +205,14 @@ tmw_SOURCES = gui/widgets/layout.cpp \
resources/ambientoverlay.h \
resources/animation.cpp \
resources/animation.h \
+ resources/buddylist.cpp \
+ resources/buddylist.h \
+ resources/colordb.cpp \
+ resources/colordb.h \
resources/dye.cpp \
resources/dye.h \
+ resources/emotedb.cpp \
+ resources/emotedb.h \
resources/image.cpp \
resources/image.h \
resources/imageloader.cpp \
@@ -215,8 +243,6 @@ tmw_SOURCES = gui/widgets/layout.cpp \
resources/soundeffect.cpp \
resources/spritedef.h \
resources/spritedef.cpp \
- resources/buddylist.h \
- resources/buddylist.cpp \
utils/base64.cpp \
utils/base64.h \
utils/dtor.h \
@@ -240,10 +266,15 @@ tmw_SOURCES = gui/widgets/layout.cpp \
configlistener.h \
configuration.cpp \
configuration.h \
+ effectmanager.cpp \
+ effectmanager.h \
+ emoteshortcut.cpp \
+ emoteshortcut.h \
engine.cpp \
engine.h \
equipment.cpp \
equipment.h \
+ extensions.h \
floor_item.cpp \
floor_item.h \
flooritemmanager.cpp \
@@ -283,11 +314,13 @@ tmw_SOURCES = gui/widgets/layout.cpp \
openglgraphics.h \
particle.cpp \
particle.h \
+ particlecontainer.cpp \
+ particlecontainer.h \
particleemitter.cpp \
particleemitter.h \
particleemitterprop.h \
- particlecontainer.cpp \
- particlecontainer.h \
+ party.cpp \
+ party.h \
player.cpp \
player.h \
player_relations.cpp \
@@ -295,6 +328,8 @@ tmw_SOURCES = gui/widgets/layout.cpp \
position.cpp \
position.h \
properties.h \
+ recorder.cpp \
+ recorder.h \
serverinfo.h \
shopitem.cpp \
shopitem.h \
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index 25a9df6c..aa2fb4ee 100644
--- a/src/animatedsprite.cpp
+++ b/src/animatedsprite.cpp
@@ -20,7 +20,6 @@
*/
#include "animatedsprite.h"
-
#include "graphics.h"
#include "log.h"
diff --git a/src/animationparticle.cpp b/src/animationparticle.cpp
index ca4f4d31..9c1f7ccb 100644
--- a/src/animationparticle.cpp
+++ b/src/animationparticle.cpp
@@ -20,7 +20,6 @@
*/
#include "animationparticle.h"
-
#include "graphics.h"
#include "simpleanimation.h"
diff --git a/src/being.cpp b/src/being.cpp
index 7036b8cd..63c60390 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -22,44 +22,52 @@
#include "being.h"
#include "animatedsprite.h"
+#include "configuration.h"
#include "equipment.h"
#include "game.h"
#include "graphics.h"
+#include "localplayer.h"
#include "log.h"
#include "map.h"
#include "particle.h"
#include "sound.h"
-#include "localplayer.h"
#include "text.h"
#include "statuseffect.h"
-#include "resources/itemdb.h"
-#include "resources/resourcemanager.h"
+#include "resources/emotedb.h"
#include "resources/imageset.h"
+#include "resources/itemdb.h"
#include "resources/iteminfo.h"
+#include "resources/resourcemanager.h"
#include "gui/gui.h"
+#include "gui/speechbubble.h"
#include "utils/dtor.h"
+#include "utils/gettext.h"
#include "utils/tostring.h"
-
#include "utils/xml.h"
#include <cassert>
+#include <cmath>
#define BEING_EFFECTS_FILE "effects.xml"
#define HAIR_FILE "hair.xml"
int Being::instances = 0;
-ImageSet *Being::emotionSet = NULL;
+int Being::mNumberOfHairstyles = 1;
+std::vector<AnimatedSprite*> Being::emotionSet;
static const int X_SPEECH_OFFSET = 18;
static const int Y_SPEECH_OFFSET = 60;
+static const int DEFAULT_WIDTH = 32;
+static const int DEFAULT_HEIGHT = 32;
+
Being::Being(int id, int job, Map *map):
mJob(job),
mX(0), mY(0),
- mAction(0),
+ mAction(STAND),
mWalkTime(0),
mEmotion(0), mEmotionTime(0),
mAttackSpeed(350),
@@ -68,6 +76,9 @@ Being::Being(int id, int job, Map *map):
mWalkSpeed(150),
mDirection(DOWN),
mMap(NULL),
+ mName(""),
+ mIsGM(false),
+ mParticleEffects(config.getValue("particleeffects", 1)),
mEquippedWeapon(NULL),
mHairStyle(1), mHairColor(0),
mGender(GENDER_UNSPECIFIED),
@@ -83,16 +94,33 @@ Being::Being(int id, int job, Map *map):
{
setMap(map);
+ mSpeechBubble = new SpeechBubble();
+
if (instances == 0)
{
- // Load the emotion set
- ResourceManager *rm = ResourceManager::getInstance();
- emotionSet = rm->getImageSet("graphics/gui/emotions.png", 30, 32);
- if (!emotionSet) logger->error("Unable to load emotions!");
+ // Setup emote sprites
+ for (int i = 0; i <= EmoteDB::getLast(); i++)
+ {
+ EmoteInfo info = EmoteDB::get(i);
+
+ std::string file = "graphics/sprites/" + info.sprites.front()->sprite;
+ int variant = info.sprites.front()->variant;
+ emotionSet.push_back(AnimatedSprite::load(file, variant));
+ }
+
+ // Hairstyles are encoded as negative numbers. Count how far negative we can go.
+ int hairstyles = 1;
+ while (ItemDB::get(-hairstyles).getSprite(GENDER_MALE) != "error.xml")
+ {
+ hairstyles++;
+ }
+ mNumberOfHairstyles = hairstyles;
}
instances++;
- mSpeech = 0;
+ mSpeech = "";
+ mNameColor = 0x202020;
+ mText = 0;
}
Being::~Being()
@@ -106,11 +134,11 @@ Being::~Being()
if (instances == 0)
{
- emotionSet->decRef();
- emotionSet = NULL;
+ delete_all(emotionSet);
}
- delete mSpeech;
+ delete mSpeechBubble;
+ delete mText;
}
void Being::setDestination(Uint16 destX, Uint16 destY)
@@ -139,8 +167,8 @@ void Being::setPath(const Path &path)
void Being::setHairStyle(int style, int color)
{
- mHairStyle = style < 0 ? mHairStyle : style % getHairStylesNr();
- mHairColor = color < 0 ? mHairColor : color % getHairColorsNr();
+ mHairStyle = style < 0 ? mHairStyle : style % mNumberOfHairstyles;
+ mHairColor = color < 0 ? mHairColor : color % ColorDB::size();
}
void Being::setSprite(int slot, int id, std::string color)
@@ -152,13 +180,48 @@ void Being::setSprite(int slot, int id, std::string color)
void Being::setSpeech(const std::string &text, Uint32 time)
{
- // don't introduce a memory leak
- delete mSpeech;
+ mSpeech = text;
+
+ // Trim whitespace
+ while (mSpeech[0] == ' ')
+ {
+ mSpeech = mSpeech.substr(1, mSpeech.size());
+ }
+ while (mSpeech[mSpeech.size()] == ' ')
+ {
+ mSpeech = mSpeech.substr(0, mSpeech.size() - 1);
+ }
+
+ // check for links
+ std::string::size_type start = mSpeech.find('[');
+ std::string::size_type end = mSpeech.find(']', start);
+
+ while (start != std::string::npos && end != std::string::npos)
+ {
+ // Catch multiple embeds and ignore them so it doesn't crash the client.
+ while ((mSpeech.find('[', start + 1) != std::string::npos) &&
+ (mSpeech.find('[', start + 1) < end))
+ {
+ start = mSpeech.find('[', start + 1);
+ }
- mSpeech = new Text(text, mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET,
- gcn::Graphics::CENTER,
- gcn::Color(255, 255, 255), true);
- mSpeechTime = 500;
+ std::string::size_type position = mSpeech.find('|');
+ mSpeech.erase(end, 1);
+ mSpeech.erase(start, (position - start) + 1);
+ position = mSpeech.find('@');
+
+ while (position != std::string::npos)
+ {
+ mSpeech.erase(position, 2);
+ position = mSpeech.find('@');
+ }
+
+ start = mSpeech.find('[', start + 1);
+ end = mSpeech.find(']', start);
+ }
+
+ if (mSpeech != "")
+ mSpeechTime = 500;
}
void Being::takeDamage(int amount)
@@ -173,10 +236,6 @@ void Being::takeDamage(int amount)
}
else
{
- // Hit particle effect
- controlParticle(particleEngine->addEffect(
- "graphics/particles/hit.particle.xml", 0, 0));
-
if (getType() == MONSTER)
{
font = hitBlueFont;
@@ -192,6 +251,26 @@ void Being::takeDamage(int amount)
mPx + 16, mPy + 16);
}
+void Being::showCrit()
+{
+ gcn::Font *font;
+ std::string text = "crit!";
+
+ // Selecting the right color
+ if (getType() == MONSTER)
+ {
+ font = hitBlueFont;
+ }
+ else
+ {
+ font = hitRedFont;
+ }
+
+ // Show crit notice
+ particleEngine->addTextSplashEffect(text, 255, 255, 255, font,
+ mPx + 16, mPy + 16);
+}
+
void Being::handleAttack(Being *victim, int damage)
{
setAction(Being::ATTACK);
@@ -225,9 +304,10 @@ void Being::controlParticle(Particle *particle)
mChildParticleEffects.addLocally(particle);
}
-void Being::setAction(Uint8 action)
+void Being::setAction(Action action)
{
SpriteAction currentAction = ACTION_INVALID;
+
switch (action)
{
case WALK:
@@ -241,7 +321,8 @@ void Being::setAction(Uint8 action)
{
currentAction = mEquippedWeapon->getAttackType();
}
- else {
+ else
+ {
currentAction = ACTION_ATTACK;
}
for (int i = 0; i < VECTOREND_SPRITE; i++)
@@ -278,9 +359,11 @@ void Being::setAction(Uint8 action)
}
}
-
void Being::setDirection(Uint8 direction)
{
+ if (mDirection == direction)
+ return;
+
mDirection = direction;
SpriteDirection dir = getSpriteDirection();
@@ -307,10 +390,11 @@ SpriteDirection Being::getSpriteDirection() const
{
dir = DIRECTION_RIGHT;
}
- else {
- dir = DIRECTION_LEFT;
+ else
+ {
+ dir = DIRECTION_LEFT;
}
-
+
return dir;
}
@@ -352,28 +436,28 @@ void Being::nextStep()
void Being::logic()
{
// Reduce the time that speech is still displayed
- if (mSpeechTime > 0 && mSpeech)
+ if (mSpeechTime > 0)
+ mSpeechTime--;
+
+ // Remove text if speech boxes aren't being used
+ if (mSpeechTime == 0 && mText)
{
- if (--mSpeechTime == 0)
- {
- delete mSpeech;
- mSpeech = 0;
- }
+ delete mText;
+ mText = 0;
}
int oldPx = mPx;
int oldPy = mPy;
+
// Update pixel coordinates
mPx = mX * 32 + getXOffset();
mPy = mY * 32 + getYOffset();
+
if (mPx != oldPx || mPy != oldPy)
{
- if (mSpeech)
- {
- mSpeech->adviseXY(mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET);
- }
updateCoords();
}
+
if (mEmotion != 0)
{
mEmotionTime--;
@@ -431,8 +515,47 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
const int py = mPy + offsetY - 60;
const int emotionIndex = mEmotion - 1;
- if (emotionIndex >= 0 && emotionIndex < (int) emotionSet->size())
- graphics->drawImage(emotionSet->get(emotionIndex), px, py);
+ if (emotionIndex >= 0 && emotionIndex <= EmoteDB::getLast())
+ emotionSet[emotionIndex]->draw(graphics, px, py);
+}
+
+void Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY)
+{
+ int px = mPx + offsetX;
+ int py = mPy + offsetY;
+
+ // Draw speech above this being
+ if (mSpeechTime > 0 && config.getValue("speechbubble", 1))
+ {
+ if (mText)
+ {
+ delete mText;
+ mText = 0;
+ }
+
+ mSpeechBubble->setCaption(mName, mNameColor);
+
+ // Not quite centered, but close enough. However, it's not too important to get
+ // it right right now, as it doesn't take bubble collision into account yet.
+ mSpeechBubble->setText(mSpeech);
+ mSpeechBubble->setPosition(px - (mSpeechBubble->getWidth() * 4 / 11), py - 70 -
+ (mSpeechBubble->getNumRows()*14));
+ mSpeechBubble->setVisible(true);
+ }
+ else if (mSpeechTime > 0 && !config.getValue("speechbubble", 1))
+ {
+ mSpeechBubble->setVisible(false);
+ // don't introduce a memory leak
+ if (mText)
+ delete mText;
+
+ mText = new Text(mSpeech, mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET,
+ gcn::Graphics::CENTER, gcn::Color(255, 255, 255));
+ }
+ else if (mSpeechTime == 0)
+ {
+ mSpeechBubble->setVisible(false);
+ }
}
Being::Type Being::getType() const
@@ -455,9 +578,11 @@ void Being::handleStatusEffect(StatusEffect *effect, int effectId)
if (!effect)
return;
- SpriteAction action = effect->getAction();
- if (action != ACTION_INVALID)
- setAction(action);
+ // TODO: Find out how this is meant to be used
+ // (SpriteAction != Being::Action)
+ //SpriteAction action = effect->getAction();
+ //if (action != ACTION_INVALID)
+ // setAction(action);
Particle *particle = effect->getParticle();
@@ -497,7 +622,8 @@ void Being::setStatusEffect(int index, bool active)
int Being::getOffset(char pos, char neg) const
{
// Check whether we're walking in the requested direction
- if (mAction != WALK || !(mDirection & (pos | neg))) {
+ if (mAction != WALK || !(mDirection & (pos | neg)))
+ {
return 0;
}
@@ -505,27 +631,32 @@ int Being::getOffset(char pos, char neg) const
// We calculate the offset _from_ the _target_ location
offset -= 32;
- if (offset > 0) {
+ if (offset > 0)
+ {
offset = 0;
}
// Going into negative direction? Invert the offset.
- if (mDirection & pos) {
+ if (mDirection & pos)
+ {
offset = -offset;
}
return offset;
}
-
int Being::getWidth() const
{
if (mSprites[BASE_SPRITE])
{
- return mSprites[BASE_SPRITE]->getWidth();
+ const int width = mSprites[BASE_SPRITE]->getWidth() > DEFAULT_WIDTH ?
+ mSprites[BASE_SPRITE]->getWidth() :
+ DEFAULT_WIDTH;
+ return width;
}
- else {
- return 0;
+ else
+ {
+ return DEFAULT_WIDTH;
}
}
@@ -534,10 +665,14 @@ int Being::getHeight() const
{
if (mSprites[BASE_SPRITE])
{
- return mSprites[BASE_SPRITE]->getHeight();
+ const int height = mSprites[BASE_SPRITE]->getHeight() > DEFAULT_HEIGHT ?
+ mSprites[BASE_SPRITE]->getHeight() :
+ DEFAULT_HEIGHT;
+ return height;
}
- else {
- return 0;
+ else
+ {
+ return DEFAULT_HEIGHT;
}
}
diff --git a/src/being.h b/src/being.h
index 7d5ed989..9e207448 100644
--- a/src/being.h
+++ b/src/being.h
@@ -24,15 +24,22 @@
#include <list>
#include <memory>
-#include <string>
#include <SDL_types.h>
#include <set>
+#include <string>
+#include <vector>
+#include <bitset>
-#include "position.h"
-#include "sprite.h"
-#include "map.h"
#include "animatedsprite.h"
+#include "effectmanager.h"
+#include "map.h"
#include "particlecontainer.h"
+#include "position.h"
+#include "sprite.h"
+
+#include "gui/speechbubble.h"
+
+#include "resources/colordb.h"
#define FIRST_IGNORE_EMOTE 14
#define STATUS_EFFECTS 32
@@ -43,8 +50,8 @@ class ItemInfo;
class Item;
class Map;
class Graphics;
-class ImageSet;
class Particle;
+class SpeechBubble;
class Text;
class StatusEffect;
@@ -107,13 +114,13 @@ class Being : public Sprite
Uint16 mJob; /**< Job (player job, npc, monster, ) */
Uint16 mX, mY; /**< Tile coordinates */
- Uint8 mAction; /**< Action the being is performing */
- Uint8 mFrame;
+ Action mAction; /**< Action the being is performing */
+ Uint16 mFrame;
Uint16 mWalkTime;
Uint8 mEmotion; /**< Currently showing emotion */
Uint8 mEmotionTime; /**< Time until emotion disappears */
- Uint16 mAttackSpeed; /**< Attack speed */
+ Uint16 mAttackSpeed; /**< Attack speed */
/**
* Constructor.
@@ -152,6 +159,11 @@ class Being : public Sprite
virtual void takeDamage(int amount);
/**
+ * Puts a crit notification bubble above this being.
+ */
+ virtual void showCrit();
+
+ /**
* Handles an attack of another being by this being.
*
* @param victim The attacked being.
@@ -186,6 +198,11 @@ class Being : public Sprite
{ return mHairStyle; }
/**
+ * Get the number of hairstyles implemented
+ */
+ static int getNumOfHairstyles() { return mNumberOfHairstyles; }
+
+ /**
* Sets the hair style and color for this being.
*/
virtual void setHairStyle(int style, int color);
@@ -211,11 +228,24 @@ class Being : public Sprite
virtual void nextStep();
/**
+ * Triggers whether or not to show the name as a GM name.
+ * NOTE: This doesn't mean that just anyone can use this.
+ * If the server doesn't acknowlege you, you won't be shown
+ * as a GM on other people's clients.
+ */
+ virtual void setGM() { mIsGM = true; }
+
+ /**
* Performs being logic.
*/
virtual void logic();
/**
+ * Draws the speech text above the being.
+ */
+ void drawSpeech(Graphics *graphics, int offsetX, int offsetY);
+
+ /**
* Draws the emotion picture above the being.
*/
void drawEmotion(Graphics *graphics, int offsetX, int offsetY);
@@ -253,7 +283,7 @@ class Being : public Sprite
/**
* Sets the current action.
*/
- virtual void setAction(Uint8 action);
+ virtual void setAction(Action action);
/**
* Returns the current direction.
@@ -266,6 +296,16 @@ class Being : public Sprite
void setDirection(Uint8 direction);
/**
+ * Gets the current action.
+ */
+ int getWalkTime() { return mWalkTime; }
+
+ /**
+ * Returns the direction the being is facing.
+ */
+ SpriteDirection getSpriteDirection() const;
+
+ /**
* Draws this being to the given graphics context.
*
* @see Sprite::draw(Graphics, int, int)
@@ -317,6 +357,8 @@ class Being : public Sprite
*/
void controlParticle(Particle *particle);
+ AnimatedSprite* getEmote(int index) { return emotionSet[index]; }
+
void setEmote(Uint8 emotion, Uint8 emote_time)
{
mEmotion = emotion;
@@ -356,8 +398,10 @@ class Being : public Sprite
internalTriggerEffect(effectId, false, true);
}
- const std::auto_ptr<Equipment> mEquipment;
+ // Target cursor being used by the being
+ Image *mTargetCursor;
+ const std::auto_ptr<Equipment> mEquipment;
static int getHairColorsNr();
@@ -365,6 +409,9 @@ class Being : public Sprite
static std::string getHairColor(int index);
+ virtual AnimatedSprite* getSprite(int index) const
+ { return mSprites[index]; }
+
protected:
/**
* Sets the new path for this being.
@@ -377,11 +424,6 @@ class Being : public Sprite
virtual void updateCoords() {}
/**
- * Returns the sprite direction of this being.
- */
- SpriteDirection getSpriteDirection() const;
-
- /**
* Trigger visual effect, with components
*
* \param effectId ID of the effect to trigger
@@ -416,12 +458,17 @@ class Being : public Sprite
Map *mMap; /**< Map on which this being resides */
std::string mName; /**< Name of character */
SpriteIterator mSpriteIterator;
+ bool mIsGM;
+ bool mParticleEffects; /**< Whether to display particles or not */
/** Engine-related infos about weapon. */
const ItemInfo* mEquippedWeapon;
+ static int mNumberOfHairstyles; /** Number of hair styles in use */
+
Path mPath;
- Text *mSpeech;
+ std::string mSpeech;
+ Text *mText;
Uint16 mHairStyle, mHairColor;
Gender mGender;
Uint32 mSpeechTime;
@@ -429,6 +476,8 @@ class Being : public Sprite
Uint16 mStunMode; /**< Stun mode; zero if not stunned */
std::set<int> mStatusEffects; /**< set of active status effects */
+ gcn::Color mNameColor;
+
std::vector<AnimatedSprite*> mSprites;
std::vector<int> mSpriteIDs;
std::vector<std::string> mSpriteColors;
@@ -443,9 +492,13 @@ class Being : public Sprite
*/
int getOffset(char pos, char neg) const;
- static int instances; /**< Number of Being instances */
- static ImageSet *emotionSet; /**< Emoticons used by beings */
bool mMustResetParticles; /**< Reset particle status effects on next redraw? */
+
+ // Speech Bubble components
+ SpeechBubble *mSpeechBubble;
+
+ static int instances; /**< Number of Being instances */
+ static std::vector<AnimatedSprite*> emotionSet; /**< Emoticons used by beings */
};
#endif
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
index 551820da..3c8edf86 100644
--- a/src/beingmanager.cpp
+++ b/src/beingmanager.cpp
@@ -31,6 +31,8 @@
#include "utils/dtor.h"
+#include <cassert>
+
class FindBeingFunctor
{
public:
@@ -128,12 +130,16 @@ Being* BeingManager::findBeingByPixel(Uint16 x, Uint16 y)
for (; itr != itr_end; ++itr)
{
Being *being = (*itr);
+
+ int xtol = being->getWidth();
+ int uptol = being->getHeight() / 2;
+
if ((being->mAction != Being::DEAD) &&
(being != player_node) &&
(being->getPixelX() <= x) &&
- (being->getPixelX() + being->getWidth() >= x) &&
- (being->getPixelY() <= y) &&
- (being->getPixelY() + being->getHeight() >= y))
+ (being->getPixelX() + xtol >= x) &&
+ (being->getPixelY() - uptol <= y) &&
+ (being->getPixelY() + uptol >= y))
{
return being;
}
@@ -155,8 +161,6 @@ Being* BeingManager::findBeingByName(std::string name, Being::Type type)
return NULL;
}
-
-
Beings& BeingManager::getAll()
{
return mBeings;
@@ -204,9 +208,12 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
Being *closestBeing = NULL;
int dist = 0;
- for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++)
+ BeingIterator itr = mBeings.begin();
+ BeingIterator itr_end = mBeings.end();
+
+ for (; itr != itr_end; ++itr)
{
- Being *being = (*i);
+ Being *being = (*itr);
int d = abs(being->mX - x) + abs(being->mY - y);
if ((being->getType() == type || type == Being::UNKNOWN)
diff --git a/src/beingmanager.h b/src/beingmanager.h
index 017de22e..11721709 100644
--- a/src/beingmanager.h
+++ b/src/beingmanager.h
@@ -49,7 +49,7 @@ class BeingManager
/**
* Create a being and add it to the list of beings.
*/
- Being* createBeing(Uint32 id, Uint16 job);
+ Being *createBeing(Uint32 id, Uint16 job);
/**
* Remove a Being.
@@ -60,33 +60,36 @@ class BeingManager
* Return a specific id Being.
*/
Being* findBeing(Uint32 id);
+ Being* findBeingByPixel(Uint16 x, Uint16 y);
/**
- * Return a being at specific coordinates.
+ * Returns a being at specific coordinates.
*/
Being* findBeing(Uint16 x, Uint16 y, Being::Type type = Being::UNKNOWN);
- Being* findBeingByPixel(Uint16 x, Uint16 y);
- /**
- * Return a being nearest to specific coordinates.
- *
- * \param maxdist maximal distance. If minimal distance is larger,
- * no being is returned
- */
+ /**
+ * Returns a being nearest to specific coordinates.
+ *
+ * @param x X coordinate.
+ * @param y Y coordinate.
+ * @param maxdist Maximal distance. If minimal distance is larger,
+ * no being is returned.
+ * @param type The type of being to look for.
+ */
Being* findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist,
Being::Type type = Being::UNKNOWN);
- /**
- * Finds a being by name and (optionally) by type.
- */
+ /**
+ * Finds a being by name and (optionally) by type.
+ */
Being* findBeingByName(std::string name, Being::Type type = Being::UNKNOWN);
- /**
- * Return a being nearest to another being.
- *
- * \param maxdist maximal distance. If minimal distance is larger,
- * no being is returned
- */
+ /**
+ * Returns a being nearest to another being.
+ *
+ * \param maxdist maximal distance. If minimal distance is larger,
+ * no being is returned
+ */
Being* findNearestLivingBeing(Being *aroundBeing, int maxdist,
Being::Type type = Being::UNKNOWN);
diff --git a/src/configlistener.h b/src/configlistener.h
index 009a4830..51d58144 100644
--- a/src/configlistener.h
+++ b/src/configlistener.h
@@ -24,7 +24,6 @@
#include <iosfwd>
-
/**
* The listener interface for receiving notifications about changes to
* configuration options.
diff --git a/src/configuration.cpp b/src/configuration.cpp
index 04839777..31c18c1d 100644
--- a/src/configuration.cpp
+++ b/src/configuration.cpp
@@ -19,12 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
-#include "configuration.h"
-
#include <libxml/xmlwriter.h>
#include "configlistener.h"
+#include "configuration.h"
#include "log.h"
#include "utils/tostring.h"
@@ -90,7 +88,6 @@ void ConfigurationObject::clear()
mOptions.clear();
}
-
ConfigurationObject::~ConfigurationObject()
{
clear();
@@ -193,7 +190,6 @@ void ConfigurationObject::writeToXML(xmlTextWriterPtr writer)
}
}
-
void Configuration::write()
{
// Do not attempt to write to file that cannot be opened for writing
diff --git a/src/configuration.h b/src/configuration.h
index 9f97e221..91ae536b 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -22,11 +22,11 @@
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
-#include <map>
-#include <list>
-#include <string>
#include <cassert>
#include <libxml/xmlwriter.h>
+#include <list>
+#include <map>
+#include <string>
class ConfigListener;
class ConfigurationObject;
diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp
new file mode 100644
index 00000000..cf77de37
--- /dev/null
+++ b/src/effectmanager.cpp
@@ -0,0 +1,106 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "effectmanager.h"
+#include "log.h"
+#include "particle.h"
+#include "sound.h"
+
+#include "utils/xml.h"
+
+EffectManager::EffectManager()
+{
+ XML::Document doc("effects.xml");
+ xmlNodePtr root = doc.rootNode();
+
+ if (!root || !xmlStrEqual(root->name, BAD_CAST "being-effects"))
+ {
+ logger->log("Error loading being effects file: effects.xml");
+ return;
+ }
+ else
+ {
+ logger->log("Effects are now loading");
+ }
+
+ for_each_xml_child_node(node, root)
+ {
+ //int id;
+
+ if (xmlStrEqual(node->name, BAD_CAST "effect"))
+ {
+ EffectDescription ed;
+ ed.id = XML::getProperty(node, "id", -1);
+ ed.GFX = XML::getProperty(node, "particle", "");
+ ed.SFX = XML::getProperty(node, "audio", "");
+ mEffects.push_back(ed);
+ }
+ }
+}
+
+EffectManager::~EffectManager()
+{
+
+}
+
+bool EffectManager::trigger(int id, Being* being)
+{
+ bool rValue = false;
+ for (std::list<EffectDescription>::iterator i = mEffects.begin(); i != mEffects.end(); ++i)
+ {
+ if ((*i).id == id)
+ {
+ printf("Found effect, playing it");
+ rValue = true;
+ if((*i).GFX != "")
+ {
+ Particle *selfFX;
+ selfFX = particleEngine->addEffect((*i).GFX, 0, 0);
+ being->controlParticle(selfFX);
+ }
+ if((*i).SFX != "")
+ sound.playSfx((*i).SFX);
+ break;
+ }
+ }
+ return rValue;
+}
+
+bool EffectManager::trigger(int id, int x, int y)
+{
+ bool rValue = false;
+ for (std::list<EffectDescription>::iterator i = mEffects.begin(); i != mEffects.end(); ++i)
+ {
+ if ((*i).id == id)
+ {
+ printf("Found effect, playing it");
+ rValue = true;
+ if((*i).GFX != "")
+ particleEngine->addEffect((*i).GFX, x, y);
+ if((*i).SFX != "")
+ sound.playSfx((*i).SFX);
+ break;
+ }
+ }
+ return rValue;
+}
+
diff --git a/src/effectmanager.h b/src/effectmanager.h
new file mode 100644
index 00000000..a9efcdbc
--- /dev/null
+++ b/src/effectmanager.h
@@ -0,0 +1,66 @@
+/*
+ * The Mana World
+ * Copyright 2008 The Mana World Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _EFFECT_MANAGER_H
+#define _EFFECT_MANAGER_H
+
+#include <list>
+#include <string>
+
+#include "being.h"
+
+class Being;
+
+class EffectManager
+{
+
+ public:
+ struct EffectDescription {
+ int id;
+ std::string GFX;
+ std::string SFX;
+ };
+
+
+ EffectManager();
+
+ ~EffectManager();
+
+ /**
+ * Triggers a effect with the id, at
+ * the specified being.
+ */
+ bool trigger(int id, Being* being);
+
+ /**
+ * Triggers a effect with the id, at
+ * the specified x and y coordinate.
+ */
+ bool trigger(int id, int x, int y);
+
+ private:
+ std::list<EffectDescription> mEffects;
+
+};
+
+extern EffectManager *effectManager;
+
+#endif // _EFFECT_MANAGER_H
diff --git a/src/emoteshortcut.cpp b/src/emoteshortcut.cpp
new file mode 100644
index 00000000..66989d44
--- /dev/null
+++ b/src/emoteshortcut.cpp
@@ -0,0 +1,77 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "emoteshortcut.h"
+
+#include "configuration.h"
+#include "localplayer.h"
+
+#include "utils/tostring.h"
+
+EmoteShortcut::EmoteShortcut *emoteShortcut;
+
+EmoteShortcut::EmoteShortcut():
+ mEmoteSelected(0)
+{
+ for (int i = 0; i < SHORTCUT_EMOTES; i++)
+ {
+ mEmotes[i] = i + 1;
+ }
+ load();
+}
+
+EmoteShortcut::~EmoteShortcut()
+{
+ save();
+}
+
+void EmoteShortcut::load()
+{
+ for (int i = 0; i < SHORTCUT_EMOTES; i++)
+ {
+ int emoteId = (int) config.getValue("emoteshortcut" + toString(i), i + 1);
+
+ if (emoteId)
+ {
+ mEmotes[i] = emoteId;
+ }
+ }
+}
+
+void EmoteShortcut::save()
+{
+ for (int i = 0; i < SHORTCUT_EMOTES; i++)
+ {
+ const int emoteId = mEmotes[i] ? mEmotes[i] : 0;
+ config.setValue("emoteshortcut" + toString(i), emoteId);
+ }
+}
+
+void EmoteShortcut::useEmote(int index)
+{
+ if ((index > 0) && (index <= SHORTCUT_EMOTES))
+ {
+ if (mEmotes[index - 1] > 0)
+ {
+ player_node->emote(mEmotes[index - 1]);
+ }
+ }
+}
diff --git a/src/emoteshortcut.h b/src/emoteshortcut.h
new file mode 100644
index 00000000..3f907e1b
--- /dev/null
+++ b/src/emoteshortcut.h
@@ -0,0 +1,125 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EMOTESHORTCUT_H__
+#define EMOTESHORTCUT_H__
+
+#define SHORTCUT_EMOTES 12
+
+/**
+ * The class which keeps track of the emote shortcuts.
+ */
+class EmoteShortcut
+{
+ public:
+ /**
+ * Constructor.
+ */
+ EmoteShortcut();
+
+ /**
+ * Destructor.
+ */
+ ~EmoteShortcut();
+
+ /**
+ * Load the configuration information.
+ */
+ void load();
+
+ /**
+ * Returns the shortcut Emote ID specified by the index.
+ *
+ * @param index Index of the shortcut Emote.
+ */
+ int getEmote(int index) const
+ { return mEmotes[index]; }
+
+ /**
+ * Returns the amount of shortcut Emotes.
+ */
+ int getEmoteCount() const
+ { return SHORTCUT_EMOTES; }
+
+ /**
+ * Returns the emote ID that is currently selected.
+ */
+ int getEmoteSelected() const
+ { return mEmoteSelected; }
+
+ /**
+ * Adds the selected emote ID to the emotes specified by the index.
+ *
+ * @param index Index of the emotes.
+ */
+ void setEmote(int index)
+ { mEmotes[index] = mEmoteSelected; }
+
+ /**
+ * Adds a emoticon to the emotes store specified by the index.
+ *
+ * @param index Index of the emote.
+ * @param emoteId ID of the emote.
+ */
+ void setEmotes(int index, int emoteId)
+ { mEmotes[index] = emoteId; }
+
+ /**
+ * Set the Emote that is selected.
+ *
+ * @param emoteId The ID of the emote that is to be assigned.
+ */
+ void setEmoteSelected(int emoteId)
+ { mEmoteSelected = emoteId; }
+
+ /**
+ * A flag to check if the Emote is selected.
+ */
+ bool isEmoteSelected()
+ { return mEmoteSelected; }
+
+ /**
+ * Remove a Emote from the shortcut.
+ */
+ void removeEmote(int index)
+ { mEmotes[index] = 0; }
+
+ /**
+ * Try to use the Emote specified by the index.
+ *
+ * @param index Index of the emote shortcut.
+ */
+ void useEmote(int index);
+
+ private:
+ /**
+ * Save the configuration information.
+ */
+ void save();
+
+ int mEmotes[SHORTCUT_EMOTES]; /**< The emote stored. */
+ int mEmoteSelected; /**< The emote held by cursor. */
+
+};
+
+extern EmoteShortcut *emoteShortcut;
+
+#endif
diff --git a/src/engine.cpp b/src/engine.cpp
index 7a76e1b0..29b8921a 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "engine.h"
-
#include <list>
#include "being.h"
#include "beingmanager.h"
#include "configuration.h"
+#include "engine.h"
#include "flooritemmanager.h"
#include "game.h"
#include "graphics.h"
@@ -82,28 +81,40 @@ void Engine::changeMap(const std::string &mapPath)
map_path = "maps/" + mapPath.substr(0, mapPath.rfind(".")) + ".tmx";
ResourceManager *resman = ResourceManager::getInstance();
if (!resman->exists(map_path))
- {
map_path += ".gz";
- }
// Attempt to load the new map
Map *newMap = MapReader::readMap(map_path);
- if (!newMap) {
+ if (!newMap)
logger->error("Could not find map file");
- }
// Notify the minimap and beingManager about the map change
Image *mapImage = NULL;
if (newMap->hasProperty("minimap"))
{
mapImage = resman->getImage(newMap->getProperty("minimap"));
- }
- if (newMap->hasProperty("name"))
- {
- minimap->setCaption(newMap->getProperty("name"));
- } else {
- minimap->setCaption("Map");
+
+ // Set the title for the Minimap
+ if (newMap->hasProperty("mapname"))
+ minimap->setCaption(newMap->getProperty("mapname"));
+ else if (newMap->hasProperty("name"))
+ minimap->setCaption(newMap->getProperty("name"));
+ else
+ {
+ minimap->setCaption("Unknown");
+ logger->log("WARNING: Map file '%s' defines a minimap image but "
+ "does not define a 'mapname' property",
+ map_path.c_str());
+ }
+
+ // How many pixels equal one tile. .5 (which is the TMW default) is
+ // 2 tiles to a pixel, while 1 is 1 tile to 1 pixel
+ if (newMap->hasProperty("minimapproportion"))
+ minimap->setProportion(atof(
+ newMap->getProperty("minimapproportion").c_str()));
+ else
+ minimap->setProportion(0.5);
}
minimap->setMapImage(mapImage);
beingManager->setMap(newMap);
@@ -116,16 +127,16 @@ void Engine::changeMap(const std::string &mapPath)
// Start playing new music file when necessary
std::string oldMusic = "";
- if (mCurrentMap) {
+ if (mCurrentMap)
+ {
oldMusic = mCurrentMap->getProperty("music");
delete mCurrentMap;
}
std::string newMusic = newMap->getProperty("music");
- if (newMusic != oldMusic) {
+ if (newMusic != oldMusic)
sound.playMusic(newMusic, -1);
- }
mCurrentMap = newMap;
mMapName = mapPath;
diff --git a/src/equipment.cpp b/src/equipment.cpp
index b93beed4..d5e0f656 100644
--- a/src/equipment.cpp
+++ b/src/equipment.cpp
@@ -19,24 +19,24 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <algorithm>
+
#include "equipment.h"
#include "item.h"
#include "inventory.h"
#include "localplayer.h"
-#include <algorithm>
-
Equipment::Equipment():
mArrows(0)
{
std::fill_n(mEquipment, EQUIPMENT_SIZE, 0);
}
-void
-Equipment::setEquipment(int index, int inventoryIndex)
+void Equipment::setEquipment(int index, int inventoryIndex)
{
mEquipment[index] = inventoryIndex;
Item* item = player_node->getInventory()->getItem(inventoryIndex);
if (item)
item->setEquipped(true);
}
+
diff --git a/src/extensions.h b/src/extensions.h
new file mode 100644
index 00000000..5b95afc8
--- /dev/null
+++ b/src/extensions.h
@@ -0,0 +1,34 @@
+/*
+ * Aethyra
+ * Copyright 2008 Lloyd Bryant <sanga@aethyra.com>
+ *
+ * This file is part of the Aethyra project.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _EXTENSIONS_
+#define _EXTENSIONS_
+
+struct EXTENSIONS
+{
+ bool aethyra_inventory;
+ bool aethyra_spells;
+ bool aethyra_misc;
+};
+
+extern struct EXTENSIONS extensions;
+#endif
diff --git a/src/floor_item.cpp b/src/floor_item.cpp
index e96b3652..0c4c1c10 100644
--- a/src/floor_item.cpp
+++ b/src/floor_item.cpp
@@ -20,7 +20,6 @@
*/
#include "floor_item.h"
-
#include "map.h"
FloorItem::FloorItem(unsigned int id,
diff --git a/src/floor_item.h b/src/floor_item.h
index e0a67eca..a7299bfb 100644
--- a/src/floor_item.h
+++ b/src/floor_item.h
@@ -51,42 +51,36 @@ class FloorItem : public Sprite
/**
* Returns instance id of this item.
*/
- unsigned int
- getId() const { return mId; }
+ unsigned int getId() const { return mId; }
/**
* Returns the item id.
*/
- unsigned int
- getItemId() const { return mItem->getId(); }
+ unsigned int getItemId() const { return mItem->getId(); }
/**
* Returns the x coordinate.
*/
- unsigned short
- getX() const { return mX; }
+ unsigned short getX() const { return mX; }
/**
* Returns the y coordinate.
*/
- unsigned short
- getY() const { return mY; }
+ unsigned short getY() const { return mY; }
/**
* Returns the pixel y coordinate.
*
* @see Sprite::getPixelY()
*/
- int
- getPixelY() const { return mY * 32; }
+ int getPixelY() const { return mY * 32; }
/**
* Draws this floor item to the given graphics context.
*
* @see Sprite::draw(Graphics, int, int)
*/
- void
- draw(Graphics *graphics, int offsetX, int offsetY) const
+ void draw(Graphics *graphics, int offsetX, int offsetY) const
{
graphics->drawImage(mItem->getImage(),
mX * 32 + offsetX,
diff --git a/src/flooritemmanager.cpp b/src/flooritemmanager.cpp
index 836bbe8d..65556abb 100644
--- a/src/flooritemmanager.cpp
+++ b/src/flooritemmanager.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "flooritemmanager.h"
-
#include "floor_item.h"
+#include "flooritemmanager.h"
#include "utils/dtor.h"
diff --git a/src/game.cpp b/src/game.cpp
index 1c4bb538..3b943f6b 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -19,19 +19,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "game.h"
-
#include <fstream>
#include <physfs.h>
#include <sstream>
#include <string>
#include <guichan/exception.hpp>
+#include <guichan/sdl/sdlinput.hpp>
#include "beingmanager.h"
-#include "configuration.h"
+#include "effectmanager.h"
+#include "emoteshortcut.h"
#include "engine.h"
#include "flooritemmanager.h"
+#include "game.h"
#include "graphics.h"
#include "itemshortcut.h"
#include "joystick.h"
@@ -47,11 +48,15 @@
#include "gui/chat.h"
#include "gui/confirm_dialog.h"
#include "gui/debugwindow.h"
+#include "gui/emoteshortcutcontainer.h"
+#include "gui/emotewindow.h"
#include "gui/equipmentwindow.h"
#include "gui/gui.h"
#include "gui/help.h"
#include "gui/inventorywindow.h"
-#include "gui/itemshortcutwindow.h"
+#include "gui/shortcutwindow.h"
+#include "gui/shortcutcontainer.h"
+#include "gui/itemshortcutcontainer.h"
#include "gui/menuwindow.h"
#include "gui/minimap.h"
#include "gui/ministatus.h"
@@ -75,15 +80,19 @@
#include "net/equipmenthandler.h"
#include "net/inventoryhandler.h"
#include "net/itemhandler.h"
+#include "net/messageout.h"
#include "net/network.h"
#include "net/npchandler.h"
#include "net/playerhandler.h"
+#include "net/protocol.h"
#include "net/skillhandler.h"
#include "net/tradehandler.h"
#include "net/messageout.h"
#include "resources/imagewriter.h"
+#include "utils/gettext.h"
+
extern Graphics *graphics;
class Map;
@@ -93,6 +102,7 @@ std::string map_path;
bool done = false;
volatile int tick_time;
volatile int fps = 0, frame = 0;
+
Engine *engine = NULL;
Joystick *joystick = NULL;
@@ -109,6 +119,7 @@ BuyDialog *buyDialog;
SellDialog *sellDialog;
BuySellDialog *buySellDialog;
InventoryWindow *inventoryWindow;
+EmoteWindow *emoteWindow;
NpcIntegerDialog *npcIntegerDialog;
NpcListDialog *npcListDialog;
NpcTextDialog *npcTextDialog;
@@ -118,19 +129,20 @@ Setup* setupWindow;
Minimap *minimap;
EquipmentWindow *equipmentWindow;
TradeWindow *tradeWindow;
-//BuddyWindow *buddyWindow;
HelpWindow *helpWindow;
DebugWindow *debugWindow;
-ItemShortcutWindow *itemShortcutWindow;
+ShortcutWindow *itemShortcutWindow;
+ShortcutWindow *emoteShortcutWindow;
BeingManager *beingManager = NULL;
FloorItemManager *floorItemManager = NULL;
Particle* particleEngine = NULL;
+EffectManager *effectManager = NULL;
const int MAX_TIME = 10000;
/**
- * Listener used for exitting handling.
+ * Listener used for exiting handling.
*/
namespace {
struct ExitListener : public gcn::ActionListener
@@ -163,15 +175,18 @@ Uint32 nextSecond(Uint32 interval, void *param)
{
fps = frame;
frame = 0;
+
return interval;
}
int get_elapsed_time(int start_time)
{
- if (start_time <= tick_time) {
+ if (start_time <= tick_time)
+ {
return (tick_time - start_time) * 10;
}
- else {
+ else
+ {
return (tick_time + (MAX_TIME - start_time)) * 10;
}
}
@@ -190,6 +205,7 @@ void createGuiWindows(Network *network)
sellDialog = new SellDialog(network);
buySellDialog = new BuySellDialog();
inventoryWindow = new InventoryWindow();
+ emoteWindow = new EmoteWindow();
npcTextDialog = new NpcTextDialog();
npcIntegerDialog = new NpcIntegerDialog();
npcListDialog = new NpcListDialog();
@@ -199,20 +215,16 @@ void createGuiWindows(Network *network)
minimap = new Minimap();
equipmentWindow = new EquipmentWindow(player_node->mEquipment.get());
tradeWindow = new TradeWindow(network);
- //buddyWindow = new BuddyWindow();
helpWindow = new HelpWindow();
debugWindow = new DebugWindow();
- itemShortcutWindow = new ItemShortcutWindow();
-
- // Initialize window positions
- //buddyWindow->setPosition(10, minimap->getHeight() + 30);
+ itemShortcutWindow = new ShortcutWindow("ItemShortcut",new ItemShortcutContainer);
+ emoteShortcutWindow = new ShortcutWindow("emoteShortcut",new EmoteShortcutContainer);
// Set initial window visibility
chatWindow->setVisible((bool) config.getValue(
chatWindow->getWindowName() + "Visible", true));
miniStatusWindow->setVisible((bool) config.getValue(
- miniStatusWindow->getWindowName() + "Visible",
- true));
+ miniStatusWindow->getWindowName() + "Visible", true));
buyDialog->setVisible(false);
sellDialog->setVisible(false);
minimap->setVisible((bool) config.getValue(
@@ -222,11 +234,10 @@ void createGuiWindows(Network *network)
menuWindow->getWindowName() + "Visible", true));
itemShortcutWindow->setVisible((bool) config.getValue(
itemShortcutWindow->getWindowName() + "Visible", true));
-
- if (config.getValue("logToChat", 0))
- {
- logger->setChatWindow(chatWindow);
- }
+ emoteShortcutWindow->setVisible((bool) config.getValue(
+ emoteShortcutWindow->getWindowName() + "Visible", true));
+ minimap->setVisible((bool) config.getValue(
+ minimap->getWindowName() + "Visible", true));
}
/**
@@ -243,6 +254,7 @@ void destroyGuiWindows()
delete sellDialog;
delete buySellDialog;
delete inventoryWindow;
+ delete emoteWindow;
delete npcIntegerDialog;
delete npcListDialog;
delete npcTextDialog;
@@ -252,10 +264,10 @@ void destroyGuiWindows()
delete minimap;
delete equipmentWindow;
delete tradeWindow;
- //delete buddyWindow;
delete helpWindow;
delete debugWindow;
delete itemShortcutWindow;
+ delete emoteShortcutWindow;
}
Game::Game(Network *network):
@@ -276,6 +288,8 @@ Game::Game(Network *network):
beingManager = new BeingManager(network);
floorItemManager = new FloorItemManager();
+ effectManager = new EffectManager();
+
particleEngine = new Particle(NULL);
particleEngine->setupEngine();
@@ -310,17 +324,13 @@ Game::Game(Network *network):
network->registerHandler(mTradeHandler.get());
/*
- * THIS IS A TEMPORARY WORKAROUND!
+ * To prevent the server from sending data before the client
+ * has initialized, I've modified it to wait for a "ping"
+ * from the client to complete its initialization
*
- * To prevent the server from sending data before the client has
- * initialized, it's been modified to wait for a "ping" from the client to
- * complete its initialization.
- *
- * The real fix is to make sure we are not throwing away messages in the
- * network buffer due to not having registered the handlers above straight
- * after receiving a login success from the map server.
- *
- * The response from eAthena on this packet is ignored by the client.
+ * Note: This only affects the latest eAthena version. This
+ * packet is handled by the older version, but its response
+ * is ignored by the client
*/
MessageOut msg(mNetwork);
msg.writeInt16(CMSG_CLIENT_PING);
@@ -379,13 +389,13 @@ static bool saveScreenshot()
if (success)
{
std::stringstream chatlogentry;
- chatlogentry << "Screenshot saved to ~/" << filenameSuffix.str();
+ chatlogentry << _("Screenshot saved to ~/") << filenameSuffix.str();
chatWindow->chatLog(chatlogentry.str(), BY_SERVER);
}
else
{
- chatWindow->chatLog("Saving screenshot failed!", BY_SERVER);
- logger->log("Error: could not save screenshot.");
+ chatWindow->chatLog(_("Saving screenshot failed!"), BY_SERVER);
+ logger->log(_("Error: could not save screenshot."));
}
SDL_FreeSurface(screenshot);
@@ -430,7 +440,7 @@ void Game::logic()
// Draw a frame if either frames are not limited or enough time has
// passed since the last frame.
if (!mMinFrameTime ||
- get_elapsed_time(mDrawTime / 10) > mMinFrameTime)
+ get_elapsed_time(mDrawTime / 10) > mMinFrameTime)
{
frame++;
gui->draw();
@@ -460,9 +470,9 @@ void Game::logic()
{
if (!disconnectedDialog)
{
- disconnectedDialog = new OkDialog("Network Error",
- "The connection to the server was lost, "
- "the program will now quit");
+ disconnectedDialog = new OkDialog(_("Network Error"),
+ _("The connection to the server was lost, "
+ "the program will now quit"));
disconnectedDialog->addActionListener(&exitListener);
disconnectedDialog->requestMoveToTop();
}
@@ -486,8 +496,8 @@ void Game::handleInput()
{
gcn::Window *requestedWindow = NULL;
- if (setupWindow->isVisible() &&
- keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
+ if (setupWindow->isVisible() &&
+ keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
{
keyboard.setNewKey((int) event.key.keysym.sym);
keyboard.callbackNewKey();
@@ -496,11 +506,11 @@ void Game::handleInput()
}
// Keys pressed together with Alt/Meta
// Emotions and some internal gui windows
- #ifndef __APPLE__
+#ifndef __APPLE__
if (event.key.keysym.mod & KMOD_LALT)
- #else
+#else
if (event.key.keysym.mod & KMOD_LMETA)
- #endif
+#endif
{
switch (event.key.keysym.sym)
{
@@ -521,52 +531,37 @@ void Game::handleInput()
case SDLK_t:
// Toggle accepting of incoming trade requests
+ unsigned int deflt = player_relations.getDefault();
+ if (deflt & PlayerRelation::TRADE)
{
- unsigned int deflt = player_relations.getDefault();
- if (deflt & PlayerRelation::TRADE) {
- chatWindow->chatLog(
- "Ignoring incoming trade requests",
- BY_SERVER);
- deflt &= ~PlayerRelation::TRADE;
- } else {
- chatWindow->chatLog(
- "Accepting incoming trade requests",
- BY_SERVER);
- deflt |= PlayerRelation::TRADE;
- }
-
- player_relations.setDefault(deflt);
+ chatWindow->chatLog(
+ _("Ignoring incoming trade requests"),
+ BY_SERVER);
+ deflt &= ~PlayerRelation::TRADE;
}
+ else
+ {
+ chatWindow->chatLog(
+ _("Accepting incoming trade requests"),
+ BY_SERVER);
+ deflt |= PlayerRelation::TRADE;
+ }
+
+ player_relations.setDefault(deflt);
+
used = true;
break;
}
}
- // Smilie
- if (keyboard.isKeyActive(keyboard.KEY_SMILIE))
+ // Mode switch to emotes
+ if (keyboard.isKeyActive(keyboard.KEY_EMOTE))
{
// Emotions
- Uint8 emotion;
- switch (event.key.keysym.sym)
- {
- case SDLK_1: emotion = 1; break;
- case SDLK_2: emotion = 2; break;
- case SDLK_3: emotion = 3; break;
- case SDLK_4: emotion = 4; break;
- case SDLK_5: emotion = 5; break;
- case SDLK_6: emotion = 6; break;
- case SDLK_7: emotion = 7; break;
- case SDLK_8: emotion = 8; break;
- case SDLK_9: emotion = 9; break;
- case SDLK_0: emotion = 10; break;
- case SDLK_MINUS: emotion = 11; break;
- case SDLK_EQUALS: emotion = 12; break;
- default: emotion = 0; break;
- }
-
+ int emotion = keyboard.getKeyEmoteOffset(event.key.keysym.sym);
if (emotion)
{
- player_node->emote(emotion);
+ emoteShortcut->useEmote(emotion);
used = true;
return;
}
@@ -580,21 +575,18 @@ void Game::handleInput()
used = true;
}
break;
-
case SDLK_PAGEDOWN:
if (chatWindow->isVisible())
{
chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL);
used = true;
+ return;
}
break;
-
case SDLK_F1:
// In-game Help
if (helpWindow->isVisible())
- {
helpWindow->setVisible(false);
- }
else
{
helpWindow->loadHelp("index");
@@ -606,47 +598,33 @@ void Game::handleInput()
case SDLK_RETURN:
// Input chat window
if (chatWindow->isInputFocused() ||
- deathNotice != NULL ||
- weightNotice != NULL)
+ deathNotice != NULL ||
+ weightNotice != NULL)
{
break;
}
// Quit by pressing Enter if the exit confirm is there
if (exitConfirm)
- {
- done = true;
- }
+ done = true;
// Close the Browser if opened
else if (helpWindow->isVisible())
- {
helpWindow->setVisible(false);
- }
// Close the config window, cancelling changes if opened
else if (setupWindow->isVisible())
- {
setupWindow->action(gcn::ActionEvent(NULL, "cancel"));
- }
// Submits the text and proceeds to the next dialog
else if (npcStringDialog->isVisible())
- {
npcStringDialog->action(gcn::ActionEvent(NULL, "ok"));
- }
// Proceed to the next dialog option, or close the window
else if (npcTextDialog->isVisible())
- {
npcTextDialog->action(gcn::ActionEvent(NULL, "ok"));
- }
// Choose the currently highlighted dialogue option
else if (npcListDialog->isVisible())
- {
npcListDialog->action(gcn::ActionEvent(NULL, "ok"));
- }
// Submits the text and proceeds to the next dialog
else if (npcIntegerDialog->isVisible())
- {
npcIntegerDialog->action(gcn::ActionEvent(NULL, "ok"));
- }
// Else, open the chat edit box
else
{
@@ -654,17 +632,19 @@ void Game::handleInput()
used = true;
}
break;
- // Quitting confirmation dialog
- case SDLK_ESCAPE:
- if (!exitConfirm) {
- exitConfirm = new ConfirmDialog(
- "Quit", "Are you sure you want to quit?");
+ // Quitting confirmation dialog
+ case SDLK_ESCAPE:
+ if (!exitConfirm)
+ {
+ exitConfirm = new ConfirmDialog( _("Quit"),
+ _("Are you sure you "
+ "want to quit?"));
exitConfirm->addActionListener(&exitListener);
exitConfirm->requestMoveToTop();
}
else
{
- exitConfirm->action(gcn::ActionEvent(NULL, "no"));
+ exitConfirm->action(gcn::ActionEvent(NULL, _("no")));
}
break;
@@ -672,25 +652,29 @@ void Game::handleInput()
break;
}
if (keyboard.isEnabled() && !chatWindow->isInputFocused()
- && !npcStringDialog->isInputFocused())
+ && !npcStringDialog->isInputFocused())
{
const int tKey = keyboard.getKeyIndex(event.key.keysym.sym);
+
// Do not activate shortcuts if tradewindow is visible
if (!tradeWindow->isVisible())
{
// Checks if any item shortcut is pressed.
- for (int i = KeyboardConfig::KEY_SHORTCUT_0;
- i <= KeyboardConfig::KEY_SHORTCUT_9;
- i++)
+ for (int i = KeyboardConfig::KEY_SHORTCUT_1;
+ i <= KeyboardConfig::KEY_SHORTCUT_12;
+ i++)
{
- if (tKey == i && !used) {
+ if (tKey == i && !used)
+ {
itemShortcut->useItem(
- i - KeyboardConfig::KEY_SHORTCUT_0);
+ i - KeyboardConfig::KEY_SHORTCUT_1);
break;
}
}
}
- switch (tKey) {
+
+ switch (tKey)
+ {
case KeyboardConfig::KEY_PICKUP:
{
FloorItem *item =
@@ -699,7 +683,8 @@ void Game::handleInput()
// If none below the player, try the tile in front
// of the player
- if (!item) {
+ if (!item)
+ {
Uint16 x = player_node->mX;
Uint16 y = player_node->mY;
if (player_node->getDirection() & Being::UP)
@@ -727,11 +712,12 @@ void Game::handleInput()
used = true;
break;
case KeyboardConfig::KEY_HIDE_WINDOWS:
- // Hide certain windows
+ // Hide certain windows
if (!chatWindow->isInputFocused())
{
statusWindow->setVisible(false);
inventoryWindow->setVisible(false);
+ emoteWindow->setVisible(false);
skillDialog->setVisible(false);
setupWindow->setVisible(false);
equipmentWindow->setVisible(false);
@@ -739,7 +725,6 @@ void Game::handleInput()
debugWindow->setVisible(false);
}
break;
-
case KeyboardConfig::KEY_WINDOW_STATUS:
requestedWindow = statusWindow;
break;
@@ -753,6 +738,7 @@ void Game::handleInput()
requestedWindow = skillDialog;
break;
case KeyboardConfig::KEY_WINDOW_MINIMAP:
+ minimap->toggle();
requestedWindow = minimap;
break;
case KeyboardConfig::KEY_WINDOW_CHAT:
@@ -767,6 +753,12 @@ void Game::handleInput()
case KeyboardConfig::KEY_WINDOW_DEBUG:
requestedWindow = debugWindow;
break;
+ case KeyboardConfig::KEY_WINDOW_EMOTE:
+ requestedWindow = emoteWindow;
+ break;
+ case KeyboardConfig::KEY_WINDOW_EMOTE_SHORTCUT:
+ requestedWindow = emoteShortcutWindow;
+ break;
}
}
@@ -774,14 +766,10 @@ void Game::handleInput()
{
requestedWindow->setVisible(!requestedWindow->isVisible());
if (requestedWindow->isVisible())
- {
requestedWindow->requestMoveToTop();
- }
used = true;
}
-
}
-
// Quit event
else if (event.type == SDL_QUIT)
{
@@ -798,10 +786,9 @@ void Game::handleInput()
catch (gcn::Exception e)
{
const char* err = e.getMessage().c_str();
- logger->log("Warning: guichan input exception: %s", err);
+ logger->log(_("Warning: guichan input exception: %s"), err);
}
}
-
} // End while
// If the user is configuring the keys then don't respond.
@@ -810,8 +797,7 @@ void Game::handleInput()
// Moving player around
if (player_node->mAction != Being::DEAD &&
- current_npc == 0 &&
- !chatWindow->isInputFocused())
+ current_npc == 0 && !chatWindow->isInputFocused())
{
// Get the state of the keyboard keys
keyboard.refreshActiveKeys();
@@ -822,23 +808,23 @@ void Game::handleInput()
// Translate pressed keys to movement and direction
if (keyboard.isKeyActive(keyboard.KEY_MOVE_UP) ||
- (joystick && joystick->isUp()))
+ (joystick && joystick->isUp()))
{
direction |= Being::UP;
}
else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) ||
- (joystick && joystick->isDown()))
+ (joystick && joystick->isDown()))
{
direction |= Being::DOWN;
}
if (keyboard.isKeyActive(keyboard.KEY_MOVE_LEFT) ||
- (joystick && joystick->isLeft()))
+ (joystick && joystick->isLeft()))
{
direction |= Being::LEFT;
}
else if (keyboard.isKeyActive(keyboard.KEY_MOVE_RIGHT) ||
- (joystick && joystick->isRight()))
+ (joystick && joystick->isRight()))
{
direction |= Being::RIGHT;
}
@@ -847,60 +833,92 @@ void Game::handleInput()
// Attacking monsters
if (keyboard.isKeyActive(keyboard.KEY_ATTACK) ||
- (joystick && joystick->buttonPressed(0)))
+ (joystick && joystick->buttonPressed(0)))
{
- Being *target = NULL;
- bool newTarget = keyboard.isKeyActive(keyboard.KEY_TARGET);
+ Being *target = beingManager->findNearestLivingBeing(x, y, 20,
+ Being::MONSTER);
+
+ bool newTarget = !keyboard.isKeyActive(keyboard.KEY_TARGET);
// A set target has highest priority
if (newTarget || !player_node->getTarget())
{
Uint16 targetX = x, targetY = y;
- if (player_node->getDirection() & Being::UP)
- targetY--;
- if (player_node->getDirection() & Being::DOWN)
- targetY++;
- if (player_node->getDirection() & Being::LEFT)
- targetX--;
- if (player_node->getDirection() & Being::RIGHT)
- targetX++;
+ switch (player_node->getSpriteDirection())
+ {
+ case DIRECTION_UP : --targetY; break;
+ case DIRECTION_DOWN : ++targetY; break;
+ case DIRECTION_LEFT : --targetX; break;
+ case DIRECTION_RIGHT: ++targetX; break;
+ default: break;
+ }
// Attack priorioty is: Monster, Player, auto target
- target = beingManager->findBeing(
- targetX, targetY, Being::MONSTER);
+ target = beingManager->findBeing(targetX, targetY, Being::MONSTER);
if (!target)
- target = beingManager->findBeing(
- targetX, targetY, Being::PLAYER);
+ target = beingManager->findBeing(targetX, targetY, Being::PLAYER);
}
player_node->attack(target, newTarget);
}
- // Target the nearest player
- if (keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER))
+ // Target the nearest player if 'q' is pressed
+ if ( keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER) &&
+ !keyboard.isKeyActive(keyboard.KEY_TARGET) )
{
- Being *target = beingManager->findNearestLivingBeing(
- player_node, 20, Being::PLAYER);
+ Being *target = beingManager->findNearestLivingBeing(player_node, 20, Being::PLAYER);
- if (target)
- {
- player_node->setTarget(target);
- }
+ player_node->setTarget(target);
}
- // Target the nearest monster
- if (keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST)
- || (joystick && joystick->buttonPressed(3)))
+ // Target the nearest monster if 'a' pressed
+ if ((keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) ||
+ (joystick && joystick->buttonPressed(3))) &&
+ !keyboard.isKeyActive(keyboard.KEY_TARGET))
{
Being *target = beingManager->findNearestLivingBeing(
x, y, 20, Being::MONSTER);
- if (target)
+ player_node->setTarget(target);
+ }
+
+ // Target the nearest npc if 'n' pressed
+ if ( keyboard.isKeyActive(keyboard.KEY_TARGET_NPC) &&
+ !keyboard.isKeyActive(keyboard.KEY_TARGET) )
+ {
+ Being *target = beingManager->findNearestLivingBeing(
+ x, y, 20, Being::NPC);
+
+ player_node->setTarget(target);
+ }
+
+ // Talk to the nearest NPC if 't' pressed
+ if ( keyboard.isKeyActive(keyboard.KEY_TALK) )
+ {
+ if (!npcTextDialog->isVisible() && !npcListDialog->isVisible())
{
- player_node->setTarget(target);
+ Being *target = player_node->getTarget();
+
+ if (!target)
+ {
+ target = beingManager->findNearestLivingBeing(
+ x, y, 20, Being::NPC);
+ }
+
+ if (target)
+ {
+ if (target->getType() == Being::NPC)
+ dynamic_cast<NPC*>(target)->talk();
+ }
}
}
+ // Stop attacking if shift is pressed
+ if (keyboard.isKeyActive(keyboard.KEY_TARGET))
+ {
+ player_node->stopAttack();
+ }
+
if (joystick)
{
if (joystick->buttonPressed(1))
diff --git a/src/game.h b/src/game.h
index fd824a2a..4f512d97 100644
--- a/src/game.h
+++ b/src/game.h
@@ -40,35 +40,35 @@ extern volatile int tick_time;
class Game : public ConfigListener
{
public:
- Game(Network *network);
- ~Game();
+ Game(Network *network);
+ ~Game();
- void logic();
+ void logic();
- void handleInput();
+ void handleInput();
- void optionChanged(const std::string &name);
+ void optionChanged(const std::string &name);
private:
- Network *mNetwork;
-
- /** Used to determine whether to draw the next frame. */
- int mDrawTime;
-
- /** The minimum frame time (used for frame limiting). */
- int mMinFrameTime;
-
- typedef const std::auto_ptr<MessageHandler> MessageHandlerPtr;
- MessageHandlerPtr mBeingHandler;
- MessageHandlerPtr mBuySellHandler;
- MessageHandlerPtr mChatHandler;
- MessageHandlerPtr mEquipmentHandler;
- MessageHandlerPtr mInventoryHandler;
- MessageHandlerPtr mItemHandler;
- MessageHandlerPtr mNpcHandler;
- MessageHandlerPtr mPlayerHandler;
- MessageHandlerPtr mSkillHandler;
- MessageHandlerPtr mTradeHandler;
+ Network *mNetwork;
+
+ /** Used to determine whether to draw the next frame. */
+ int mDrawTime;
+
+ /** The minimum frame time (used for frame limiting). */
+ int mMinFrameTime;
+
+ typedef const std::auto_ptr<MessageHandler> MessageHandlerPtr;
+ MessageHandlerPtr mBeingHandler;
+ MessageHandlerPtr mBuySellHandler;
+ MessageHandlerPtr mChatHandler;
+ MessageHandlerPtr mEquipmentHandler;
+ MessageHandlerPtr mInventoryHandler;
+ MessageHandlerPtr mItemHandler;
+ MessageHandlerPtr mNpcHandler;
+ MessageHandlerPtr mPlayerHandler;
+ MessageHandlerPtr mSkillHandler;
+ MessageHandlerPtr mTradeHandler;
};
/**
diff --git a/src/graphics.cpp b/src/graphics.cpp
index bbe4221e..4af7b723 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -42,6 +42,8 @@ bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
logger->log("Setting video mode %dx%d %s",
w, h, fs ? "fullscreen" : "windowed");
+ logger->log("Bits per pixel: %d", bpp);
+
int displayFlags = SDL_ANYFORMAT;
mFullscreen = fs;
@@ -69,7 +71,7 @@ bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
logger->log("Using video driver: %s", videoDriverName);
}
else {
- logger->log("Using video driver: unkown");
+ logger->log("Using video driver: unknown");
}
const SDL_VideoInfo *vi = SDL_GetVideoInfo();
@@ -176,13 +178,12 @@ void Graphics::drawImagePattern(Image *image, int x, int y, int w, int h)
}
}
-void
-Graphics::drawImageRect(int x, int y, int w, int h,
- Image *topLeft, Image *topRight,
- Image *bottomLeft, Image *bottomRight,
- Image *top, Image *right,
- Image *bottom, Image *left,
- Image *center)
+void Graphics::drawImageRect(int x, int y, int w, int h,
+ Image *topLeft, Image *topRight,
+ Image *bottomLeft, Image *bottomRight,
+ Image *top, Image *right,
+ Image *bottom, Image *left,
+ Image *center)
{
pushClipArea(gcn::Rectangle(x, y, w, h));
@@ -220,9 +221,8 @@ Graphics::drawImageRect(int x, int y, int w, int h,
popClipArea();
}
-void
-Graphics::drawImageRect(int x, int y, int w, int h,
- const ImageRect &imgRect)
+void Graphics::drawImageRect(int x, int y, int w, int h,
+ const ImageRect &imgRect)
{
drawImageRect(x, y, w, h,
imgRect.grid[0], imgRect.grid[2], imgRect.grid[6], imgRect.grid[8],
diff --git a/src/graphics.h b/src/graphics.h
index 4a695a7a..8009ceda 100644
--- a/src/graphics.h
+++ b/src/graphics.h
@@ -95,17 +95,15 @@ class Graphics : public gcn::SDLGraphics {
* @return <code>true</code> if the image was blitted properly
* <code>false</code> otherwise.
*/
- virtual bool
- drawImage(Image *image,
- int srcX, int srcY,
- int dstX, int dstY,
- int width, int height,
- bool useColor = false);
-
- virtual void
- drawImagePattern(Image *image,
- int x, int y,
- int w, int h);
+ virtual bool drawImage(Image *image,
+ int srcX, int srcY,
+ int dstX, int dstY,
+ int width, int height,
+ bool useColor = false);
+
+ virtual void drawImagePattern(Image *image,
+ int x, int y,
+ int w, int h);
/**
* Draws a rectangle using images. 4 corner images, 4 side images and 1
diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp
index 2d805b9c..6fd0482a 100644
--- a/src/gui/browserbox.cpp
+++ b/src/gui/browserbox.cpp
@@ -22,7 +22,7 @@
#include <algorithm>
#include "browserbox.h"
-
+#include "colour.h"
#include "linkhandler.h"
#include "truetypefont.h"
@@ -98,12 +98,12 @@ void BrowserBox::addRow(const std::string &row)
mLinks.push_back(bLink);
- newRow += "##L" + bLink.caption;
+ newRow += "##<" + bLink.caption;
tmp.erase(0, idx3 + 2);
if(tmp != "")
{
- newRow += "##P";
+ newRow += "##>";
}
idx1 = tmp.find("@@");
}
@@ -210,8 +210,7 @@ struct MouseOverLink
int mX, mY;
};
-void
-BrowserBox::mousePressed(gcn::MouseEvent &event)
+void BrowserBox::mousePressed(gcn::MouseEvent &event)
{
LinkIterator i = find_if(mLinks.begin(), mLinks.end(),
MouseOverLink(event.getX(), event.getY()));
@@ -221,8 +220,7 @@ BrowserBox::mousePressed(gcn::MouseEvent &event)
}
}
-void
-BrowserBox::mouseMoved(gcn::MouseEvent &event)
+void BrowserBox::mouseMoved(gcn::MouseEvent &event)
{
LinkIterator i = find_if(mLinks.begin(), mLinks.end(),
MouseOverLink(event.getX(), event.getY()));
@@ -230,8 +228,7 @@ BrowserBox::mouseMoved(gcn::MouseEvent &event)
mSelectedLink = (i != mLinks.end()) ? (i - mLinks.begin()) : -1;
}
-void
-BrowserBox::draw(gcn::Graphics *graphics)
+void BrowserBox::draw(gcn::Graphics *graphics)
{
if (mOpaque)
{
@@ -254,7 +251,8 @@ BrowserBox::draw(gcn::Graphics *graphics)
if ((mHighMode & UNDERLINE))
{
- graphics->setColor(gcn::Color(LINK));
+ bool valid;
+ graphics->setColor(gcn::Color(textColour->getColour('<', valid)));
graphics->drawLine(
mLinks[mSelectedLink].x1,
mLinks[mSelectedLink].y2,
@@ -311,57 +309,30 @@ BrowserBox::draw(gcn::Graphics *graphics)
// Check for color change in format "##x", x = [L,P,0..9]
if (row.find("##", start) == start && row.size() > start + 2)
{
- switch (row.at(start + 2))
+ char c = row.at(start + 2);
+ if (c == '>')
{
- case 'L': // Link color
- prevColor = selColor;
- selColor = LINK;
- break;
- case 'P': // Previous color
- selColor = prevColor;
- break;
- case '1':
- prevColor = selColor;
- selColor = RED;
- break;
- case '2':
- prevColor = selColor;
- selColor = GREEN;
- break;
- case '3':
- prevColor = selColor;
- selColor = BLUE;
- break;
- case '4':
- prevColor = selColor;
- selColor = ORANGE;
- break;
- case '5':
- prevColor = selColor;
- selColor = YELLOW;
- break;
- case '6':
- prevColor = selColor;
- selColor = PINK;
- break;
- case '7':
- prevColor = selColor;
- selColor = PURPLE;
- break;
- case '8':
- prevColor = selColor;
- selColor = GRAY;
- break;
- case '9':
- prevColor = selColor;
- selColor = BROWN;
- break;
- case '0':
- default:
+ selColor = prevColor;
+ }
+ else
+ {
+ bool valid;
+ int rgb = textColour->getColour(c, valid);
+ if (c == '<')
+ {
prevColor = selColor;
- selColor = BLACK;
+ }
+ if (valid)
+ {
+ selColor = rgb;
+ }
}
start += 3;
+
+ if (start == row.size())
+ {
+ break;
+ }
}
graphics->setColor(gcn::Color(selColor));
}
@@ -424,3 +395,4 @@ BrowserBox::draw(gcn::Graphics *graphics)
setHeight((mTextRows.size() + wrappedLines) * font->getHeight());
}
}
+
diff --git a/src/gui/browserbox.h b/src/gui/browserbox.h
index 4dc41e3d..4bdf224b 100644
--- a/src/gui/browserbox.h
+++ b/src/gui/browserbox.h
@@ -165,3 +165,4 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener
};
#endif
+
diff --git a/src/gui/buddywindow.cpp b/src/gui/buddywindow.cpp
deleted file mode 100644
index 0927ddf8..00000000
--- a/src/gui/buddywindow.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * The Mana World
- * Copyright (C) 2004 The Mana World Development Team
- *
- * This file is part of The Mana World.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "buddywindow.h"
-
-#include <guichan/widgets/listbox.hpp>
-
-#include "button.h"
-#include "chat.h"
-#include "scrollarea.h"
-
-#include "../resources/buddylist.h"
-
-extern ChatWindow *chatWindow;
-
-BuddyWindow::BuddyWindow():
- Window("Buddy")
-{
- setContentSize(124, 202);
-
- mBuddyList = new BuddyList();
-
- mListbox = new gcn::ListBox();
- mListbox->setListModel(mBuddyList);
-
- ScrollArea *scrollArea = new ScrollArea(mListbox);
- scrollArea->setDimension(gcn::Rectangle(
- 7, 5, 110, 170));
- add(scrollArea);
-
- Button *talk = new Button("Talk", "Talk", this);
- Button *remove = new Button("Remove", "Remove", this);
- Button *cancel = new Button("Cancel", "Cancel", this);
-
- talk->setPosition(2,180);
- remove->setPosition(talk->getWidth()+2,180);
- cancel->setPosition(talk->getWidth()+remove->getWidth()+2,180);
-
- add(talk);
- add(remove);
- add(cancel);
-}
-
-void BuddyWindow::action(const gcn::ActionEvent &event)
-{
- if (event.getId() == "Talk") {
- int selected = mListbox->getSelected();
- if ( selected > -1 )
- {
- std::string who = mBuddyList->getElementAt(selected);
- chatWindow->setInputText(who +": ");
- }
- }
- else if (event.getId() == "Remove") {
- int selected = mListbox->getSelected();
- if ( selected > -1 )
- {
- std::string who = mBuddyList->getElementAt(selected);
- mBuddyList->removeBuddy(who);
- }
- }
- else if (event.getId() == "Cancel") {
- setVisible(false);
- }
-}
diff --git a/src/gui/button.cpp b/src/gui/button.cpp
index caf93b94..9b624015 100644
--- a/src/gui/button.cpp
+++ b/src/gui/button.cpp
@@ -122,8 +122,7 @@ Button::~Button()
}
}
-void
-Button::draw(gcn::Graphics *graphics)
+void Button::draw(gcn::Graphics *graphics)
{
int mode;
diff --git a/src/gui/button.h b/src/gui/button.h
index 0ec99245..d8ed9fa7 100644
--- a/src/gui/button.h
+++ b/src/gui/button.h
@@ -26,6 +26,8 @@
#include <guichan/widgets/button.hpp>
+#include "../guichanfwd.h"
+
class ImageRect;
/**
diff --git a/src/gui/buttonbox.cpp b/src/gui/buttonbox.cpp
new file mode 100644
index 00000000..d29f3c58
--- /dev/null
+++ b/src/gui/buttonbox.cpp
@@ -0,0 +1,43 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "button.h"
+#include "buttonbox.h"
+
+ButtonBox::ButtonBox(const std::string &title, const std::string &buttonTxt,
+ ButtonBoxListener *listener) :
+ Window(title),
+ mListener(listener)
+{
+ Button *button = new Button(buttonTxt, "activate", this);
+ setContentSize(button->getWidth() + 10,
+ button->getHeight() + 10);
+ button->setPosition(5, 5);
+ add(button);
+}
+
+void ButtonBox::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "activate")
+ {
+ mListener->buttonBoxRespond();
+ }
+}
diff --git a/src/gui/buttonbox.h b/src/gui/buttonbox.h
new file mode 100644
index 00000000..6d0e46b6
--- /dev/null
+++ b/src/gui/buttonbox.h
@@ -0,0 +1,69 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef BUTTONBOX_H
+#define BUTTONBOX_H
+
+#include <string>
+
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+
+#include "../guichanfwd.h"
+
+class ButtonBoxListener
+{
+ public:
+
+ /*
+ * function that ButtonBox calls when the button has been pressed
+ */
+ virtual void buttonBoxRespond() = 0;
+};
+
+class ButtonBox : public Window, public gcn::ActionListener
+{
+ public:
+
+ /*
+ * Constructor
+ *
+ * @param title is the text that appears at the top of the box
+ * @param buttonTxt is the text that appears on the button
+ * @param listener points to the class that should respond to the
+ * button press
+ */
+ ButtonBox(const std::string &title, const std::string &buttonTxt,
+ ButtonBoxListener *listener);
+
+ /*
+ * called when the button is pressed
+ *
+ * @param event is the event that is generated
+ */
+ void action(const gcn::ActionEvent &event);
+
+ private:
+
+ ButtonBoxListener *mListener;
+};
+#endif
diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp
index 49dd52af..0c8c4d9d 100644
--- a/src/gui/buy.cpp
+++ b/src/gui/buy.cpp
@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "buy.h"
-
#include <guichan/widgets/label.hpp>
#include "button.h"
+#include "buy.h"
#include "scrollarea.h"
#include "shop.h"
#include "shoplistbox.h"
@@ -43,7 +42,7 @@ BuyDialog::BuyDialog(Network *network):
Window(_("Buy")), mNetwork(network),
mMoney(0), mAmountItems(0), mMaxItems(0)
{
- setWindowName("Buy");
+ setWindowName(_("Buy"));
setResizable(true);
setMinWidth(260);
setMinHeight(230);
diff --git a/src/gui/buy.h b/src/gui/buy.h
index 37a39890..423918ce 100644
--- a/src/gui/buy.h
+++ b/src/gui/buy.h
@@ -111,9 +111,9 @@ class BuyDialog : public Window, public gcn::ActionListener,
ShopItems *mShopItems;
- int mMoney;
- int mAmountItems;
- int mMaxItems;
+ Uint32 mMoney;
+ Uint32 mAmountItems;
+ Uint32 mMaxItems;
};
#endif
diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp
index cdab0855..d060db85 100644
--- a/src/gui/buysell.cpp
+++ b/src/gui/buysell.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "buysell.h"
-
#include "button.h"
+#include "buysell.h"
#include "../npc.h"
diff --git a/src/gui/buysell.h b/src/gui/buysell.h
index e3cdc52a..60a6398d 100644
--- a/src/gui/buysell.h
+++ b/src/gui/buysell.h
@@ -26,6 +26,8 @@
#include "window.h"
+#include "../guichanfwd.h"
+
/**
* A dialog to choose between buying or selling at a shop.
*
diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
index df57f969..e556dfa0 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -19,13 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "char_select.h"
-
#include <string>
+#include <guichan/font.hpp>
#include <guichan/widgets/label.hpp>
#include "button.h"
+#include "char_select.h"
#include "confirm_dialog.h"
#include "ok_dialog.h"
#include "playerbox.h"
@@ -69,7 +69,8 @@ CharDeleteConfirm::CharDeleteConfirm(CharSelectDialog *m):
void CharDeleteConfirm::action(const gcn::ActionEvent &event)
{
//ConfirmDialog::action(event);
- if (event.getId() == "yes") {
+ if (event.getId() == "yes")
+ {
master->attemptCharDelete();
}
ConfirmDialog::action(event);
@@ -81,38 +82,42 @@ CharSelectDialog::CharSelectDialog(Network *network,
Window(_("Select Character")), mNetwork(network),
mCharInfo(charInfo), mGender(gender), mCharSelected(false)
{
- mSelectButton = new Button(_("Ok"), "ok", this);
- mCancelButton = new Button(_("Cancel"), "cancel", this);
- mNewCharButton = new Button(_("New"), "new", this);
- mDelCharButton = new Button(_("Delete"), "delete", this);
- mPreviousButton = new Button(_("Previous"), "previous", this);
- mNextButton = new Button(_("Next"), "next", this);
+ // Control that shows the Player
+ mPlayerBox = new PlayerBox;
+ mPlayerBox->setWidth(74);
mNameLabel = new gcn::Label(strprintf(_("Name: %s"), ""));
mLevelLabel = new gcn::Label(strprintf(_("Level: %d"), 0));
mJobLevelLabel = new gcn::Label(strprintf(_("Job Level: %d"), 0));
mMoneyLabel = new gcn::Label(strprintf(_("Money: %d"), 0));
- // Control that shows the Player
- mPlayerBox = new PlayerBox;
- mPlayerBox->setWidth(74);
+ const std::string tempString = getFont()->getWidth(_("New")) <
+ getFont()->getWidth(_("Delete")) ?
+ _("Delete") : _("New");
+
+ mPreviousButton = new Button(_("Previous"), "previous", this);
+ mNextButton = new Button(_("Next"), "next", this);
+ mNewDelCharButton = new Button(tempString, "newdel", this);
+ mSelectButton = new Button(_("Ok"), "ok", this);
+ mCancelButton = new Button(_("Cancel"), "cancel", this);
ContainerPlacer place;
place = getPlacer(0, 0);
+
place(0, 0, mPlayerBox, 1, 6).setPadding(3);
- place(1, 0, mNameLabel, 3);
- place(1, 1, mLevelLabel, 3);
- place(1, 2, mJobLevelLabel, 3);
- place(1, 3, mMoneyLabel, 3);
- place(1, 4, mPreviousButton);
- place(2, 4, mNextButton);
- place(1, 5, mNewCharButton);
- place(2, 5, mDelCharButton);
- place.getCell().matchColWidth(1, 2);
+ place(1, 0, mNewDelCharButton);
+ place(1, 1, mNameLabel, 5);
+ place(1, 2, mLevelLabel, 5);
+ place(1, 3, mJobLevelLabel, 5);
+ place(1, 4, mMoneyLabel, 5);
+ place.getCell().matchColWidth(1, 4);
place = getPlacer(0, 2);
- place(0, 0, mSelectButton);
- place(1, 0, mCancelButton);
- reflowLayout(265, 0);
+ place(0, 0, mPreviousButton);
+ place(1, 0, mNextButton);
+ place(4, 0, mCancelButton);
+ place(5, 0, mSelectButton);
+
+ reflowLayout(250, 0);
setLocationRelativeTo(getParent());
setVisible(true);
@@ -125,8 +130,7 @@ void CharSelectDialog::action(const gcn::ActionEvent &event)
if (event.getId() == "ok" && n_character > 0)
{
// Start game
- mNewCharButton->setEnabled(false);
- mDelCharButton->setEnabled(false);
+ mNewDelCharButton->setEnabled(false);
mSelectButton->setEnabled(false);
mPreviousButton->setEnabled(false);
mNextButton->setEnabled(false);
@@ -137,20 +141,21 @@ void CharSelectDialog::action(const gcn::ActionEvent &event)
{
state = EXIT_STATE;
}
- else if (event.getId() == "new" && n_character <= MAX_SLOT)
- {
- // Start new character dialog
- CharCreateDialog *charCreateDialog =
- new CharCreateDialog(this, mCharInfo->getPos(), mNetwork, mGender);
- charServerHandler.setCharCreateDialog(charCreateDialog);
- }
- else if (event.getId() == "delete")
+ else if (event.getId() == "newdel")
{
- // Delete character
- if (mCharInfo->getEntry())
+ // Check for a character
+ if (mCharInfo->getEntry() && n_character <= MAX_SLOT )
{
new CharDeleteConfirm(this);
}
+ else
+ {
+ // Start new character dialog
+ CharCreateDialog *charCreateDialog =
+ new CharCreateDialog(this, mCharInfo->getPos(),
+ mNetwork, mGender);
+ charServerHandler.setCharCreateDialog(charCreateDialog);
+ }
}
else if (event.getId() == "previous")
{
@@ -174,18 +179,17 @@ void CharSelectDialog::updatePlayerInfo()
mMoneyLabel->setCaption(strprintf(_("Gold: %d"), pi->mGp));
if (!mCharSelected)
{
- mNewCharButton->setEnabled(false);
- mDelCharButton->setEnabled(true);
+ mNewDelCharButton->setCaption(_("Delete"));
mSelectButton->setEnabled(true);
}
}
- else {
+ else
+ {
mNameLabel->setCaption(strprintf(_("Name: %s"), ""));
mLevelLabel->setCaption(strprintf(_("Level: %d"), 0));
mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), 0));
mMoneyLabel->setCaption(strprintf(_("Money: %d"), 0));
- mNewCharButton->setEnabled(true);
- mDelCharButton->setEnabled(false);
+ mNewDelCharButton->setCaption(_("New"));
mSelectButton->setEnabled(false);
}
@@ -224,7 +228,8 @@ bool CharSelectDialog::selectByName(const std::string &name)
unsigned int oldPos = mCharInfo->getPos();
mCharInfo->select(0);
- do {
+ do
+ {
LocalPlayer *player = mCharInfo->getEntry();
if (player && player->getName() == name)
@@ -244,7 +249,10 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
{
mPlayer = new Player(0, 0, NULL);
mPlayer->setGender(gender);
- mPlayer->setHairStyle(rand() % Being::getHairStylesNr(), rand() % Being::getHairColorsNr());
+
+ int numberOfHairColors = ColorDB::size();
+
+ mPlayer->setHairStyle(rand() % mPlayer->getNumOfHairstyles(), rand() % numberOfHairColors);
mNameField = new TextField("");
mNameLabel = new gcn::Label(_("Name:"));
@@ -258,41 +266,29 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network,
mCancelButton = new Button(_("Cancel"), "cancel", this);
mPlayerBox = new PlayerBox(mPlayer);
+ mPlayerBox->setWidth(74);
+
mNameField->setActionEventId("create");
+ mNameField->addActionListener(this);
- int w = 200;
- int h = 150;
- setContentSize(w, h);
- mPlayerBox->setDimension(gcn::Rectangle(80, 30, 110, 85));
- mNameLabel->setPosition(5, 5);
- mNameField->setDimension(
- gcn::Rectangle(45, 5, w - 45 - 7, mNameField->getHeight()));
- mPrevHairColorButton->setPosition(90, 35);
- mNextHairColorButton->setPosition(165, 35);
- mHairColorLabel->setPosition(5, 40);
- mPrevHairStyleButton->setPosition(90, 64);
- mNextHairStyleButton->setPosition(165, 64);
- mHairStyleLabel->setPosition(5, 70);
- mCancelButton->setPosition(
- w - 5 - mCancelButton->getWidth(),
- h - 5 - mCancelButton->getHeight());
- mCreateButton->setPosition(
- mCancelButton->getX() - 5 - mCreateButton->getWidth(),
- h - 5 - mCancelButton->getHeight());
+ ContainerPlacer place;
+ place = getPlacer(0, 0);
- mNameField->addActionListener(this);
+ place(0, 0, mNameLabel, 1);
+ place(1, 0, mNameField, 6);
+ place(0, 1, mHairStyleLabel, 1);
+ place(1, 1, mPrevHairStyleButton);
+ place(2, 1, mPlayerBox, 1, 8).setPadding(3);
+ place(3, 1, mNextHairStyleButton);
+ place(0, 2, mHairColorLabel, 1);
+ place(1, 2, mPrevHairColorButton);
+ place(3, 2, mNextHairColorButton);
+ place.getCell().matchColWidth(0, 2);
+ place = getPlacer(0, 2);
+ place(4, 0, mCancelButton);
+ place(5, 0, mCreateButton);
- add(mPlayerBox);
- add(mNameField);
- add(mNameLabel);
- add(mNextHairColorButton);
- add(mPrevHairColorButton);
- add(mHairColorLabel);
- add(mNextHairStyleButton);
- add(mPrevHairStyleButton);
- add(mHairStyleLabel);
- add(mCreateButton);
- add(mCancelButton);
+ reflowLayout(225, 0);
setLocationRelativeTo(getParent());
setVisible(true);
@@ -307,53 +303,54 @@ CharCreateDialog::~CharCreateDialog()
charServerHandler.setCharCreateDialog(0);
}
-void
-CharCreateDialog::action(const gcn::ActionEvent &event)
+void CharCreateDialog::action(const gcn::ActionEvent &event)
{
- if (event.getId() == "create") {
- if (getName().length() >= 4) {
+ int numberOfColors = ColorDB::size();
+ if (event.getId() == "create")
+ {
+ if (getName().length() >= 4)
+ {
// Attempt to create the character
mCreateButton->setEnabled(false);
attemptCharCreate();
}
- else {
+ else
+ {
new OkDialog("Error",
"Your name needs to be at least 4 characters.", this);
}
}
- else if (event.getId() == "cancel") {
+ else if (event.getId() == "cancel")
scheduleDelete();
- }
- else if (event.getId() == "nextcolor") {
- mPlayer->setHairStyle(-1, mPlayer->getHairColor() + 1);
- }
- else if (event.getId() == "prevcolor") {
- mPlayer->setHairStyle(-1, mPlayer->getHairColor() + Being::getHairColorsNr() - 1);
- }
- else if (event.getId() == "nextstyle") {
- mPlayer->setHairStyle(mPlayer->getHairStyle() + 1, -1);
- }
- else if (event.getId() == "prevstyle") {
- mPlayer->setHairStyle(mPlayer->getHairStyle() + Being::getHairStylesNr() - 1, -1);
- }
+ else if (event.getId() == "nextcolor")
+ mPlayer->setHairStyle(mPlayer->getHairStyle(),
+ (mPlayer->getHairColor() + 1) % numberOfColors);
+ else if (event.getId() == "prevcolor")
+ mPlayer->setHairStyle(mPlayer->getHairStyle(),
+ (mPlayer->getHairColor() + numberOfColors - 1) %
+ numberOfColors);
+ else if (event.getId() == "nextstyle")
+ mPlayer->setHairStyle(mPlayer->getHairStyle() + 1,
+ mPlayer->getHairColor());
+ else if (event.getId() == "prevstyle")
+ mPlayer->setHairStyle(mPlayer->getHairStyle() +
+ mPlayer->getNumOfHairstyles() - 1,
+ mPlayer->getHairColor());
}
-std::string
-CharCreateDialog::getName()
+std::string CharCreateDialog::getName()
{
std::string name = mNameField->getText();
trim(name);
return name;
}
-void
-CharCreateDialog::unlock()
+void CharCreateDialog::unlock()
{
mCreateButton->setEnabled(true);
}
-void
-CharCreateDialog::attemptCharCreate()
+void CharCreateDialog::attemptCharCreate()
{
// Send character infos
MessageOut outMsg(mNetwork);
diff --git a/src/gui/char_select.h b/src/gui/char_select.h
index 74745788..5d4ecfa8 100644
--- a/src/gui/char_select.h
+++ b/src/gui/char_select.h
@@ -22,17 +22,17 @@
#ifndef _CHAR_SELECT_H
#define _CHAR_SELECT_H
+#include <guichan/actionlistener.hpp>
+
#include "window.h"
#include "../guichanfwd.h"
#include "../lockedarray.h"
#include "../being.h"
-#include <guichan/actionlistener.hpp>
-
-class Player;
class LocalPlayer;
class Network;
+class Player;
class PlayerBox;
/**
@@ -65,8 +65,7 @@ class CharSelectDialog : public Window, public gcn::ActionListener
gcn::Button *mSelectButton;
gcn::Button *mCancelButton;
- gcn::Button *mNewCharButton;
- gcn::Button *mDelCharButton;
+ gcn::Button *mNewDelCharButton;
gcn::Button *mPreviousButton;
gcn::Button *mNextButton;
diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp
index 7be2441d..2e823b60 100644
--- a/src/gui/char_server.cpp
+++ b/src/gui/char_server.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "char_server.h"
-
#include "button.h"
+#include "char_server.h"
#include "listbox.h"
#include "scrollarea.h"
@@ -99,8 +98,7 @@ ServerSelectDialog::~ServerSelectDialog()
delete mServerListModel;
}
-void
-ServerSelectDialog::action(const gcn::ActionEvent &event)
+void ServerSelectDialog::action(const gcn::ActionEvent &event)
{
if (event.getId() == "ok") {
mOkButton->setEnabled(false);
@@ -108,7 +106,6 @@ ServerSelectDialog::action(const gcn::ActionEvent &event)
mLoginData->hostname = iptostring(si->address);
mLoginData->port = si->port;
mLoginData->updateHost = si->updateHost;
-
state = mNextState;
}
else if (event.getId() == "cancel") {
@@ -116,14 +113,12 @@ ServerSelectDialog::action(const gcn::ActionEvent &event)
}
}
-int
-ServerListModel::getNumberOfElements()
+int ServerListModel::getNumberOfElements()
{
return n_server;
}
-std::string
-ServerListModel::getElementAt(int i)
+std::string ServerListModel::getElementAt(int i)
{
const SERVER_INFO *si = server_info[i];
return si->name + " (" + toString(si->online_users) + ")";
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
index 87d843a0..c9c3e9bc 100644
--- a/src/gui/chat.cpp
+++ b/src/gui/chat.cpp
@@ -20,56 +20,66 @@
*/
#include <algorithm>
-#include <sstream>
+#include <fstream>
#include <guichan/focushandler.hpp>
-#include "chat.h"
-
#include "browserbox.h"
+#include "chat.h"
#include "chatinput.h"
+#include "itemlinkhandler.h"
#include "scrollarea.h"
#include "sdlinput.h"
#include "windowcontainer.h"
#include "widgets/layout.h"
+#include "../beingmanager.h"
#include "../configuration.h"
+#include "../extensions.h"
#include "../game.h"
#include "../localplayer.h"
+#include "../party.h"
+#include "../recorder.h"
#include "../net/messageout.h"
#include "../net/protocol.h"
+#include "../resources/iteminfo.h"
+#include "../resources/itemdb.h"
+
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
+#include "../utils/tostring.h"
#include "../utils/trim.h"
-ChatWindow::ChatWindow(Network *network):
- Window(""),
- mNetwork(network),
- mTmpVisible(false)
+ChatWindow::ChatWindow(Network * network):
+Window(""), mNetwork(network), mTmpVisible(false)
{
- setWindowName("Chat");
+ setWindowName(_("Chat"));
setResizable(true);
setDefaultSize(0, windowContainer->getHeight() - 123, 600, 123);
setMinWidth(150);
setMinHeight(90);
+ mItemLinkHandler = new ItemLinkHandler();
+
mChatInput = new ChatInput;
mChatInput->setActionEventId("chatinput");
mChatInput->addActionListener(this);
mTextOutput = new BrowserBox(BrowserBox::AUTO_WRAP);
mTextOutput->setOpaque(false);
- mTextOutput->disableLinksAndUserColors();
mTextOutput->setMaxRow((int) config.getValue("ChatLogLength", 0));
+ mTextOutput->setLinkHandler(mItemLinkHandler);
+
mScrollArea = new ScrollArea(mTextOutput);
- mScrollArea->setPosition(
- mScrollArea->getFrameSize(), mScrollArea->getFrameSize());
- mScrollArea->setScrollPolicy(
- gcn::ScrollArea::SHOW_NEVER, gcn::ScrollArea::SHOW_ALWAYS);
+ mScrollArea->setPosition(mScrollArea->getFrameSize(),
+ mScrollArea->getFrameSize());
+ mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER,
+ gcn::ScrollArea::SHOW_ALWAYS);
+ mScrollArea->setScrollAmount(0, 1);
mScrollArea->setOpaque(false);
place(0, 0, mScrollArea, 5, 5).setPadding(0);
@@ -84,23 +94,48 @@ ChatWindow::ChatWindow(Network *network):
// Add key listener to chat input to be able to respond to up/down
mChatInput->addKeyListener(this);
mCurHist = mHistory.end();
+
+ // Read the party prefix
+ std::string partyPrefix = config.getValue("PartyPrefix", "$");
+ mPartyPrefix = (partyPrefix == "" ? '$' : partyPrefix.at(0));
+ mReturnToggles = config.getValue("ReturnToggles", "0") == "1";
+ mRecorder = new Recorder(this);
+ mParty = new Party(this, mNetwork);
+
+ // If the player had @assert on in the last session, ask the server to
+ // run the @assert command for the player again. Convenience for GMs.
+ if (config.getValue(player_node->getName() + "GMassert", 0))
+ chatSend(player_node->getName(), "@assert");
}
-void ChatWindow::chatLog(std::string line, int own)
+ChatWindow::~ChatWindow()
+{
+ char partyPrefix[2] = ".";
+ *partyPrefix = mPartyPrefix;
+ config.setValue("PartyPrefix", partyPrefix);
+ config.setValue("ReturnToggles", mReturnToggles ? "1" : "0");
+ delete mRecorder;
+}
+
+void ChatWindow::chatLog(std::string line, int own, bool ignoreRecord)
{
// Trim whitespace
trim(line);
CHATLOG tmp;
- tmp.own = own;
+ tmp.own = own;
tmp.nick = "";
tmp.text = line;
+
std::string::size_type pos = line.find(" : ");
- if (pos != std::string::npos) {
+ if (pos != std::string::npos)
+ {
tmp.nick = line.substr(0, pos);
tmp.text = line.substr(pos + 3);
- } else {
+ }
+ else
+ {
// Fix the owner of welcome message.
if (line.substr(0, 7) == "Welcome")
{
@@ -108,77 +143,99 @@ void ChatWindow::chatLog(std::string line, int own)
}
}
- std::string lineColor = "##0"; // Equiv. to BrowserBox::BLACK
- switch (own) {
+ std::string lineColor = "##C";
+ switch (own)
+ {
case BY_GM:
- if (tmp.nick.empty()) {
- tmp.nick = _("Global announcement:");
+ if (tmp.nick.empty())
+ {
+ tmp.nick = std::string(_("Global announcement:"));
tmp.nick += " ";
- } else {
+ lineColor = "##G";
+ }
+ else
+ {
tmp.nick = strprintf(_("Global announcement from %s:"),
tmp.nick.c_str());
tmp.nick += " ";
+ lineColor = "##1"; // Equiv. to BrowserBox::RED
}
- lineColor = "##1"; // Equiv. to BrowserBox::RED
break;
case BY_PLAYER:
tmp.nick += CAT_NORMAL;
- lineColor = "##2"; // Equiv. to BrowserBox::GREEN
+ lineColor = "##Y";
break;
case BY_OTHER:
tmp.nick += CAT_NORMAL;
- lineColor = "##0"; // Equiv. to BrowserBox::BLACK
+ lineColor = "##C";
break;
case BY_SERVER:
tmp.nick = _("Server:");
tmp.nick += " ";
tmp.text = line;
- lineColor = "##7"; // Equiv. to BrowserBox::PINK
+ lineColor = "##S";
+ break;
+ case BY_PARTY:
+ tmp.nick += CAT_NORMAL;
+ lineColor = "##P";
break;
case ACT_WHISPER:
tmp.nick = strprintf(_("%s whispers:"), tmp.nick.c_str());
tmp.nick += " ";
- lineColor = "##3"; // Equiv. to BrowserBox::BLUE
+ lineColor = "##W";
break;
case ACT_IS:
tmp.nick += CAT_IS;
- lineColor = "##5"; // Equiv. to BrowserBox::YELLOW
+ lineColor = "##I";
break;
case BY_LOGGER:
tmp.nick = "";
tmp.text = line;
- lineColor = "##8"; // Equiv. to BrowserBox::GREY
+ lineColor = "##L";
break;
}
+ if (tmp.nick == ": ")
+ {
+ tmp.nick = "";
+ lineColor = "##S";
+ }
+
+ if (tmp.nick == "" && tmp.text.substr(0, 17) == "Visible GM status")
+ {
+ player_node->setGM();
+ }
+
// Get the current system time
time_t t;
time(&t);
// Format the time string properly
std::stringstream timeStr;
- timeStr << "["
- << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
- << (int)(((t / 60) / 60) % 24)
- << ":"
- << (((t / 60) % 60 < 10) ? "0" : "")
- << (int)((t / 60) % 60)
- << "] ";
+ timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
+ << (int) (((t / 60) / 60) % 24)
+ << ":" << (((t / 60) % 60 < 10) ? "0" : "")
+ << (int) ((t / 60) % 60)
+ << "] ";
line = lineColor + timeStr.str() + tmp.nick + tmp.text;
// We look if the Vertical Scroll Bar is set at the max before
// adding a row, otherwise the max will always be a row higher
// at comparison.
- if (mScrollArea->getVerticalScrollAmount() == mScrollArea->getVerticalMaxScroll())
+ if (mScrollArea->getVerticalScrollAmount() ==
+ mScrollArea->getVerticalMaxScroll())
{
mTextOutput->addRow(line);
- mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll());
+ mScrollArea->setVerticalScrollAmount(mScrollArea->
+ getVerticalMaxScroll());
}
else
{
mTextOutput->addRow(line);
}
+
+ mRecorder->record(line.substr(3));
}
void ChatWindow::chatLog(CHATSKILL act)
@@ -192,12 +249,13 @@ void ChatWindow::action(const gcn::ActionEvent &event)
{
std::string message = mChatInput->getText();
- if (!message.empty()) {
+ if (!message.empty())
+ {
// If message different from previous, put it in the history
- if (mHistory.empty() || message != mHistory.back()) {
+ if (mHistory.empty() || message != mHistory.back())
+ {
mHistory.push_back(message);
}
-
// Reset history iterator
mCurHist = mHistory.end();
@@ -208,13 +266,15 @@ void ChatWindow::action(const gcn::ActionEvent &event)
mChatInput->setText("");
}
- // Remove focus and hide input
- mFocusHandler->focusNone();
+ if (message.empty() || !mReturnToggles)
+ {
+ // Remove focus and hide input
+ mFocusHandler->focusNone();
- // If the chatWindow is shown up because you want to send a message
- // It should hide now
- if (mTmpVisible) {
- setVisible(false);
+ // If the chatWindow is shown up because you want to send a message
+ // It should hide now
+ if (mTmpVisible)
+ setVisible(false);
}
}
}
@@ -244,16 +304,15 @@ bool ChatWindow::isInputFocused()
return mChatInput->isFocused();
}
-void ChatWindow::whisper(const std::string &nick, std::string msg,
- int prefixlen)
+void ChatWindow::whisper(const std::string &nick, std::string msg)
{
std::string recvnick = "";
- msg.erase(0, prefixlen + 1);
if (msg.substr(0, 1) == "\"")
{
const std::string::size_type pos = msg.find('"', 1);
- if (pos != std::string::npos) {
+ if (pos != std::string::npos)
+ {
recvnick = msg.substr(1, pos - 1);
msg.erase(0, pos + 2);
}
@@ -261,7 +320,8 @@ void ChatWindow::whisper(const std::string &nick, std::string msg,
else
{
const std::string::size_type pos = msg.find(" ");
- if (pos != std::string::npos) {
+ if (pos != std::string::npos)
+ {
recvnick = msg.substr(0, pos);
msg.erase(0, pos + 1);
}
@@ -274,8 +334,8 @@ void ChatWindow::whisper(const std::string &nick, std::string msg,
outMsg.writeString(msg, msg.length());
chatLog(strprintf(_("Whispering to %s: %s"),
- recvnick.c_str(), msg.c_str()),
- BY_PLAYER);
+ recvnick.c_str(), msg.c_str()),
+ BY_PLAYER);
}
void ChatWindow::chatSend(const std::string &nick, std::string msg)
@@ -284,8 +344,67 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg)
* require server handling by proper packet. Probably
* those if elses should be replaced by protocol calls */
+ // Send party message
+ if (msg.at(0) == mPartyPrefix)
+ {
+ msg.erase(0, 1);
+ std::size_t length = msg.length() + 1;
+
+ if (length == 0)
+ {
+ chatLog(_("Trying to send a blank party message."), BY_SERVER);
+ return;
+ }
+ MessageOut outMsg(mNetwork);
+
+ outMsg.writeInt16(CMSG_PARTY_MESSAGE);
+ outMsg.writeInt16(length + 4);
+ outMsg.writeString(msg, length);
+ return;
+ }
+
+ // check for item link
+ std::string::size_type start = msg.find('[');
+ while (start != std::string::npos && msg[start+1] != '@')
+ {
+ std::string::size_type end = msg.find(']', start);
+ if (end != std::string::npos)
+ {
+ // Catch multiple embeds and ignore them so it doesn't crash the client.
+ while ((msg.find('[', start + 1) != std::string::npos) &&
+ (msg.find('[', start + 1) < end))
+ {
+ start = msg.find('[', start + 1);
+ }
+
+ std::string temp = msg.substr(start+1, end - start - 1);
+
+ while (temp[0] == ' ')
+ {
+ temp = temp.substr(1, temp.size());
+ }
+ while (temp[temp.size()] == ' ')
+ {
+ temp = temp.substr(0, temp.size() - 1);
+ }
+
+ for (unsigned int i = 0; i < temp.size(); i++)
+ {
+ temp[i] = (char) tolower(temp[i]);
+ }
+
+ const ItemInfo itemInfo = ItemDB::get(temp);
+ msg.insert(end, "@@");
+ msg.insert(start+1, "|");
+ msg.insert(start+1, toString(itemInfo.getId()));
+ msg.insert(start+1, "@@");
+ }
+ start = msg.find('[', start + 1);
+ }
+
// Prepare ordinary message
- if (msg.substr(0, 1) != "/") {
+ if (msg.substr(0, 1) != "/")
+ {
msg = nick + " : " + msg;
MessageOut outMsg(mNetwork);
@@ -293,21 +412,39 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg)
// Added + 1 in order to let eAthena parse admin commands correctly
outMsg.writeInt16(msg.length() + 4 + 1);
outMsg.writeString(msg, msg.length() + 1);
+ return;
+ }
+
+ msg.erase(0, 1);
+ trim(msg);
+
+ std::size_t space = msg.find(" ");
+ std::string command = msg.substr(0, space);
+
+ if (space == std::string::npos)
+ {
+ msg = "";
}
- else if (msg.substr(0, IS_ANNOUNCE_LENGTH) == IS_ANNOUNCE)
+ else
+ {
+ msg = msg.substr(space);
+ trim(msg);
+ }
+
+ if (command == "announce")
{
- msg.erase(0, IS_ANNOUNCE_LENGTH);
MessageOut outMsg(mNetwork);
outMsg.writeInt16(0x0099);
outMsg.writeInt16(msg.length() + 4);
outMsg.writeString(msg, msg.length());
}
- else if (msg.substr(0, IS_HELP_LENGTH) == IS_HELP)
+ else if (command == "help")
{
- msg.erase(0, IS_HELP_LENGTH + 1);
+ msg.erase(0, 6);
trim(msg);
std::size_t space = msg.find(" ");
std::string msg1;
+
if (space == std::string::npos)
{
msg1 = "";
@@ -317,33 +454,160 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg)
msg1 = msg.substr(space + 1, msg.length());
msg = msg.substr(0, space);
}
+
if (msg != "" && msg.at(0) == '/')
{
msg.erase(0, 1);
}
+
trim(msg1);
help(msg, msg1);
}
- else if (msg.substr(0, IS_WHERE_LENGTH) == IS_WHERE)
+ else if (command == "where")
{
// Display the current map, X, and Y
std::ostringstream where;
where << map_path << " " << player_node->mX << "," << player_node->mY;
chatLog(where.str(), BY_SERVER);
}
- else if (msg.substr(0, IS_WHO_LENGTH) == IS_WHO)
+ else if (command == "who")
{
MessageOut outMsg(mNetwork);
outMsg.writeInt16(0x00c1);
}
- else if (msg.substr(0, IS_CLEAR_LENGTH) == IS_CLEAR)
- {
+ else if (command == "clear")
mTextOutput->clearRows();
+ else if (command == "whisper" || command == "msg" || command == "w")
+ whisper(nick, msg);
+ else if (command == "record")
+ mRecorder->respond(msg);
+ else if (command == "toggle")
+ {
+ if (msg == "")
+ {
+ chatLog(mReturnToggles ? _("Return toggles chat.")
+ : _("Message closes chat."), BY_SERVER);
+ return;
+ }
+
+ msg = msg.substr(0, 1);
+
+ if (msg == "1" ||
+ msg == "y" || msg == "Y" ||
+ msg == "t" || msg == "T")
+ {
+ chatLog(_("Return now toggles chat."), BY_SERVER);
+ mReturnToggles = true;
+ return;
+ }
+ else if (msg == "0" ||
+ msg == "n" || msg == "N" ||
+ msg == "f" || msg == "F")
+ {
+ chatLog(_("Message now closes chat."), BY_SERVER);
+ mReturnToggles = false;
+ return;
+ }
+ else
+ chatLog(_("Options to /toggle are \"yes\", \"no\", \"true\", "
+ "\"false\", \"1\", \"0\"."), BY_SERVER);
+ }
+ else if (command == "party")
+ {
+ if (msg == "")
+ {
+ chatLog(_("Unknown party command... Type \"/help\" party for more "
+ "information."), BY_SERVER);
+ return;
+ }
+
+ const std::string::size_type space = msg.find(" ");
+ std::string rest = (space == std::string::npos ? ""
+ : msg.substr(space + 1, msg.length()));
+
+ if (rest != "")
+ {
+ msg = msg.substr(0, space);
+ trim(msg);
+ }
+
+ party(msg, rest);
+ return;
+ }
+ else if (command == "cast")
+ {
+ /*
+ * This will eventually be replaced by a GUI, so
+ * we don't need to get too sophisticated
+ */
+ if (extensions.aethyra_spells)
+ {
+ MessageOut outMsg(mNetwork);
+ if (msg == "heal")
+ {
+ outMsg.writeInt16(0x03f3);
+ outMsg.writeInt16(0x01);
+ outMsg.writeInt32(0);
+ outMsg.writeInt8(0);
+ outMsg.writeInt8(0);
+ outMsg.writeString("", 24);
+ }
+ else if (msg == "gather")
+ {
+ outMsg.writeInt16(0x03f3);
+ outMsg.writeInt16(0x02);
+ outMsg.writeInt32(0);
+ outMsg.writeInt8(0);
+ outMsg.writeInt8(0);
+ outMsg.writeString("", 24);
+ }
+ else
+ chatLog(_("No such spell!"), BY_SERVER);
+ }
+ else
+ chatLog(_("The current server doesn't support spells"), BY_SERVER);
+ }
+ else if (command == "present")
+ {
+ Beings & beings = beingManager->getAll();
+ std::string response = "";
+
+ for (BeingIterator bi = beings.begin(), be = beings.end();
+ bi != be; ++bi)
+ {
+ if ((*bi)->getType() == Being::PLAYER)
+ {
+ if (response != "")
+ {
+ response += ", ";
+ }
+ response += (*bi)->getName();
+ }
+ }
+
+ if (mRecorder->isRecording())
+ {
+ // Get the current system time
+ time_t t;
+ time(&t);
+
+ // Format the time string properly
+ std::stringstream timeStr;
+ timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
+ << (int) (((t / 60) / 60) % 24)
+ << ":" << (((t / 60) % 60 < 10) ? "0" : "")
+ << (int) ((t / 60) % 60)
+ << "] ";
+
+
+ mRecorder->record(timeStr.str() + _("Present: ") + response + ".");
+ chatLog(_("Attendance written to record log."), BY_SERVER, true);
+ }
+ else
+ {
+ chatLog(_("Present: ") + response, BY_SERVER);
+ }
}
- else if (msg.substr(0, IS_WHISPER_LENGTH) == IS_WHISPER)
- whisper(nick, msg, IS_WHISPER_LENGTH);
- else if (msg.substr(0, IS_SHORT_WHISPER_LENGTH) == IS_SHORT_WHISPER)
- whisper(nick, msg, IS_SHORT_WHISPER_LENGTH);
else
{
chatLog(_("Unknown command"), BY_SERVER);
@@ -353,8 +617,10 @@ void ChatWindow::chatSend(const std::string &nick, std::string msg)
std::string ChatWindow::const_msg(CHATSKILL act)
{
std::string msg;
- if (act.success == SKILL_FAILED && act.skill == SKILL_BASIC) {
- switch (act.bskill) {
+ if (act.success == SKILL_FAILED && act.skill == SKILL_BASIC)
+ {
+ switch (act.bskill)
+ {
case BSKILL_TRADE:
msg = _("Trade failed!");
break;
@@ -377,7 +643,8 @@ std::string ChatWindow::const_msg(CHATSKILL act)
msg += " ";
- switch (act.reason) {
+ switch (act.reason)
+ {
case RFAIL_SKILLDEP:
msg += _("You have not yet reached a high enough lvl!");
break;
@@ -412,8 +679,11 @@ std::string ChatWindow::const_msg(CHATSKILL act)
msg += _("Huh? What's that?");
break;
}
- } else {
- switch (act.skill) {
+ }
+ else
+ {
+ switch (act.skill)
+ {
case SKILL_WARP :
msg = _("Warp failed...");
break;
@@ -448,11 +718,14 @@ void ChatWindow::keyPressed(gcn::KeyEvent &event)
{
// Move forward through the history
HistoryIterator prevHist = mCurHist++;
- if (mCurHist != mHistory.end()) {
+
+ if (mCurHist != mHistory.end())
+ {
mChatInput->setText(*mCurHist);
mChatInput->setCaretPosition(mChatInput->getText().length());
}
- else {
+ else
+ {
mCurHist = prevHist;
}
}
@@ -468,10 +741,18 @@ void ChatWindow::keyPressed(gcn::KeyEvent &event)
void ChatWindow::setInputText(std::string input_str)
{
- mChatInput->setText(input_str + " ");
+ mChatInput->setText(mChatInput->getText() + input_str + " ");
requestChatFocus();
}
+void ChatWindow::addItemText(int itemId, const std::string &item)
+{
+ std::ostringstream text;
+ text << "[@@" << itemId << "|" << item << "@@] ";
+ mChatInput->setText(mChatInput->getText() + text.str());
+ requestChatFocus();
+}
+
void ChatWindow::setVisible(bool isVisible)
{
Window::setVisible(isVisible);
@@ -484,70 +765,132 @@ void ChatWindow::setVisible(bool isVisible)
mTmpVisible = false;
}
-void ChatWindow::help(const std::string &msg1, const std::string &msg2)
+void ChatWindow::party(const std::string & command, const std::string & rest)
+{
+ if (command == "prefix")
+ {
+ if (rest == "")
+ {
+ char temp[2] = ".";
+ *temp = mPartyPrefix;
+ chatLog(_("The current party prefix is ") + std::string(temp),
+ BY_SERVER);
+ }
+ else if (rest.length() != 1)
+ {
+ chatLog(_("Party prefix must be one character long."), BY_SERVER);
+ }
+ else
+ {
+ if (rest == "/")
+ {
+ chatLog(_("Cannot use a '/' as the prefix."), BY_SERVER);
+ }
+ else
+ {
+ mPartyPrefix = rest.at(0);
+ chatLog(_("Changing prefix to ") + rest, BY_SERVER);
+ }
+ }
+ }
+ else
+ mParty->respond(command, rest);
+}
+
+void ChatWindow::help(const std::string & msg1, const std::string & msg2)
{
chatLog(_("-- Help --"), BY_SERVER);
- if (msg1 == "")
+ if (msg1 == "")
{
chatLog(_("/announce: Global announcement (GM only)"), BY_SERVER);
chatLog(_("/clear: Clears this window"), BY_SERVER);
chatLog(_("/help: Display this help"), BY_SERVER);
+ mParty->help();
+ chatLog(_("/msg <nick> <message>: Alternate form for /whisper"), BY_SERVER);
+ chatLog(_("/present: Get list of players present"), BY_SERVER);
+ mRecorder->help();
+ chatLog(_("/toggle: Determine whether <return> toggles the chat log."),
+ BY_SERVER);
chatLog(_("/where: Display map name"), BY_SERVER);
+ chatLog(_("/w <nick> <message>: Short form for /whisper"), BY_SERVER);
chatLog(_("/whisper <nick> <message>: Sends a private <message>"
" to <nick>"), BY_SERVER);
- chatLog(_("/w <nick> <message>: Short form for /whisper"), BY_SERVER);
chatLog(_("/who: Display number of online users"), BY_SERVER);
chatLog(_("For more information, type /help <command>"), BY_SERVER);
- return;
}
- if (msg1 == "announce")
+ else if (msg1 == "announce")
{
chatLog(_("Command: /announce <msg>"), BY_SERVER);
chatLog(_("*** only available to a GM ***"), BY_SERVER);
chatLog(_("This command sends the message <msg> to "
"all players currently online."), BY_SERVER);
- return;
}
- if (msg1 == "clear")
+ else if (msg1 == "clear")
{
chatLog(_("Command: /clear"), BY_SERVER);
chatLog(_("This command clears the chat log of previous chat."),
BY_SERVER);
- return;
}
- if (msg1 == "help")
+ else if (msg1 == "help")
{
chatLog(_("Command: /help"), BY_SERVER);
chatLog(_("This command displays a list of all commands available."),
BY_SERVER);
chatLog(_("Command: /help <command>"), BY_SERVER);
chatLog(_("This command displays help on <command>."), BY_SERVER);
- return;
}
- if (msg1 == "where")
+ else if (msg1 == "party")
+ {
+ mParty->help(msg2);
+ }
+ else if (msg1 == "present")
+ {
+ chatLog(_("Command: /present"), BY_SERVER);
+ chatLog(_("This command gets a list of players within hearing and "
+ "sends it to either the record log if recording, or the chat "
+ "log otherwise."), BY_SERVER);
+ }
+ else if (msg1 == "record")
+ {
+ mRecorder->help(msg2);
+ }
+ else if (msg1 == "toggle")
+ {
+ chatLog(_("Command: /toggle <state>"), BY_SERVER);
+ chatLog(_("This command sets whether the return key should toggle the"
+ "chat log, or whether the chat log turns off automatically."),
+ BY_SERVER);
+ chatLog(_("<state> can be one of \"1\", \"yes\", \"true\" to "
+ "turn the toggle on, or \"0\", \"no\", \"false\" to turn the "
+ "toggle off."), BY_SERVER);
+ chatLog(_("Command: /toggle"), BY_SERVER);
+ chatLog(_("This command displays the return toggle status."), BY_SERVER);
+ }
+ else if (msg1 == "where")
{
chatLog(_("Command: /where"), BY_SERVER);
chatLog(_("This command displays the name of the current map."),
BY_SERVER);
- return;
}
- if (msg1 == "whisper" || msg1 == "w")
+ else if (msg1 == "whisper" || msg1 == "msg" || msg1 == "w")
{
+ chatLog(_("Command: /msg <nick> <msg>"), BY_SERVER);
chatLog(_("Command: /whisper <nick> <msg>"), BY_SERVER);
chatLog(_("Command: /w <nick> <msg>"), BY_SERVER);
chatLog(_("This command sends the message <msg> to <nick>."),
BY_SERVER);
chatLog(_("If the <nick> has spaces in it, enclose it in "
- "double quotes (\")."), BY_SERVER);
- return;
+ "double quotes (\")."), BY_SERVER);
}
- if (msg1 == "who")
+ else if (msg1 == "who")
{
chatLog(_("Command: /who"), BY_SERVER);
chatLog(_("This command displays the number of players currently "
- "online."), BY_SERVER);
- return;
+ "online."), BY_SERVER);
+ }
+ else
+ {
+ chatLog(_("Unknown command."), BY_SERVER);
+ chatLog(_("Type /help for a list of commands."), BY_SERVER);
}
- chatLog(_("Unknown command."), BY_SERVER);
- chatLog(_("Type /help for a list of commands."), BY_SERVER);
}
diff --git a/src/gui/chat.h b/src/gui/chat.h
index ad89c8dc..176fccb7 100644
--- a/src/gui/chat.h
+++ b/src/gui/chat.h
@@ -22,6 +22,7 @@
#ifndef CHAT_H
#define CHAT_H
+#include <fstream>
#include <list>
#include <string>
@@ -34,32 +35,21 @@
class BrowserBox;
class Network;
+class Recorder;
+class Party;
class ScrollArea;
+class ItemLinkHandler;
#define BY_GM 0 // those should be self-explanatory =)
#define BY_PLAYER 1
#define BY_OTHER 2
#define BY_SERVER 3
+#define BY_PARTY 4
-#define ACT_WHISPER 4 // getting whispered at
-#define ACT_IS 5 // equivalent to "/me" on IRC
-
-#define BY_LOGGER 6
-
-#define IS_ANNOUNCE "/announce "
-#define IS_ANNOUNCE_LENGTH 10
-#define IS_HELP "/help"
-#define IS_HELP_LENGTH 5
-#define IS_WHERE "/where"
-#define IS_WHERE_LENGTH 6
-#define IS_WHO "/who"
-#define IS_WHO_LENGTH 4
-#define IS_CLEAR "/clear"
-#define IS_CLEAR_LENGTH 6
-#define IS_WHISPER "/whisper"
-#define IS_WHISPER_LENGTH 8
-#define IS_SHORT_WHISPER "/w"
-#define IS_SHORT_WHISPER_LENGTH 2
+#define ACT_WHISPER 5 // getting whispered at
+#define ACT_IS 6 // equivalent to "/me" on IRC
+
+#define BY_LOGGER 7
/**
* gets in between usernick and message text depending on
@@ -127,14 +117,19 @@ class ChatWindow : public Window, public gcn::ActionListener,
ChatWindow(Network *network);
/**
+ * Destructor: used to write back values to the config file
+ */
+ ~ChatWindow();
+
+ /**
* Adds a line of text to our message list. Parameters:
*
* @param line Text message.
* @parem own Type of message (usually the owner-type).
*/
- void chatLog(std::string line, int own);
+ void chatLog(std::string line, int own, bool ignoreRecord = false);
- /*
+ /**
* Calls original chat_log() after processing the packet.
*/
void chatLog(CHATSKILL);
@@ -186,6 +181,9 @@ class ChatWindow : public Window, public gcn::ActionListener,
/** Called to set current text */
void setInputText(std::string input_str);
+ /** Called to add item to chat */
+ void addItemText(int itemid, const std::string &item);
+
/** Override to reset mTmpVisible */
void setVisible(bool visible);
@@ -199,6 +197,14 @@ class ChatWindow : public Window, public gcn::ActionListener,
void scroll(int amount);
/**
+ * party implements the partying chat commands
+ *
+ * @param command is the party command to perform
+ * @param msg is the remainder of the message
+ */
+ void party(const std::string &command, const std::string &msg);
+
+ /**
* help implements the /help command
*
* @param msg1 is the command that the player needs help on
@@ -207,10 +213,11 @@ class ChatWindow : public Window, public gcn::ActionListener,
void help(const std::string &msg1, const std::string &msg2);
private:
+
Network *mNetwork;
bool mTmpVisible;
- void whisper(const std::string &nick, std::string msg, int prefixlen);
+ void whisper(const std::string &nick, std::string msg);
/** One item in the chat log */
struct CHATLOG
@@ -226,13 +233,19 @@ class ChatWindow : public Window, public gcn::ActionListener,
gcn::TextField *mChatInput; /**< Input box for typing chat messages */
BrowserBox *mTextOutput; /**< Text box for displaying chat history */
ScrollArea *mScrollArea; /**< Scroll area around text output */
-
+ ItemLinkHandler *mItemLinkHandler; /** Used for showing item popup on
+ clicking links **/
typedef std::list<std::string> History;
typedef History::iterator HistoryIterator;
History mHistory; /**< Command history */
HistoryIterator mCurHist; /**< History iterator */
+ Recorder *mRecorder; /**< Recording class */
+ char mPartyPrefix; /**< Messages beginning with the prefix are sent to
+ the party */
+ bool mReturnToggles; /**< Marks whether <Return> toggles the chat log
+ or not */
+ Party *mParty;
};
-
extern ChatWindow *chatWindow;
#endif
diff --git a/src/gui/chatinput.h b/src/gui/chatinput.h
index 07144c5b..d98e120b 100644
--- a/src/gui/chatinput.h
+++ b/src/gui/chatinput.h
@@ -22,9 +22,11 @@
#ifndef CHATINPUT_H
#define CHATINPUT_H
+#include <guichan/focuslistener.hpp>
+
#include "textfield.h"
-#include <guichan/focuslistener.hpp>
+#include "../guichanfwd.h"
/**
* The chat input hides when it loses focus. It is also invisible by default.
diff --git a/src/gui/checkbox.h b/src/gui/checkbox.h
index 4b312d22..d92fc822 100644
--- a/src/gui/checkbox.h
+++ b/src/gui/checkbox.h
@@ -26,6 +26,8 @@
#include <guichan/widgets/checkbox.hpp>
+#include "../guichanfwd.h"
+
class Image;
/**
diff --git a/src/gui/colour.cpp b/src/gui/colour.cpp
new file mode 100644
index 00000000..816420ed
--- /dev/null
+++ b/src/gui/colour.cpp
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <cstdio>
+
+#include "colour.h"
+
+#include "../configuration.h"
+
+#include "../utils/gettext.h"
+
+Colour::Colour()
+{
+ addColour('C', 0x000000, _("Chat"));
+ addColour('G', 0xff0000, _("GM"));
+ addColour('Y', 0x1fa052, _("Player"));
+ addColour('W', 0x0000ff, _("Whisper"));
+ addColour('I', 0xf1dc27, _("Is"));
+ addColour('P', 0xff00d8, _("Party"));
+ addColour('S', 0x8415e2, _("Server"));
+ addColour('L', 0x919191, _("Logger"));
+ addColour('<', 0xe50d0d, _("Hyperlink"));
+ commit();
+}
+
+Colour::~Colour()
+{
+ for (ColVector::iterator col = mColVector.begin(),
+ colEnd = mColVector.end();
+ col != colEnd;
+ ++col)
+ {
+ char buffer[20];
+ std::sprintf(buffer, "0x%06x", col->rgb);
+ config.setValue("Colour" + col->text, buffer);
+ }
+}
+
+void Colour::setColour(const char c, const int rgb)
+{
+ for (ColVector::iterator col = mColVector.begin(),
+ colEnd = mColVector.end();
+ col != colEnd;
+ ++col)
+ {
+ if (col->ch == c)
+ {
+ col->rgb = rgb;
+ return;
+ }
+ }
+}
+
+int Colour::getColour(const char c, bool &valid) const
+{
+ for (ColVector::const_iterator col = mColVector.begin(),
+ colEnd = mColVector.end();
+ col != colEnd;
+ ++col)
+ {
+ if (col->ch == c)
+ {
+ valid = true;
+ return col->rgb;
+ }
+ }
+ valid = false;
+ return 0x000000;
+}
+
+std::string Colour::getElementAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return mColVector[i].text;
+}
+
+void Colour::addColour(const char c, const int rgb, const std::string &text)
+{
+ int trueRgb = config.getValue("Colour" + text, rgb);
+ mColVector.push_back(ColourElem(c, trueRgb, text));
+}
+
+int Colour::getColourAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return 0;
+ }
+ return mColVector[i].rgb;
+}
+
+void Colour::setColourAt(int i, int rgb)
+{
+ if (i >= 0 && i < getNumberOfElements())
+ {
+ mColVector[i].rgb = rgb;
+ }
+}
+
+void Colour::commit()
+{
+ for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
+ i != iEnd;
+ ++i)
+ {
+ i->committedRgb = i->rgb;
+ }
+}
+
+void Colour::rollback()
+{
+ for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
+ i != iEnd;
+ ++i)
+ {
+ i->rgb = i->committedRgb;
+ }
+}
diff --git a/src/gui/colour.h b/src/gui/colour.h
new file mode 100644
index 00000000..1e8ba3db
--- /dev/null
+++ b/src/gui/colour.h
@@ -0,0 +1,133 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef _COLOUR_H
+#define _COLOUR_H
+
+#include <cstdio>
+#include <string>
+#include <vector>
+
+#include <guichan/listmodel.hpp>
+
+#include "../guichanfwd.h"
+
+class Colour : public gcn::ListModel
+{
+ public:
+ /**
+ * Constructor
+ */
+ Colour();
+
+ /**
+ * Destructor
+ */
+ ~Colour();
+
+ /**
+ * Define the colour replacement for a character
+ *
+ * @param c charater to be replaced
+ * @param rgb colour to replace character
+ */
+ void setColour(const char c, const int rgb);
+
+ /**
+ * Define the colour replacement for a character
+ *
+ * @param c character to be replaced
+ * @param r red component
+ * @param g green component
+ * @param b blue component
+ */
+ void setColour(const char c, const int r, const int g, const int b)
+ {
+ setColour(c, (r << 16) | (g << 8) | b);
+ }
+
+ /**
+ * Return the colour associated with a character, if exists
+ *
+ * @param c character requested
+ * @param valid indicate whether character is known
+ */
+ int getColour(const char c, bool &valid) const;
+
+ /**
+ * Return the number of colours known
+ */
+ int getNumberOfElements() {return mColVector.size(); }
+
+ /**
+ * Return the name of the ith colour
+ *
+ * @param i index of colour interested in
+ */
+ std::string getElementAt(int i);
+
+ /**
+ * Get the colour for the element at index i in the current colour
+ * model
+ */
+ int getColourAt(int i);
+
+ /**
+ * Set the colour for the element at index i
+ */
+ void setColourAt(int i, int rgb);
+
+ /**
+ * Commit the colours
+ */
+ void commit();
+
+ /**
+ * Rollback the colours
+ */
+ void rollback();
+
+ private:
+ struct ColourElem
+ {
+ ColourElem(const char c, const int rgb, const std::string &text) :
+ ch(c), rgb(rgb), text(text) {}
+ char ch;
+ int rgb;
+ int committedRgb;
+ std::string text;
+ };
+ typedef std::vector<ColourElem> ColVector;
+ ColVector mColVector;
+
+ /**
+ * Initialise colour
+ *
+ * @param c character that needs initialising
+ * @param rgb default colour if not found in config
+ * @param text identifier of colour
+ */
+ void addColour(const char c, const int rgb, const std::string &text);
+};
+
+extern Colour *textColour;
+
+#endif
diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp
index 46b7c971..569fd93f 100644
--- a/src/gui/confirm_dialog.cpp
+++ b/src/gui/confirm_dialog.cpp
@@ -19,11 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "confirm_dialog.h"
-
-#include <guichan/widgets/label.hpp>
+#include <guichan/font.hpp>
-#include "button.h"
+#include "confirm_dialog.h"
#include "../utils/gettext.h"
@@ -31,28 +29,51 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg,
Window *parent):
Window(title, true, parent)
{
- gcn::Label *textLabel = new gcn::Label(msg);
+ mTextBox = new TextBox();
+ mTextBox->setEditable(false);
+ mTextBox->setOpaque(false);
+
+ mTextArea = new ScrollArea(mTextBox);
gcn::Button *yesButton = new Button(_("Yes"), "yes", this);
gcn::Button *noButton = new Button(_("No"), "no", this);
- int w = textLabel->getWidth() + 20;
+ mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextArea->setOpaque(false);
+
+ mTextBox->setMinWidth(260);
+ mTextBox->setTextWrapped(msg);
+
+ int numRows = mTextBox->getNumberOfRows();
+ int width = getFont()->getWidth(title);
int inWidth = yesButton->getWidth() + noButton->getWidth() + 5;
- int h = textLabel->getHeight() + 25 + yesButton->getHeight();
- if (w < inWidth + 10) {
- w = inWidth + 10;
+ if (numRows > 1)
+ {
+ // 15 == height of each line of text (based on font heights)
+ // 14 == row top + bottom graphic pixel heights
+ setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + noButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5,
+ 3 + (numRows * 14)));
+ }
+ else
+ {
+ if (width < getFont()->getWidth(msg))
+ width = getFont()->getWidth(msg);
+ if (width < inWidth)
+ width = inWidth;
+ setContentSize(width + 15, 30 + noButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17));
}
- setContentSize(w, h);
- textLabel->setPosition(10, 10);
yesButton->setPosition(
- (w - inWidth) / 2,
- h - 5 - noButton->getHeight());
+ (mTextBox->getMinWidth() - inWidth) / 2,
+ (numRows * 14) + noButton->getHeight() - 8);
noButton->setPosition(
yesButton->getX() + yesButton->getWidth() + 5,
- h - 5 - noButton->getHeight());
+ (numRows * 14) + noButton->getHeight() - 8);
- add(textLabel);
+ add(mTextArea);
add(yesButton);
add(noButton);
@@ -64,6 +85,11 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg,
yesButton->requestFocus();
}
+unsigned int ConfirmDialog::getNumRows()
+{
+ return mTextBox->getNumberOfRows();
+}
+
void ConfirmDialog::action(const gcn::ActionEvent &event)
{
// Proxy button events to our listeners
diff --git a/src/gui/confirm_dialog.h b/src/gui/confirm_dialog.h
index 69b3e9e4..fb8290c8 100644
--- a/src/gui/confirm_dialog.h
+++ b/src/gui/confirm_dialog.h
@@ -24,8 +24,12 @@
#include <guichan/actionlistener.hpp>
+#include "button.h"
+#include "scrollarea.h"
+#include "textbox.h"
#include "window.h"
+#include "../guichanfwd.h"
/**
* An option dialog.
@@ -42,10 +46,17 @@ class ConfirmDialog : public Window, public gcn::ActionListener {
ConfirmDialog(const std::string &title, const std::string &msg,
Window *parent = NULL);
+ unsigned int getNumRows();
+
/**
* Called when receiving actions from the widgets.
*/
void action(const gcn::ActionEvent &event);
+
+ private:
+ TextBox *mTextBox;
+ ScrollArea *mTextArea;
+ gcn::Button *okButton;
};
#endif
diff --git a/src/gui/connection.cpp b/src/gui/connection.cpp
index f73bb74d..15d85bbc 100644
--- a/src/gui/connection.cpp
+++ b/src/gui/connection.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "connection.h"
-
#include <guichan/actionlistener.hpp>
#include <guichan/widgets/label.hpp>
#include "button.h"
+#include "connection.h"
#include "progressbar.h"
#include "../main.h"
diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp
index 669aabd2..223b7fbd 100644
--- a/src/gui/debugwindow.cpp
+++ b/src/gui/debugwindow.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "debugwindow.h"
-
#include <SDL_mouse.h>
#include <guichan/widgets/label.hpp>
#include "button.h"
+#include "debugwindow.h"
#include "gui.h"
#include "viewport.h"
diff --git a/src/gui/emotecontainer.cpp b/src/gui/emotecontainer.cpp
new file mode 100644
index 00000000..fa63d4bb
--- /dev/null
+++ b/src/gui/emotecontainer.cpp
@@ -0,0 +1,172 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/mouseinput.hpp>
+#include <guichan/selectionlistener.hpp>
+
+#include "emotecontainer.h"
+
+#include "../animatedsprite.h"
+#include "../configuration.h"
+#include "../emoteshortcut.h"
+#include "../graphics.h"
+#include "../localplayer.h"
+#include "../log.h"
+
+#include "../resources/emotedb.h"
+#include "../resources/image.h"
+#include "../resources/iteminfo.h"
+#include "../resources/resourcemanager.h"
+
+#include "../utils/dtor.h"
+#include "../utils/gettext.h"
+#include "../utils/tostring.h"
+
+const int EmoteContainer::gridWidth = 34; // emote icon width + 4
+const int EmoteContainer::gridHeight = 36; // emote icon height + 4
+
+static const int NO_EMOTE = -1;
+
+EmoteContainer::EmoteContainer():
+ mSelectedEmoteIndex(NO_EMOTE)
+{
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ // Setup emote sprites
+ for (int i = 0; i <= EmoteDB::getLast(); i++)
+ {
+ mEmoteImg.push_back(player_node->getEmote(i));
+ }
+
+ mSelImg = resman->getImage("graphics/gui/selection.png");
+ if (!mSelImg) logger->error(_("Unable to load selection.png"));
+
+ mSelImg->setAlpha(config.getValue("guialpha", 0.8));
+
+ mMaxEmote = EmoteDB::getLast() + 1;
+
+ addMouseListener(this);
+ addWidgetListener(this);
+}
+
+EmoteContainer::~EmoteContainer()
+{
+ if (!mSelImg)
+ {
+ mSelImg->decRef();
+ mSelImg = NULL;
+ }
+}
+
+void EmoteContainer::draw(gcn::Graphics *graphics)
+{
+ int columns = getWidth() / gridWidth;
+
+ // Have at least 1 column
+ if (columns < 1)
+ {
+ columns = 1;
+ }
+
+ for (int i = 0; i < mMaxEmote ; i++)
+ {
+ int emoteX = ((i) % columns) * gridWidth;
+ int emoteY = ((i) / columns) * gridHeight;
+
+ // Draw emote icon
+ mEmoteImg[i]->draw(static_cast<Graphics*>(graphics), emoteX, emoteY);
+
+ // Draw selection image below selected item
+ if (mSelectedEmoteIndex == i)
+ {
+ static_cast<Graphics*>(graphics)->drawImage(
+ mSelImg, emoteX, emoteY);
+ }
+ }
+}
+
+void EmoteContainer::widgetResized(const gcn::Event &event)
+{
+ recalculateHeight();
+}
+
+void EmoteContainer::recalculateHeight()
+{
+ int cols = getWidth() / gridWidth;
+
+ if (cols < 1)
+ cols = 1;
+
+ const int rows = (mMaxEmote / cols) + (mMaxEmote % cols > 0 ? 1 : 0);
+ const int height = rows * gridHeight + 8;
+ if (height != getHeight())
+ setHeight(height);
+}
+
+int EmoteContainer::getSelectedEmote()
+{
+ if (mSelectedEmoteIndex == NO_EMOTE)
+ return 0;
+
+ return 1 + mSelectedEmoteIndex;
+}
+
+void EmoteContainer::selectNone()
+{
+ setSelectedEmoteIndex(NO_EMOTE);
+}
+
+void EmoteContainer::setSelectedEmoteIndex(int index)
+{
+ if (index < 0 || index >= mMaxEmote )
+ mSelectedEmoteIndex = NO_EMOTE;
+ else
+ mSelectedEmoteIndex = index;
+}
+
+void EmoteContainer::distributeValueChangedEvent()
+{
+ gcn::SelectionEvent event(this);
+ std::list<gcn::SelectionListener*>::iterator i_end = mListeners.end();
+ std::list<gcn::SelectionListener*>::iterator i;
+
+ for (i = mListeners.begin(); i != i_end; ++i)
+ {
+ (*i)->valueChanged(event);
+ }
+}
+
+void EmoteContainer::mousePressed(gcn::MouseEvent &event)
+{
+ int button = event.getButton();
+ if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT)
+ {
+ int columns = getWidth() / gridWidth;
+ int mx = event.getX();
+ int my = event.getY();
+ int index = mx / gridWidth + ((my / gridHeight) * columns);
+ if (index < mMaxEmote)
+ {
+ setSelectedEmoteIndex(index);
+ emoteShortcut->setEmoteSelected(index + 1);
+ }
+ }
+}
diff --git a/src/gui/emotecontainer.h b/src/gui/emotecontainer.h
new file mode 100644
index 00000000..8e52a206
--- /dev/null
+++ b/src/gui/emotecontainer.h
@@ -0,0 +1,138 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EMOTECONTAINER_H__
+#define EMOTECONTAINER_H__
+
+#include <list>
+#include <vector>
+
+#include <guichan/mouselistener.hpp>
+#include <guichan/widget.hpp>
+#include <guichan/widgetlistener.hpp>
+
+#include "../guichanfwd.h"
+
+class AnimatedSprite;
+class Image;
+
+namespace gcn {
+ class SelectionListener;
+}
+
+/**
+ * An emote container. Used to show emotes in inventory and trade dialog.
+ *
+ * \ingroup GUI
+ */
+class EmoteContainer : public gcn::Widget,
+ public gcn::MouseListener,
+ public gcn::WidgetListener
+{
+ public:
+ /**
+ * Constructor. Initializes the graphic.
+ */
+ EmoteContainer();
+
+ /**
+ * Destructor.
+ */
+ virtual ~EmoteContainer();
+
+ /**
+ * Draws the emotes.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Called whenever the widget changes size.
+ */
+ void widgetResized(const gcn::Event &event);
+
+ /**
+ * Handles mouse click.
+ */
+ void mousePressed(gcn::MouseEvent &event);
+
+ /**
+ * Returns the selected emote.
+ */
+ int getSelectedEmote();
+
+ /**
+ * Sets selected emote to NULL.
+ */
+ void selectNone();
+
+ /**
+ * Adds a listener to the list that's notified each time a change to
+ * the selection occurs.
+ */
+ void addSelectionListener(gcn::SelectionListener *listener)
+ {
+ mListeners.push_back(listener);
+ }
+
+ /**
+ * Removes a listener from the list that's notified each time a change
+ * to the selection occurs.
+ */
+ void removeSelectionListener(gcn::SelectionListener *listener)
+ {
+ mListeners.remove(listener);
+ }
+
+ private:
+ /**
+
+ * Sets the currently selected emote. Invalid (e.g., negative) indices set `no emotr'.
+ */
+ void setSelectedEmoteIndex(int index);
+
+ /**
+ * Find the current emote index by the most recently used emote ID
+ */
+ void refindSelectedEmote(void);
+
+ /**
+ * Determine and set the height of the container.
+ */
+ void recalculateHeight(void);
+
+ /**
+ * Sends out selection events to the list of selection listeners.
+ */
+ void distributeValueChangedEvent(void);
+
+ std::vector<AnimatedSprite*> mEmoteImg;
+ Image *mSelImg;
+ int mSelectedEmoteIndex;
+
+ int mMaxEmote;
+
+ std::list<gcn::SelectionListener*> mListeners;
+
+ static const int gridWidth;
+ static const int gridHeight;
+};
+
+#endif
diff --git a/src/gui/emoteshortcutcontainer.cpp b/src/gui/emoteshortcutcontainer.cpp
new file mode 100644
index 00000000..f5ee9843
--- /dev/null
+++ b/src/gui/emoteshortcutcontainer.cpp
@@ -0,0 +1,195 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "emoteshortcutcontainer.h"
+
+#include "../animatedsprite.h"
+#include "../emoteshortcut.h"
+#include "../graphics.h"
+#include "../inventory.h"
+#include "../item.h"
+#include "../itemshortcut.h"
+#include "../keyboardconfig.h"
+#include "../localplayer.h"
+#include "../log.h"
+
+#include "../resources/emotedb.h"
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+
+#include "../utils/dtor.h"
+#include "../utils/gettext.h"
+#include "../utils/tostring.h"
+
+static const int MAX_ITEMS = 12;
+
+EmoteShortcutContainer::EmoteShortcutContainer():
+ mEmoteClicked(false),
+ mEmoteMoved(0)
+{
+ mGridWidth = 1,
+ mGridHeight = 1,
+ addMouseListener(this);
+ addWidgetListener(this);
+
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png");
+
+ // Setup emote sprites
+ for (int i = 0; i <= EmoteDB::getLast(); i++)
+ {
+ mEmoteImg.push_back(player_node->getEmote(i));
+ }
+
+ mMaxItems = EmoteDB::getLast() < MAX_ITEMS ? EmoteDB::getLast() : MAX_ITEMS;
+
+ mBoxHeight = mBackgroundImg->getHeight();
+ mBoxWidth = mBackgroundImg->getWidth();
+}
+
+EmoteShortcutContainer::~EmoteShortcutContainer()
+{
+ mBackgroundImg->decRef();
+}
+
+void EmoteShortcutContainer::draw(gcn::Graphics *graphics)
+{
+ Graphics *g = static_cast<Graphics*>(graphics);
+
+ graphics->setFont(getFont());
+
+ for (int i = 0; i < mMaxItems; i++)
+ {
+ const int emoteX = (i % mGridWidth) * mBoxWidth;
+ const int emoteY = (i / mGridWidth) * mBoxHeight;
+
+ g->drawImage(mBackgroundImg, emoteX, emoteY);
+
+ // Draw emote keyboard shortcut.
+ const char *key = SDL_GetKeyName(
+ (SDLKey) keyboard.getKeyValue(keyboard.KEY_EMOTE_1 + i));
+ graphics->setColor(0x000000);
+ g->drawText(key, emoteX + 2, emoteY + 2, gcn::Graphics::LEFT);
+
+ if (emoteShortcut->getEmote(i))
+ {
+ mEmoteImg[emoteShortcut->getEmote(i) - 1]->draw(g, emoteX + 2, emoteY + 10);
+ }
+
+ }
+ if (mEmoteMoved)
+ {
+ // Draw the emote image being dragged by the cursor.
+ AnimatedSprite* sprite = mEmoteImg[mEmoteMoved - 1];
+ if (sprite)
+ {
+ const int tPosX = mCursorPosX - (sprite->getWidth() / 2);
+ const int tPosY = mCursorPosY - (sprite->getHeight() / 2);
+
+ sprite->draw(g, tPosX, tPosY);
+ }
+ }
+}
+
+void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event)
+{
+ if (event.getButton() == gcn::MouseEvent::LEFT)
+ {
+ if (!mEmoteMoved && mEmoteClicked)
+ {
+ const int index = getIndexFromGrid(event.getX(), event.getY());
+ const int emoteId = emoteShortcut->getEmote(index);
+
+ if (index == -1)
+ {
+ return;
+ }
+
+ if (emoteId)
+ {
+ mEmoteMoved = emoteId;
+ emoteShortcut->removeEmote(index);
+ }
+ }
+ if (mEmoteMoved)
+ {
+ mCursorPosX = event.getX();
+ mCursorPosY = event.getY();
+ }
+ }
+}
+
+void EmoteShortcutContainer::mousePressed(gcn::MouseEvent &event)
+{
+ const int index = getIndexFromGrid(event.getX(), event.getY());
+
+ if (index == -1)
+ {
+ return;
+ }
+
+ // Stores the selected emote if there is one.
+ if (emoteShortcut->isEmoteSelected())
+ {
+ emoteShortcut->setEmote(index);
+ emoteShortcut->setEmoteSelected(0);
+ }
+ else if (emoteShortcut->getEmote(index))
+ {
+ mEmoteClicked = true;
+ }
+}
+
+void EmoteShortcutContainer::mouseReleased(gcn::MouseEvent &event)
+{
+ if (event.getButton() == gcn::MouseEvent::LEFT)
+ {
+ const int index = getIndexFromGrid(event.getX(), event.getY());
+
+ if (emoteShortcut->isEmoteSelected())
+ {
+ emoteShortcut->setEmoteSelected(0);
+ }
+
+ if (index == -1)
+ {
+ mEmoteMoved = 0;
+ return;
+ }
+
+ if (mEmoteMoved)
+ {
+ emoteShortcut->setEmotes(index, mEmoteMoved);
+ mEmoteMoved = 0;
+ }
+ else if (emoteShortcut->getEmote(index) && mEmoteClicked)
+ {
+ emoteShortcut->useEmote(index + 1);
+ }
+
+ if (mEmoteClicked)
+ {
+ mEmoteClicked = false;
+ }
+ }
+}
+
diff --git a/src/gui/emoteshortcutcontainer.h b/src/gui/emoteshortcutcontainer.h
new file mode 100644
index 00000000..cffaee6f
--- /dev/null
+++ b/src/gui/emoteshortcutcontainer.h
@@ -0,0 +1,81 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EMOTESHORTCUTCONTAINER_H__
+#define EMOTESHORTCUTCONTAINER_H__
+
+#include <vector>
+
+#include <guichan/mouselistener.hpp>
+
+#include "shortcutcontainer.h"
+
+#include "../guichanfwd.h"
+
+class AnimatedSprite;
+class Image;
+
+/**
+ * An emote shortcut container. Used to quickly use emoticons.
+ *
+ * \ingroup GUI
+ */
+class EmoteShortcutContainer : public ShortcutContainer
+{
+ public:
+ /**
+ * Constructor. Initializes the graphic.
+ */
+ EmoteShortcutContainer();
+
+ /**
+ * Destructor.
+ */
+ virtual ~EmoteShortcutContainer();
+
+ /**
+ * Draws the items.
+ */
+ void draw(gcn::Graphics *graphics);
+
+ /**
+ * Handles mouse when dragged.
+ */
+ void mouseDragged(gcn::MouseEvent &event);
+
+ /**
+ * Handles mouse when pressed.
+ */
+ void mousePressed(gcn::MouseEvent &event);
+
+ /**
+ * Handles mouse release.
+ */
+ void mouseReleased(gcn::MouseEvent &event);
+
+ private:
+ std::vector<AnimatedSprite*> mEmoteImg;
+
+ bool mEmoteClicked;
+ int mEmoteMoved;
+};
+
+#endif
diff --git a/src/gui/emotewindow.cpp b/src/gui/emotewindow.cpp
new file mode 100644
index 00000000..b4e9c735
--- /dev/null
+++ b/src/gui/emotewindow.cpp
@@ -0,0 +1,82 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string>
+
+#include <guichan/mouseinput.hpp>
+
+#include "button.h"
+#include "gui.h"
+#include "emotewindow.h"
+#include "emotecontainer.h"
+#include "scrollarea.h"
+#include "textbox.h"
+
+#include "widgets/layout.h"
+
+#include "../localplayer.h"
+
+#include "../utils/gettext.h"
+#include "../utils/tostring.h"
+
+EmoteWindow::EmoteWindow():
+ Window(_("Emote"))
+{
+ setWindowName(_("Emote"));
+ setResizable(true);
+ setCloseButton(true);
+ setMinWidth(80);
+ setMinHeight(130);
+ setDefaultSize(115, 25, 322, 200);
+
+ mUseButton = new Button(_("Use"), "use", this);
+
+ mEmotes = new EmoteContainer();
+ mEmotes->addSelectionListener(this);
+
+ mEmoteScroll = new ScrollArea(mEmotes);
+ mEmoteScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+
+ place(0, 0, mEmoteScroll, 5, 4);
+ place(4, 4, mUseButton);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
+
+ mUseButton->setSize(60, mUseButton->getHeight());
+
+ loadWindowState();
+}
+
+void EmoteWindow::action(const gcn::ActionEvent &event)
+{
+ int emote = mEmotes->getSelectedEmote();
+
+ if (!emote)
+ return;
+
+ player_node->emote(emote);
+}
+
+int EmoteWindow::getSelectedEmote() const
+{
+ return mEmotes->getSelectedEmote();
+}
diff --git a/src/gui/emotewindow.h b/src/gui/emotewindow.h
new file mode 100644
index 00000000..8e36e5ce
--- /dev/null
+++ b/src/gui/emotewindow.h
@@ -0,0 +1,68 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EMOTEWINDOW_H
+#define EMOTEWINDOW_H
+
+#include <guichan/actionlistener.hpp>
+#include <guichan/selectionlistener.hpp>
+
+#include "window.h"
+
+#include "../guichanfwd.h"
+
+class EmoteContainer;
+class TextBox;
+
+/**
+ * Emote dialog.
+ *
+ * \ingroup Interface
+ */
+class EmoteWindow : public Window, gcn::ActionListener,
+ gcn::SelectionListener
+{
+ public:
+ /**
+ * Constructor.
+ */
+ EmoteWindow();
+
+ /**
+ * Called when receiving actions from the widgets.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Returns the selected item.
+ */
+ int getSelectedEmote() const;
+
+ private:
+ EmoteContainer *mEmotes;
+
+ gcn::Button *mUseButton;
+ gcn::ScrollArea *mEmoteScroll;
+};
+
+extern EmoteWindow *emoteWindow;
+
+#endif
diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp
index aa6825f2..1fb2b601 100644
--- a/src/gui/equipmentwindow.cpp
+++ b/src/gui/equipmentwindow.cpp
@@ -19,14 +19,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define BOX_WIDTH 36
+#define BOX_HEIGHT 36
+
+#include <guichan/font.hpp>
+
+#include "button.h"
#include "equipmentwindow.h"
+#include "playerbox.h"
#include "../equipment.h"
-#include "../inventory.h"
-#include "../localplayer.h"
#include "../graphics.h"
+#include "../inventory.h"
#include "../item.h"
-#include "../log.h"
+#include "../localplayer.h"
#include "../resources/iteminfo.h"
#include "../resources/resourcemanager.h"
@@ -34,19 +40,57 @@
#include "../utils/gettext.h"
#include "../utils/tostring.h"
+// Positions of the boxes, 2nd dimension is X and Y respectively.
+static const int boxPosition[][2] = {
+ {50, 208}, // EQUIP_LEGS_SLOT
+ {8, 123}, // EQUIP_FIGHT1_SLOT
+ {8, 78}, // EQUIP_GLOVES_SLOT
+ {129, 168}, // EQUIP_RING2_SLOT
+ {8, 168}, // EQUIP_RING1_SLOT
+ {129, 123}, // EQUIP_FIGHT2_SLOT
+ {90, 208}, // EQUIP_FEET_SLOT
+ {50, 40}, // EQUIP_CAPE_SLOT
+ {70, 0}, // EQUIP_HEAD_SLOT
+ {90, 40}, // EQUIP_TORSO_SLOT
+ {129, 78} // EQUIP_AMMO_SLOT
+};
+
EquipmentWindow::EquipmentWindow(Equipment *equipment):
Window(_("Equipment")),
- mEquipment(equipment)
+ mEquipment(equipment),
+ mSelected(-1)
+
{
+ // Control that shows the Player
+ mPlayerBox = new PlayerBox;
+ mPlayerBox->setDimension(gcn::Rectangle(50, 80, 74, 123));
+ mPlayerBox->setPlayer(player_node);
+
setWindowName("Equipment");
setCloseButton(true);
- setDefaultSize(5, 230, 200, 140);
+ setDefaultSize(5, 195, 180, 300);
loadWindowState();
+
+ mUnequip = new Button(_("Unequip"), "unequip", this);
+ gcn::Rectangle const &area = getChildrenArea();
+ mUnequip->setPosition(area.width - mUnequip->getWidth() - 5,
+ area.height - mUnequip->getHeight() - 5);
+
+ add(mPlayerBox);
+ add(mUnequip);
+
+ for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
+ {
+ mEquipBox[i].posX = boxPosition[i][0] + getPadding();
+ mEquipBox[i].posY = boxPosition[i][1] + getTitleBarHeight();
+ }
+
mInventory = player_node->getInventory();
}
EquipmentWindow::~EquipmentWindow()
{
+ delete mUnequip;
}
void EquipmentWindow::draw(gcn::Graphics *graphics)
@@ -54,37 +98,85 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
// Draw window graphics
Window::draw(graphics);
- Item *item;
- Image *image;
+ Item* item;
- // Rectangles around items are black
- graphics->setColor(gcn::Color(0, 0, 0));
+ Graphics *g = static_cast<Graphics*>(graphics);
- for (int i = 0; i < EQUIPMENT_SIZE; i++) {
- graphics->drawRectangle(gcn::Rectangle(10 + 36 * (i % 4),
- 36 * (i / 4) + 25, 32, 32));
+ Window::drawChildren(graphics);
- if (!(item = mInventory->getItem(mEquipment->getEquipment(i))))
- continue;
+ for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
+ {
+ item = (i != EQUIP_AMMO_SLOT) ?
+ mInventory->getItem(mEquipment->getEquipment(i)) :
+ mInventory->getItem(mEquipment->getArrows());
+ if (item)
+ {
+ // Draw Item.
+ Image* image = item->getImage();
+ g->drawImage(image, mEquipBox[i].posX, mEquipBox[i].posY);
+ if (i == EQUIP_AMMO_SLOT)
+ {
+ g->setColor(gcn::Color(0, 0, 0));
+ graphics->drawText(toString(item->getQuantity()),
+ mEquipBox[i].posX + (BOX_WIDTH / 2),
+ mEquipBox[i].posY - getFont()->getHeight(),
+ gcn::Graphics::CENTER);
+ }
+ }
- image = item->getImage();
- if (image)
+ if (i == mSelected)
+ {
+ // Set color red.
+ g->setColor(gcn::Color(255, 0, 0));
+ }
+ else
{
- static_cast<Graphics*>(graphics)->drawImage(
- image, 36 * (i % 4) + 10, 36 * (i / 4) + 25);
+ // Set color black.
+ g->setColor(gcn::Color(0, 0, 0));
}
+
+ // Draw box border.
+ g->drawRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY,
+ BOX_WIDTH, BOX_HEIGHT));
+ }
+}
+
+void EquipmentWindow::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "unequip" && mSelected > -1)
+ {
+ Item* item = (mSelected != EQUIP_AMMO_SLOT) ?
+ mInventory->getItem(mEquipment->getEquipment(mSelected)) :
+ mInventory->getItem(mEquipment->getArrows());
+ player_node->unequipItem(item);
+ mSelected = -1;
}
+}
+
+void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent)
+{
+ Window::mousePressed(mouseEvent);
- graphics->drawRectangle(gcn::Rectangle(160, 25, 32, 32));
+ const int x = mouseEvent.getX();
+ const int y = mouseEvent.getY();
- if (!(item = mInventory->getItem(mEquipment->getArrows())))
- return;
+ Item* item;
- image = item->getImage();
- if (image)
+ // Checks if any of the presses were in the equip boxes.
+ for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
{
- static_cast<Graphics*>(graphics)->drawImage(image, 160, 25);
+ item = (i != EQUIP_AMMO_SLOT) ?
+ mInventory->getItem(mEquipment->getEquipment(i)) :
+ mInventory->getItem(mEquipment->getArrows());
+ gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY,
+ BOX_WIDTH, BOX_HEIGHT);
+ if (tRect.isPointInRect(x, y))
+ {
+ if (item)
+ {
+ mSelected = i;
+ }
+ }
}
- graphics->drawText(toString(item->getQuantity()), 170, 62,
- gcn::Graphics::CENTER);
}
+
diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h
index e2420134..0b3aede0 100644
--- a/src/gui/equipmentwindow.h
+++ b/src/gui/equipmentwindow.h
@@ -22,17 +22,29 @@
#ifndef EQUIPMENTWINDOW_H
#define EQUIPMENTWINDOW_H
+#include <guichan/actionlistener.hpp>
+
#include "window.h"
-#include "../inventory.h"
class Equipment;
+class Inventory;
+class PlayerBox;
+
+/**
+ * Equipment box.
+ */
+struct EquipBox
+{
+ int posX;
+ int posY;
+};
/**
* Equipment dialog.
*
* \ingroup Interface
*/
-class EquipmentWindow : public Window
+class EquipmentWindow : public Window, public gcn::ActionListener
{
public:
/**
@@ -50,9 +62,36 @@ class EquipmentWindow : public Window
*/
void draw(gcn::Graphics *graphics);
+ void action(const gcn::ActionEvent &event);
+
+ void mousePressed(gcn::MouseEvent& mouseEvent);
+
+ enum {
+ // Equipment rules:
+ EQUIP_LEGS_SLOT = 0,
+ EQUIP_FIGHT1_SLOT,
+ EQUIP_GLOVES_SLOT,
+ EQUIP_RING2_SLOT,
+ EQUIP_RING1_SLOT,
+ EQUIP_FIGHT2_SLOT,
+ EQUIP_FEET_SLOT,
+ EQUIP_CAPE_SLOT,
+ EQUIP_HEAD_SLOT,
+ EQUIP_TORSO_SLOT,
+ EQUIP_AMMO_SLOT,
+ EQUIP_VECTOREND
+ };
+
+
private:
Equipment *mEquipment;
Inventory *mInventory;
+ gcn::Button *mUnequip; /**< Button for unequipping. */
+ EquipBox mEquipBox[EQUIP_VECTOREND]; /**< Equipment Boxes. */
+
+ PlayerBox *mPlayerBox;
+
+ int mSelected; /**< Index of selected item. */
};
extern EquipmentWindow *equipmentWindow;
diff --git a/src/gui/focushandler.cpp b/src/gui/focushandler.cpp
index 3ceed595..dd605be6 100644
--- a/src/gui/focushandler.cpp
+++ b/src/gui/focushandler.cpp
@@ -21,7 +21,6 @@
#include "focushandler.h"
-
void FocusHandler::requestModalFocus(gcn::Widget *widget)
{
/* If there is another widget with modal focus, remove its modal focus
diff --git a/src/gui/gccontainer.h b/src/gui/gccontainer.h
index da584a42..0a573645 100644
--- a/src/gui/gccontainer.h
+++ b/src/gui/gccontainer.h
@@ -26,6 +26,8 @@
#include <guichan/widgets/container.hpp>
+#include "../guichanfwd.h"
+
/**
* A garbage collecting container. Childs added to this container are
* automatically deleted when the container is deleted.
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index 2da451a3..642e916b 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "gui.h"
-
#include <guichan/exception.hpp>
#include <guichan/image.hpp>
#include <guichan/imagefont.hpp>
#include "focushandler.h"
+#include "gui.h"
#include "sdlinput.h"
#include "truetypefont.h"
#include "viewport.h"
@@ -39,12 +38,12 @@
#include "../resources/image.h"
#include "../resources/imageset.h"
-#include "../resources/resourcemanager.h"
#include "../resources/imageloader.h"
+#include "../resources/resourcemanager.h"
// Guichan stuff
Gui *gui = 0;
-Viewport *viewport = 0; /**< Viewport on the map. */
+Viewport *viewport = 0; /**< Viewport on the map. */
SDLInput *guiInput = 0;
// Fonts used in showing hits
@@ -52,6 +51,9 @@ gcn::Font *hitRedFont = 0;
gcn::Font *hitBlueFont = 0;
gcn::Font *hitYellowFont = 0;
+// Bolded font
+gcn::Font *boldFont = 0;
+
class GuiConfigListener : public ConfigListener
{
public:
@@ -115,14 +117,26 @@ Gui::Gui(Graphics *graphics):
+ e.getMessage());
}
+ // Set bold font
+ path = resman->getPath("fonts/dejavusans-bold.ttf");
+ try {
+ const int fontSize = config.getValue("fontSize", 11);
+ boldFont = new TrueTypeFont(path, fontSize);
+ }
+ catch (gcn::Exception e)
+ {
+ logger->error(std::string("Unable to load dejavusans-bold.ttf: ")
+ + e.getMessage());
+ }
+
gcn::Widget::setGlobalFont(mGuiFont);
// Load hits' colourful fonts
try {
hitRedFont = new gcn::ImageFont("graphics/gui/hits_red.png",
- "0123456789");
+ "0123456789crit! ");
hitBlueFont = new gcn::ImageFont("graphics/gui/hits_blue.png",
- "0123456789");
+ "0123456789crit! ");
hitYellowFont = new gcn::ImageFont("graphics/gui/hits_yellow.png",
"0123456789misxp ");
}
@@ -158,6 +172,7 @@ Gui::~Gui()
mMouseCursors->decRef();
delete mGuiFont;
+ delete boldFont;
delete viewport;
delete getTop();
diff --git a/src/gui/gui.h b/src/gui/gui.h
index 95cd5815..9681d44a 100644
--- a/src/gui/gui.h
+++ b/src/gui/gui.h
@@ -26,8 +26,8 @@
#include "../guichanfwd.h"
-class GuiConfigListener;
class Graphics;
+class GuiConfigListener;
class ImageSet;
class SDLInput;
class Viewport;
@@ -125,4 +125,9 @@ extern gcn::Font *hitRedFont;
extern gcn::Font *hitBlueFont;
extern gcn::Font *hitYellowFont;
+/**
+ * Bolded text font
+ */
+extern gcn::Font *boldFont;
+
#endif
diff --git a/src/gui/help.cpp b/src/gui/help.cpp
index 390cb44e..6b14f6d8 100644
--- a/src/gui/help.cpp
+++ b/src/gui/help.cpp
@@ -19,12 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "help.h"
-
#include "button.h"
#include "browserbox.h"
+#include "help.h"
#include "scrollarea.h"
+#include "widgets/layout.h"
+
#include "../resources/resourcemanager.h"
#include "../utils/gettext.h"
@@ -33,7 +34,8 @@ HelpWindow::HelpWindow():
Window(_("Help"))
{
setContentSize(455, 350);
- setWindowName("Help");
+ setWindowName(_("Help"));
+ setResizable(true);
mBrowserBox = new BrowserBox();
mBrowserBox->setOpaque(false);
@@ -48,8 +50,11 @@ HelpWindow::HelpWindow():
mBrowserBox->setLinkHandler(this);
- add(mScrollArea);
- add(okButton);
+ place(0, 0, mScrollArea, 5, 3).setPadding(3);
+ place(4, 3, okButton);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
setLocationRelativeTo(getParent());
}
diff --git a/src/gui/help.h b/src/gui/help.h
index e3d9246d..2ba74c0a 100644
--- a/src/gui/help.h
+++ b/src/gui/help.h
@@ -24,8 +24,8 @@
#include <guichan/actionlistener.hpp>
-#include "window.h"
#include "linkhandler.h"
+#include "window.h"
#include "../guichanfwd.h"
diff --git a/src/gui/inttextfield.cpp b/src/gui/inttextfield.cpp
index eb61c4d7..fcbe938d 100644
--- a/src/gui/inttextfield.cpp
+++ b/src/gui/inttextfield.cpp
@@ -20,7 +20,6 @@
*/
#include "inttextfield.h"
-
#include "sdlinput.h"
#include "../utils/tostring.h"
diff --git a/src/gui/inttextfield.h b/src/gui/inttextfield.h
index 4dfef8e1..2a913ef6 100644
--- a/src/gui/inttextfield.h
+++ b/src/gui/inttextfield.h
@@ -24,6 +24,8 @@
#include "textfield.h"
+#include "../guichanfwd.h"
+
/**
* TextBox which only accepts numbers as input.
*/
@@ -58,8 +60,7 @@ class IntTextField : public TextField
/**
* Responds to key presses.
*/
- void
- keyPressed(gcn::KeyEvent &event);
+ void keyPressed(gcn::KeyEvent &event);
private:
int mMin; /**< Minimum value */
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index 31ebb86e..58c13910 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -19,72 +19,91 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "inventorywindow.h"
-
#include <string>
+#include <guichan/font.hpp>
#include <guichan/mouseinput.hpp>
+
#include <guichan/widgets/label.hpp>
#include "button.h"
#include "gui.h"
+#include "inventorywindow.h"
#include "item_amount.h"
#include "itemcontainer.h"
+#include "progressbar.h"
#include "scrollarea.h"
+#include "textbox.h"
#include "viewport.h"
+#include "widgets/layout.h"
+
#include "../inventory.h"
#include "../item.h"
-#include "../localplayer.h"
#include "../resources/iteminfo.h"
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
+#include "../utils/tostring.h"
-InventoryWindow::InventoryWindow():
- Window(_("Inventory"))
+InventoryWindow::InventoryWindow(int invSize):
+ Window(_("Inventory")),
+ mMaxSlots(invSize),
+ mItemDesc(false)
{
- setWindowName("Inventory");
+ setWindowName(_("Inventory"));
setResizable(true);
setCloseButton(true);
- setMinWidth(240);
- setMinHeight(172);
+
// If you adjust these defaults, don't forget to adjust the trade window's.
- setDefaultSize(115, 25, 322, 200);
+ setDefaultSize(115, 25, 375, 300);
- mUseButton = new Button(_("Use"), "use", this);
+ std::string longestUseString = getFont()->getWidth(_("Equip")) >
+ getFont()->getWidth(_("Use")) ?
+ _("Equip") : _("Use");
+
+ if (getFont()->getWidth(longestUseString) <
+ getFont()->getWidth(_("Unequip")))
+ {
+ longestUseString = _("Unequip");
+ }
+
+ mUseButton = new Button(longestUseString, "use", this);
mDropButton = new Button(_("Drop"), "drop", this);
- mItems = new ItemContainer(player_node->getInventory());
+ mItems = new ItemContainer(player_node->getInventory(), 2);
mItems->addSelectionListener(this);
mInvenScroll = new ScrollArea(mItems);
mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
- mItemNameLabel = new gcn::Label("Name:");
- mItemDescriptionLabel = new gcn::Label("Description:");
- mItemEffectLabel = new gcn::Label("Effect:");
- mWeightLabel = new gcn::Label("Weight:");
- mWeightLabel->setPosition(8, 8);
- mInvenScroll->setPosition(8,
- mWeightLabel->getY() + mWeightLabel->getHeight() + 5);
- mInvenSlotLabel = new gcn::Label("Slots used:");
- mInvenSlotLabel->setPosition(mWeightLabel->getX()
- + mWeightLabel->getWidth() + 100, 8);
-
- add(mUseButton);
- add(mDropButton);
- add(mInvenScroll);
- add(mItemNameLabel);
- add(mItemDescriptionLabel);
- add(mItemEffectLabel);
- add(mWeightLabel);
- add(mInvenSlotLabel);
-
- mUseButton->setSize(60, mUseButton->getHeight());
+ mTotalWeight = toString(player_node->mTotalWeight);
+ mMaxWeight = toString(player_node->mMaxWeight);
+ mUsedSlots = toString(player_node->getInventory()->getNumberOfSlotsUsed());
+
+ mSlotsLabel = new gcn::Label(_("Slots: "));
+ mWeightLabel = new gcn::Label(_("Weight: "));
+
+ mSlotsBar = new ProgressBar(1.0f, 100, 20, 225, 200, 25);
+ mWeightBar = new ProgressBar(1.0f, 100, 20, 0, 0, 255);
+
+ setMinHeight(130);
+ setMinWidth(mWeightLabel->getWidth() + mSlotsLabel->getWidth() + 310);
+
+ place(0, 0, mInvenScroll, 7, 4);
+ place(0, 4, mWeightLabel).setPadding(3);
+ place(1, 4, mWeightBar, 2);
+ place(3, 4, mSlotsLabel).setPadding(3);
+ place(4, 4, mSlotsBar, 2);
+ place(5, 5, mDropButton);
+ place(6, 5, mUseButton);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
loadWindowState();
+ setLocationRelativeTo(getParent());
}
void InventoryWindow::logic()
@@ -95,15 +114,39 @@ void InventoryWindow::logic()
// redesign of InventoryWindow and ItemContainer probably.
updateButtons();
- // Update weight information
- mWeightLabel->setCaption(strprintf(_("Weight: %d / %d"),
- player_node->mTotalWeight,
- player_node->mMaxWeight));
+ if ((mMaxWeight != toString(player_node->mMaxWeight)) ||
+ mTotalWeight != toString(player_node->mTotalWeight) ||
+ mUsedSlots != toString(player_node->getInventory()->getNumberOfSlotsUsed()))
+ {
+ mTotalWeight = toString(player_node->mTotalWeight);
+ mMaxWeight = toString(player_node->mMaxWeight);
+ mUsedSlots = toString(player_node->getInventory()->getNumberOfSlotsUsed());
+
+ // Weight Bar coloration
+ if (int(player_node->mTotalWeight) < int(player_node->mMaxWeight / 3))
+ {
+ mWeightBar->setColor(0, 0, 255); // Blue
+ }
+ else if (int(player_node->mTotalWeight) <
+ int((player_node->mMaxWeight / 3) * 2))
+ {
+ mWeightBar->setColor(255, 255, 0); // Yellow
+ }
+ else
+ {
+ mWeightBar->setColor(255, 0, 0); // Red
+ }
+
+ // Adjust progress bars
+ mSlotsBar->setProgress((float)
+ player_node->getInventory()->getNumberOfSlotsUsed() / mMaxSlots);
+ mWeightBar->setProgress((float) player_node->mTotalWeight /
+ player_node->mMaxWeight);
- // Update number of items in inventory
- mInvenSlotLabel->setCaption(strprintf(_("Slots used: %d / %d"),
- player_node->getInventory()->getNumberOfSlotsUsed(),
- player_node->getInventory()->getInventorySize()));
+ mSlotsBar->setText(strprintf("%s/%d", mUsedSlots.c_str(), mMaxSlots));
+ mWeightBar->setText(strprintf("%sg/%sg", mTotalWeight.c_str(),
+ mMaxWeight.c_str()));
+ }
}
void InventoryWindow::action(const gcn::ActionEvent &event)
@@ -113,55 +156,30 @@ void InventoryWindow::action(const gcn::ActionEvent &event)
if (!item)
return;
- if (event.getId() == "use") {
- if (item->isEquipment()) {
- if (item->isEquipped()) {
+ if (event.getId() == "use")
+ {
+ if (item->isEquipment())
+ {
+ if (item->isEquipped())
player_node->unequipItem(item);
- }
- else {
+ else
player_node->equipItem(item);
- }
}
- else {
+ else
player_node->useItem(item);
- }
}
else if (event.getId() == "drop")
{
- if (item->getQuantity() == 1) {
+ if (item->getQuantity() == 1)
player_node->dropItem(item, 1);
- }
- else {
+ else
+ {
// Choose amount of items to drop
new ItemAmountWindow(AMOUNT_ITEM_DROP, this, item);
}
}
}
-void InventoryWindow::valueChanged(const gcn::SelectionEvent &event)
-{
- const Item *item = mItems->getSelectedItem();
-
- // Update name, effect and description
- if (!item)
- {
- mItemNameLabel->setCaption(strprintf(_("Name: %s"), ""));
- mItemEffectLabel->setCaption(strprintf(_("Effect: %s"), ""));
- mItemDescriptionLabel->setCaption(strprintf(_("Description: %s"), ""));
- }
- else
- {
- const ItemInfo& itemInfo = item->getInfo();
- mItemNameLabel->setCaption(
- strprintf(_("Name: %s"), itemInfo.getName().c_str()));
- mItemEffectLabel->setCaption(
- strprintf(_("Effect: %s"), itemInfo.getEffect().c_str()));
- mItemDescriptionLabel->setCaption(
- strprintf(_("Description: %s"),
- itemInfo.getDescription().c_str()));
- }
-}
-
void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
{
Window::mouseClicked(event);
@@ -182,55 +200,19 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
}
}
-void InventoryWindow::widgetResized(const gcn::Event &event)
-{
- Window::widgetResized(event);
-
- const gcn::Rectangle &area = getChildrenArea();
- const int width = area.width;
- const int height = area.height;
-
- // Adjust widgets
- mUseButton->setPosition(8, height - 8 - mUseButton->getHeight());
- mDropButton->setPosition(8 + mUseButton->getWidth() + 5,
- mUseButton->getY());
-
- mItemNameLabel->setDimension(gcn::Rectangle(8,
- mUseButton->getY() - 5 - mItemNameLabel->getHeight(),
- width - 16,
- mItemNameLabel->getHeight()));
- mItemEffectLabel->setDimension(gcn::Rectangle(8,
- mItemNameLabel->getY() - 5 - mItemEffectLabel->getHeight(),
- width - 16,
- mItemEffectLabel->getHeight()));
- mItemDescriptionLabel->setDimension(gcn::Rectangle(8,
- mItemEffectLabel->getY() - 5 - mItemDescriptionLabel->getHeight(),
- width - 16,
- mItemDescriptionLabel->getHeight()));
-
- mInvenScroll->setSize(width - 16,
- mItemDescriptionLabel->getY() - mWeightLabel->getHeight() - 18);
-
- mWeightLabel->setWidth(width - 16);
- mInvenSlotLabel->setWidth(width - 16);
-}
-
void InventoryWindow::updateButtons()
{
const Item *selectedItem = mItems->getSelectedItem();
if (selectedItem && selectedItem->isEquipment())
{
- if (selectedItem->isEquipped()) {
+ if (selectedItem->isEquipped())
mUseButton->setCaption(_("Unequip"));
- }
- else {
+ else
mUseButton->setCaption(_("Equip"));
- }
}
- else {
+ else
mUseButton->setCaption(_("Use"));
- }
mUseButton->setEnabled(selectedItem != 0);
mDropButton->setEnabled(selectedItem != 0);
diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h
index 402ab0d2..2c19ce26 100644
--- a/src/gui/inventorywindow.h
+++ b/src/gui/inventorywindow.h
@@ -28,9 +28,12 @@
#include "window.h"
#include "../guichanfwd.h"
+#include "../localplayer.h"
class Item;
class ItemContainer;
+class ProgressBar;
+class TextBox;
/**
* Inventory dialog.
@@ -38,13 +41,13 @@ class ItemContainer;
* \ingroup Interface
*/
class InventoryWindow : public Window, gcn::ActionListener,
- gcn::SelectionListener
+ gcn::SelectionListener
{
public:
/**
* Constructor.
*/
- InventoryWindow();
+ InventoryWindow(int invSize = (INVENTORY_SIZE - 2));
/**
* Logic (updates buttons and weight information).
@@ -61,30 +64,30 @@ class InventoryWindow : public Window, gcn::ActionListener,
*/
Item* getSelectedItem() const;
- /**
- * Updates labels to currently selected item.
- */
- void valueChanged(const gcn::SelectionEvent &event);
-
void mouseClicked(gcn::MouseEvent &event);
- /**
- * Called whenever the widget changes size.
- */
- void widgetResized(const gcn::Event &event);
-
private:
void updateButtons(); /**< Updates button states. */
ItemContainer *mItems;
+ std::string mWeight;
+ std::string mSlots;
+ std::string mUsedSlots;
+ std::string mTotalWeight;
+ std::string mMaxWeight;
gcn::Button *mUseButton, *mDropButton;
gcn::ScrollArea *mInvenScroll;
- gcn::Label *mItemNameLabel;
- gcn::Label *mItemDescriptionLabel;
- gcn::Label *mItemEffectLabel;
+
gcn::Label *mWeightLabel;
- gcn::Label *mInvenSlotLabel;
+ gcn::Label *mSlotsLabel;
+
+ ProgressBar *mWeightBar;
+ ProgressBar *mSlotsBar;
+
+ int mMaxSlots;
+
+ bool mItemDesc;
};
extern InventoryWindow *inventoryWindow;
diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp
index 7ef3d71b..d8682c95 100644
--- a/src/gui/item_amount.cpp
+++ b/src/gui/item_amount.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "item_amount.h"
-
#include "button.h"
#include "inttextfield.h"
+#include "item_amount.h"
#include "slider.h"
#include "trade.h"
diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp
index a0885279..e3ecdd4e 100644
--- a/src/gui/itemcontainer.cpp
+++ b/src/gui/itemcontainer.cpp
@@ -21,13 +21,18 @@
#include "itemcontainer.h"
+#include "itempopup.h"
+
#include <guichan/mouseinput.hpp>
#include <guichan/selectionlistener.hpp>
+#include <SDL_mouse.h>
+
#include "../graphics.h"
#include "../inventory.h"
#include "../item.h"
#include "../itemshortcut.h"
+#include "../localplayer.h"
#include "../log.h"
#include "../resources/image.h"
@@ -41,11 +46,14 @@ const int ItemContainer::gridHeight = 42; // item icon height + 10
static const int NO_ITEM = -1;
-ItemContainer::ItemContainer(Inventory *inventory):
+ItemContainer::ItemContainer(Inventory *inventory, int offset):
mInventory(inventory),
mSelectedItemIndex(NO_ITEM),
- mLastSelectedItemId(NO_ITEM)
+ mLastSelectedItemId(NO_ITEM),
+ mOffset(offset)
{
+ mItemPopup = new ItemPopup();
+
ResourceManager *resman = ResourceManager::getInstance();
mSelImg = resman->getImage("graphics/gui/selection.png");
@@ -86,10 +94,11 @@ void ItemContainer::draw(gcn::Graphics *graphics)
}
/*
- * eAthena seems to start inventory from the 3rd slot. Still a mystery to
- * us why, make sure not to copy this oddity to our own server.
+ * mOffset is used to compensate for some weirdness that eAthena inherited from
+ * Ragnarok Online. Inventory slots and cart slots are +2 from their actual index,
+ * while storage slots are +1.
*/
- for (int i = 2; i < INVENTORY_SIZE; i++)
+ for (int i = mOffset; i < mInventory->getSize(); i++)
{
Item *item = mInventory->getItem(i);
@@ -138,6 +147,7 @@ void ItemContainer::recalculateHeight()
const int rows = (mMaxItems / cols) + (mMaxItems % cols > 0 ? 1 : 0);
const int height = rows * gridHeight + 8;
+
if (height != getHeight())
setHeight(height);
}
@@ -159,8 +169,8 @@ void ItemContainer::selectNone()
void ItemContainer::refindSelectedItem()
{
- if (mSelectedItemIndex != NO_ITEM) {
-
+ if (mSelectedItemIndex != NO_ITEM)
+ {
if (mInventory->getItem(mSelectedItemIndex) &&
mInventory->getItem(mSelectedItemIndex)->getId() == mLastSelectedItemId)
return; // we're already fine
@@ -170,7 +180,8 @@ void ItemContainer::refindSelectedItem()
for (int i = 0; i <= mMaxItems + 1; i++)
if (mInventory->getItem(i) &&
- mInventory->getItem(i)->getId() == mLastSelectedItemId) {
+ mInventory->getItem(i)->getId() == mLastSelectedItemId)
+ {
mSelectedItemIndex = i;
return;
}
@@ -179,14 +190,16 @@ void ItemContainer::refindSelectedItem()
mLastSelectedItemId = mSelectedItemIndex = NO_ITEM;
}
-
void ItemContainer::setSelectedItemIndex(int index)
{
int newSelectedItemIndex;
- // mMaxItems is broken because of eAthena's odd inventory layout and the client's refusal
- // to handle it properly, so we work around the issue right here.
- if (index < 0 || index > mMaxItems + 1 || mInventory->getItem(index) == NULL)
+ /*
+ * mOffset is used to compensate for some weirdness that eAthena inherited from
+ * Ragnarok Online. Inventory slots and cart slots are +2 from their actual index,
+ * while storage slots are +1.
+ */
+ if (index < 0 || index > mMaxItems + mOffset || mInventory->getItem(index) == NULL)
newSelectedItemIndex = NO_ITEM;
else
newSelectedItemIndex = index;
@@ -218,14 +231,14 @@ void ItemContainer::distributeValueChangedEvent()
void ItemContainer::mousePressed(gcn::MouseEvent &event)
{
- int button = event.getButton();
+ const int button = event.getButton();
if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT)
{
int columns = getWidth() / gridWidth;
int mx = event.getX();
int my = event.getY();
- int index = mx / gridWidth + ((my / gridHeight) * columns) + 2;
+ int index = mx / gridWidth + ((my / gridHeight) * columns) + mOffset;
itemShortcut->setItemSelected(-1);
setSelectedItemIndex(index);
@@ -236,3 +249,38 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event)
itemShortcut->setItemSelected(item->getId());
}
}
+
+// Show ItemTooltip
+void ItemContainer::mouseMoved(gcn::MouseEvent &event)
+{
+ Item *item = mInventory->getItem(getSlotIndex(event.getX(), event.getY()));
+
+ if (item)
+ {
+ int mouseX, mouseY;
+ SDL_GetMouseState(&mouseX, &mouseY);
+
+ mItemPopup->setItem(item->getInfo());
+ mItemPopup->setOpaque(false);
+ mItemPopup->view(mouseX, mouseY);
+ }
+ else
+ {
+ mItemPopup->setVisible(false);
+ }
+}
+
+// Hide ItemTooltip
+void ItemContainer::mouseExited(gcn::MouseEvent &event)
+{
+ mItemPopup->setVisible(false);
+}
+
+int ItemContainer::getSlotIndex(const int posX, const int posY) const
+{
+ int columns = getWidth() / gridWidth;
+ int index = posX / gridWidth + ((posY / gridHeight) * columns) + mOffset;
+
+ return (index);
+}
+
diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h
index a40237af..1fa76343 100644
--- a/src/gui/itemcontainer.h
+++ b/src/gui/itemcontainer.h
@@ -22,15 +22,18 @@
#ifndef ITEMCONTAINER_H
#define ITEMCONTAINER_H
+#include <list>
+
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
#include <guichan/widgetlistener.hpp>
-#include <list>
+#include "../guichanfwd.h"
class Image;
class Inventory;
class Item;
+class ItemPopup;
namespace gcn {
class SelectionListener;
@@ -41,14 +44,15 @@ namespace gcn {
*
* \ingroup GUI
*/
-class ItemContainer : public gcn::Widget, public gcn::MouseListener,
- public gcn::WidgetListener
+class ItemContainer : public gcn::Widget,
+ public gcn::MouseListener,
+ public gcn::WidgetListener
{
public:
/**
* Constructor. Initializes the graphic.
*/
- ItemContainer(Inventory *inventory);
+ ItemContainer(Inventory *inventory, int offset);
/**
* Destructor.
@@ -104,7 +108,11 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener,
}
private:
+ void mouseExited(gcn::MouseEvent &event);
+ void mouseMoved(gcn::MouseEvent &event);
+
/**
+
* Sets the currently selected item. Invalid (e.g., negative) indices set `no item'.
*/
void setSelectedItemIndex(int index);
@@ -124,12 +132,24 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener,
*/
void distributeValueChangedEvent();
+ /**
+ * Gets the slot index based on the cursor position.
+ *
+ * @param posX The X Coordinate position.
+ * @param posY The Y Coordinate position.
+ * @return The slot index on success, -1 on failure.
+ */
+ int getSlotIndex(const int posX, const int posY) const;
+
Inventory *mInventory;
Image *mSelImg;
- int mSelectedItemIndex;
- int mLastSelectedItemId; // last selected item ID. If we lose the item, find again by ID.
+ int mSelectedItemIndex;
+ int mLastSelectedItemId; // last selected item ID. If we lose the item, find again by ID.
int mMaxItems;
+ int mOffset;
+
+ ItemPopup *mItemPopup;
std::list<gcn::SelectionListener*> mListeners;
diff --git a/src/gui/itemlinkhandler.cpp b/src/gui/itemlinkhandler.cpp
new file mode 100644
index 00000000..34c12a0c
--- /dev/null
+++ b/src/gui/itemlinkhandler.cpp
@@ -0,0 +1,63 @@
+/*
+ * The Mana World
+ * Copyright 2009 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <SDL_mouse.h>
+
+#include "itemlinkhandler.h"
+#include "itempopup.h"
+
+#include "../resources/iteminfo.h"
+#include "../resources/itemdb.h"
+
+#include <sstream>
+#include <string>
+
+ItemLinkHandler::ItemLinkHandler()
+{
+ mItemPopup = new ItemPopup;
+}
+
+ItemLinkHandler::~ItemLinkHandler()
+{
+ delete mItemPopup;
+}
+
+void ItemLinkHandler::handleLink(const std::string &link)
+{
+ int id = 0;
+ std::stringstream stream;
+ stream << link;
+ stream >> id;
+ if (id > 0)
+ {
+ const ItemInfo &iteminfo = ItemDB::get(id);
+ int mouseX, mouseY;
+
+ SDL_GetMouseState(&mouseX, &mouseY);
+
+ mItemPopup->setItem(iteminfo);
+
+ if (mItemPopup->isVisible())
+ mItemPopup->setVisible(false);
+ else
+ mItemPopup->view(mouseX, mouseY);
+ }
+}
diff --git a/src/gui/itemlinkhandler.h b/src/gui/itemlinkhandler.h
new file mode 100644
index 00000000..cd6fd900
--- /dev/null
+++ b/src/gui/itemlinkhandler.h
@@ -0,0 +1,40 @@
+/*
+ * The Mana World
+ * Copyright 2009 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef ITEM_LINK_HANDLER_H_
+#define ITEM_LINK_HANDLER_H_
+
+#include "linkhandler.h"
+
+class ItemPopup;
+
+class ItemLinkHandler : public LinkHandler
+{
+ public:
+ ItemLinkHandler();
+ ~ItemLinkHandler();
+ void handleLink(const std::string &link);
+
+ private:
+ ItemPopup *mItemPopup;
+};
+
+#endif
diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp
new file mode 100644
index 00000000..8235d640
--- /dev/null
+++ b/src/gui/itempopup.cpp
@@ -0,0 +1,176 @@
+/*
+ * The Mana World
+ * Copyright (C) 2008 The Legend of Mazzeroth Development Team
+ * Copyright (C) 2008 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/font.hpp>
+
+#include <guichan/widgets/label.hpp>
+
+#include "gui.h"
+#include "itempopup.h"
+#include "windowcontainer.h"
+
+#include "widgets/layout.h"
+
+#include "../resources/image.h"
+#include "../resources/iteminfo.h"
+#include "../resources/resourcemanager.h"
+
+#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
+#include "../utils/tostring.h"
+
+ItemPopup::ItemPopup():
+ Window()
+{
+ setResizable(false);
+ setShowTitle(false);
+ setTitleBarHeight(0);
+
+ // Item Name
+ mItemName = new gcn::Label("Label");
+ mItemName->setFont(gui->getFont());
+ mItemName->setPosition(2, 2);
+ mItemName->setWidth(getWidth() - 4);
+ mItemName->setFont(boldFont);
+
+ // Item Description
+ mItemDesc = new TextBox();
+ mItemDesc->setEditable(false);
+ mItemDesc->setMinWidth(186);
+ mItemDesc->setTextWrapped("");
+ mItemDescScroll = new ScrollArea(mItemDesc);
+
+ mItemDescScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemDescScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemDescScroll->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight()));
+ mItemDescScroll->setOpaque(false);
+ mItemDescScroll->setPosition(2, getFont()->getHeight());
+
+ // Item Effect
+ mItemEffect = new TextBox();
+ mItemEffect->setEditable(false);
+ mItemEffect->setMinWidth(186);
+ mItemEffect->setTextWrapped("");
+ mItemEffectScroll = new ScrollArea(mItemEffect);
+
+ mItemEffectScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemEffectScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemEffectScroll->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight()));
+ mItemEffectScroll->setOpaque(false);
+ mItemEffectScroll->setPosition(2, (2 * getFont()->getHeight()) + 5);
+
+ // Item Weight
+ mItemWeight = new TextBox();
+ mItemWeight->setEditable(false);
+ mItemWeight->setMinWidth(186);
+ mItemWeight->setTextWrapped("");
+ mItemWeightScroll = new ScrollArea(mItemWeight);
+
+ mItemWeightScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemWeightScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mItemWeightScroll->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight()));
+ mItemWeightScroll->setOpaque(false);
+ mItemWeightScroll->setPosition(2, (3 * getFont()->getHeight()) + 10);
+
+ add(mItemName);
+ add(mItemDescScroll);
+ add(mItemEffectScroll);
+ add(mItemWeightScroll);
+
+ setLocationRelativeTo(getParent());
+
+ // LEEOR / TODO: This causes an exception error.
+ //moveToBottom(getParent());
+}
+
+void ItemPopup::setItem(const ItemInfo &item)
+{
+ const gcn::Rectangle &area = getChildrenArea();
+ const int width = area.width;
+
+ mItemDesc->setMinWidth(width - 10);
+ mItemEffect->setMinWidth(width - 10);
+ mItemWeight->setMinWidth(width - 10);
+
+ mItemName->setCaption(item.getName());
+ mItemDesc->setTextWrapped(item.getDescription());
+ mItemEffect->setTextWrapped(item.getEffect());
+ mItemWeight->setTextWrapped(_("Weight: ") + toString(item.getWeight()) +
+ _(" grams"));
+
+ int numRowsDesc = mItemDesc->getNumberOfRows();
+ int numRowsEffect = mItemEffect->getNumberOfRows();
+ int numRowsWeight = mItemWeight->getNumberOfRows();
+
+ mItemDescScroll->setDimension(gcn::Rectangle(2, 0, 196,
+ numRowsDesc * getFont()->getHeight()));
+
+ mItemEffectScroll->setDimension(gcn::Rectangle(2, 0, 196,
+ numRowsEffect * getFont()->getHeight()));
+
+ mItemWeightScroll->setDimension(gcn::Rectangle(2, 0, 196,
+ numRowsWeight * getFont()->getHeight()));
+
+ if(item.getEffect() == "")
+ {
+ setContentSize(200, (numRowsDesc * getFont()->getHeight() +
+ (3 * getFont()->getHeight())));
+
+ mItemWeightScroll->setPosition(2,
+ (numRowsDesc * getFont()->getHeight()) +
+ (2 * getFont()->getHeight()));
+ }
+ else
+ {
+ setContentSize(200, (numRowsDesc * getFont()->getHeight()) +
+ (numRowsEffect * getFont()->getHeight()) +
+ (3 * getFont()->getHeight()));
+
+ mItemWeightScroll->setPosition(2,
+ (numRowsDesc * getFont()->getHeight()) +
+ (numRowsEffect * getFont()->getHeight()) +
+ (2 * getFont()->getHeight()));
+ }
+
+ mItemDescScroll->setPosition(2, 20);
+ mItemEffectScroll->setPosition(2, (numRowsDesc * getFont()->getHeight()) +
+ (2 * getFont()->getHeight()));
+}
+
+unsigned int ItemPopup::getNumRows()
+{
+ return mItemDesc->getNumberOfRows() + mItemEffect->getNumberOfRows() +
+ mItemWeight->getNumberOfRows();
+}
+
+void ItemPopup::view(int x, int y)
+{
+ if (windowContainer->getWidth() < (x + getWidth() + 5))
+ x = windowContainer->getWidth() - getWidth();
+ if ((y - getHeight() - 5) < 0)
+ y = 0;
+ else
+ y = y - getHeight() - 5;
+ setPosition(x, y);
+ setVisible(true);
+ requestMoveToTop();
+}
diff --git a/src/gui/buddywindow.h b/src/gui/itempopup.h
index 4eed3a2c..b6120af8 100644
--- a/src/gui/buddywindow.h
+++ b/src/gui/itempopup.h
@@ -1,6 +1,7 @@
/*
* The Mana World
- * Copyright (C) 2004 The Mana World Development Team
+ * Copyright (C) 2008 The Legend of Mazzeroth Development Team
+ * Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
*
@@ -19,38 +20,32 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef BUDDYWINDOW_H
-#define BUDDYWINDOW_H
-
-#include <guichan/actionlistener.hpp>
+#ifndef ITEMPOPUP_H__
+#define ITEMPOPUP_H__
+#include "scrollarea.h"
+#include "textbox.h"
#include "window.h"
-#include "../guichanfwd.h"
-
-class BuddyList;
+#include "../item.h"
-/**
- * Window showing buddy list.
- *
- * \ingroup Interface
- */
-class BuddyWindow : public Window, public gcn::ActionListener
+class ItemPopup : public Window
{
public:
- /**
- * Constructor.
- */
- BuddyWindow();
+ ItemPopup();
- /**
- * Performs action.
- */
- void action(const gcn::ActionEvent &event);
+ void setItem(const ItemInfo &item);
+ unsigned int getNumRows();
+ void view(int x, int y);
private:
- BuddyList *mBuddyList;
- gcn::ListBox *mListbox;
+ gcn::Label *mItemName;
+ TextBox *mItemDesc;
+ TextBox *mItemEffect;
+ TextBox *mItemWeight;
+ ScrollArea *mItemDescScroll;
+ ScrollArea *mItemEffectScroll;
+ ScrollArea *mItemWeightScroll;
};
-#endif /* BUDDYWINDOW_H */
+#endif // ITEMPOPUP_H__
diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp
index b2f70348..3735afe2 100644
--- a/src/gui/itemshortcutcontainer.cpp
+++ b/src/gui/itemshortcutcontainer.cpp
@@ -18,15 +18,20 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <SDL_mouse.h>
+#include "gui.h"
#include "itemshortcutcontainer.h"
+#include "itempopup.h"
+#include "viewport.h"
-#include "../localplayer.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../inventory.h"
#include "../item.h"
#include "../itemshortcut.h"
#include "../keyboardconfig.h"
+#include "../localplayer.h"
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
@@ -34,21 +39,25 @@
#include "../utils/tostring.h"
ItemShortcutContainer::ItemShortcutContainer():
- mGridWidth(1),
- mGridHeight(1),
mItemClicked(false),
mItemMoved(NULL)
{
+ mGridWidth=1;
+ mGridHeight=1;
addMouseListener(this);
addWidgetListener(this);
+ mItemPopup = new ItemPopup();
+
ResourceManager *resman = ResourceManager::getInstance();
mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png");
mMaxItems = itemShortcut->getItemCount();
- mBoxHeight = 42;
- mBoxWidth = 36;
+ mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8));
+
+ mBoxHeight = mBackgroundImg->getHeight();
+ mBoxWidth = mBackgroundImg->getWidth();
}
ItemShortcutContainer::~ItemShortcutContainer()
@@ -56,8 +65,7 @@ ItemShortcutContainer::~ItemShortcutContainer()
mBackgroundImg->decRef();
}
-void
-ItemShortcutContainer::logic()
+void ItemShortcutContainer::logic()
{
gcn::Widget::logic();
@@ -70,8 +78,7 @@ ItemShortcutContainer::logic()
}
}
-void
-ItemShortcutContainer::draw(gcn::Graphics *graphics)
+void ItemShortcutContainer::draw(gcn::Graphics *graphics)
{
Graphics *g = static_cast<Graphics*>(graphics);
@@ -87,7 +94,8 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics)
// Draw item keyboard shortcut.
const char *key = SDL_GetKeyName(
- (SDLKey) keyboard.getKeyValue(keyboard.KEY_SHORTCUT_0 + i));
+ (SDLKey) keyboard.getKeyValue(keyboard.KEY_SHORTCUT_1 + i));
+ graphics->setColor(0x000000);
g->drawText(key, itemX + 2, itemY + 2, gcn::Graphics::LEFT);
if (itemShortcut->getItem(i) < 0)
@@ -97,6 +105,8 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics)
player_node->getInventory()->findItem(itemShortcut->getItem(i));
if (item) {
// Draw item icon.
+ const std::string label =
+ item->isEquipped() ? "Eq." : toString(item->getQuantity());
Image* image = item->getImage();
if (image) {
const std::string label =
@@ -129,35 +139,23 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics)
}
}
-void ItemShortcutContainer::widgetResized(const gcn::Event &event)
+void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
{
- mGridWidth = getWidth() / mBoxWidth;
- if (mGridWidth < 1) {
- mGridWidth = 1;
- }
-
- setHeight((mMaxItems / mGridWidth +
- (mMaxItems % mGridWidth > 0 ? 1 : 0)) * mBoxHeight);
-
- mGridHeight = getHeight() / mBoxHeight;
- if (mGridHeight < 1) {
- mGridHeight = 1;
- }
-}
-
-void
-ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
-{
- if (event.getButton() == gcn::MouseEvent::LEFT) {
- if (!mItemMoved && mItemClicked) {
+ if (event.getButton() == gcn::MouseEvent::LEFT)
+ {
+ if (!mItemMoved && mItemClicked)
+ {
const int index = getIndexFromGrid(event.getX(), event.getY());
- if (index == -1) {
- return;
- }
const int itemId = itemShortcut->getItem(index);
+
+ if (index == -1)
+ return;
+
if (itemId < 0)
return;
+
Item *item = player_node->getInventory()->findItem(itemId);
+
if (item)
{
mItemMoved = item;
@@ -171,39 +169,56 @@ ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
}
}
-void
-ItemShortcutContainer::mousePressed(gcn::MouseEvent &event)
+void ItemShortcutContainer::mousePressed(gcn::MouseEvent &event)
{
const int index = getIndexFromGrid(event.getX(), event.getY());
- if (index == -1) {
+ if (index == -1)
return;
- }
- // Stores the selected item if theirs one.
- if (itemShortcut->isItemSelected()) {
- itemShortcut->setItem(index);
- itemShortcut->setItemSelected(-1);
+ if (event.getButton() == gcn::MouseEvent::LEFT)
+ {
+
+ // Stores the selected item if theirs one.
+ if (itemShortcut->isItemSelected())
+ {
+ itemShortcut->setItem(index);
+ itemShortcut->setItemSelected(-1);
+ }
+ else if (itemShortcut->getItem(index))
+ mItemClicked = true;
}
- else if (itemShortcut->getItem(index)) {
- mItemClicked = true;
+ else if (event.getButton() == gcn::MouseEvent::RIGHT)
+ {
+ Item *item = player_node->getInventory()->
+ findItem(itemShortcut->getItem(index));
+
+ if (!item)
+ return;
+
+ /* Convert relative to the window coordinates to absolute screen
+ * coordinates.
+ */
+ int mx, my;
+ SDL_GetMouseState(&mx, &my);
+ viewport->showPopup(mx, my, item);
}
}
-void
-ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event)
+void ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event)
{
if (event.getButton() == gcn::MouseEvent::LEFT)
{
if (itemShortcut->isItemSelected())
- {
itemShortcut->setItemSelected(-1);
- }
+
const int index = getIndexFromGrid(event.getX(), event.getY());
- if (index == -1) {
+ if (index == -1)
+ {
mItemMoved = NULL;
return;
}
- if (mItemMoved) {
+ if (mItemMoved)
+ {
itemShortcut->setItems(index, mItemMoved->getId());
mItemMoved = NULL;
}
@@ -211,25 +226,43 @@ ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event)
{
itemShortcut->useItem(index);
}
- if (mItemClicked) {
+ if (mItemClicked)
mItemClicked = false;
- }
}
}
-int
-ItemShortcutContainer::getIndexFromGrid(int pointX, int pointY) const
+// Show ItemTooltip
+void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event)
{
- const gcn::Rectangle tRect = gcn::Rectangle(
- 0, 0, mGridWidth * mBoxWidth, mGridHeight * mBoxHeight);
- if (!tRect.isPointInRect(pointX, pointY)) {
- return -1;
+ const int index = getIndexFromGrid(event.getX(), event.getY());
+ const int itemId = itemShortcut->getItem(index);
+
+ if (index == -1)
+ return;
+
+ if (itemId < 0)
+ return;
+
+ Item *item = player_node->getInventory()->findItem(itemId);
+
+ if (item)
+ {
+ int mouseX, mouseY;
+ SDL_GetMouseState(&mouseX, &mouseY);
+
+ mItemPopup->setItem(item->getInfo());
+ mItemPopup->setOpaque(false);
+ mItemPopup->view(mouseX, mouseY);
}
- const int index = ((pointY / mBoxHeight) * mGridWidth) +
- pointX / mBoxWidth;
- if (index >= mMaxItems)
+ else
{
- return -1;
+ mItemPopup->setVisible(false);
}
- return index;
}
+
+// Hide ItemTooltip
+void ItemShortcutContainer::mouseExited(gcn::MouseEvent &event)
+{
+ mItemPopup->setVisible(false);
+}
+
diff --git a/src/gui/itemshortcutcontainer.h b/src/gui/itemshortcutcontainer.h
index cdaf6713..d6a04d7b 100644
--- a/src/gui/itemshortcutcontainer.h
+++ b/src/gui/itemshortcutcontainer.h
@@ -23,20 +23,21 @@
#define ITEMSHORTCUTCONTAINER_H
#include <guichan/mouselistener.hpp>
-#include <guichan/widget.hpp>
-#include <guichan/widgetlistener.hpp>
+
+#include "shortcutcontainer.h"
+
+#include "../guichanfwd.h"
class Image;
class Item;
+class ItemPopup;
/**
* An item shortcut container. Used to quickly use items.
*
* \ingroup GUI
*/
-class ItemShortcutContainer : public gcn::Widget,
- public gcn::WidgetListener,
- public gcn::MouseListener
+class ItemShortcutContainer : public ShortcutContainer
{
public:
/**
@@ -60,12 +61,6 @@ class ItemShortcutContainer : public gcn::Widget,
void draw(gcn::Graphics *graphics);
/**
- * Invoked when a widget changes its size. This is used to determine
- * the new height of the container.
- */
- void widgetResized(const gcn::Event &event);
-
- /**
* Handles mouse when dragged.
*/
void mouseDragged(gcn::MouseEvent &event);
@@ -80,34 +75,14 @@ class ItemShortcutContainer : public gcn::Widget,
*/
void mouseReleased(gcn::MouseEvent &event);
- int getMaxItems()
- { return mMaxItems; }
-
- int getBoxWidth()
- { return mBoxWidth; }
-
- int getBoxHeight()
- { return mBoxHeight; }
-
private:
- /**
- * Gets the index from the grid provided the point is in an item box.
- *
- * @param pointX X coordinate of the point.
- * @param pointY Y coordinate of the point.
- * @return index on success, -1 on failure.
- */
- int getIndexFromGrid(int pointX, int pointY) const;
-
- Image *mBackgroundImg;
+ void mouseExited(gcn::MouseEvent &event);
+ void mouseMoved(gcn::MouseEvent &event);
- int mMaxItems;
- int mBoxWidth;
- int mBoxHeight;
- int mCursorPosX, mCursorPosY;
- int mGridWidth, mGridHeight;
bool mItemClicked;
Item *mItemMoved;
+
+ ItemPopup *mItemPopup;
};
#endif
diff --git a/src/gui/listbox.cpp b/src/gui/listbox.cpp
index b72c64cf..990a0ade 100644
--- a/src/gui/listbox.cpp
+++ b/src/gui/listbox.cpp
@@ -19,13 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "listbox.h"
-
#include <guichan/font.hpp>
#include <guichan/graphics.hpp>
#include <guichan/listmodel.hpp>
#include <guichan/mouseinput.hpp>
+#include "listbox.h"
+
ListBox::ListBox(gcn::ListModel *listModel):
gcn::ListBox(listModel)
{
@@ -36,7 +36,7 @@ void ListBox::draw(gcn::Graphics *graphics)
if (!mListModel)
return;
- graphics->setColor(gcn::Color(110, 160, 255));
+ graphics->setColor(gcn::Color(235, 200, 115));
graphics->setFont(getFont());
int fontHeight = getFont()->getHeight();
@@ -57,8 +57,7 @@ void ListBox::draw(gcn::Graphics *graphics)
}
}
-void
-ListBox::mouseDragged(gcn::MouseEvent &event)
+void ListBox::mouseDragged(gcn::MouseEvent &event)
{
// Pretend mouse is pressed continuously while dragged. Causes list
// selection to be updated as is default in many GUIs.
diff --git a/src/gui/listbox.h b/src/gui/listbox.h
index 934ea82e..3d0062bc 100644
--- a/src/gui/listbox.h
+++ b/src/gui/listbox.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/listbox.hpp>
+#include "../guichanfwd.h"
+
class SelectionListener;
/**
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index 2b87f6df..8de2867c 100644
--- a/src/gui/login.cpp
+++ b/src/gui/login.cpp
@@ -19,24 +19,31 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "login.h"
-
#include <string>
+#include <vector>
#include <guichan/widgets/label.hpp>
-#include "../main.h"
-#include "../logindata.h"
-
#include "button.h"
#include "checkbox.h"
+#include "login.h"
#include "ok_dialog.h"
#include "passwordfield.h"
#include "textfield.h"
#include "widgets/layout.h"
+#include "../main.h"
+#include "../logindata.h"
+#include "../configuration.h"
+
#include "../utils/gettext.h"
+#include "../utils/tostring.h"
+
+static const int MAX_SERVER_LIST_SIZE = 5;
+static const int LOGIN_DIALOG_WIDTH = 220;
+static const int LOGIN_DIALOG_HEIGHT = 140;
+static const int FIELD_WIDTH = LOGIN_DIALOG_WIDTH - 70;
LoginDialog::LoginDialog(LoginData *loginData):
Window(_("Login")), mLoginData(loginData)
@@ -44,36 +51,64 @@ LoginDialog::LoginDialog(LoginData *loginData):
gcn::Label *userLabel = new gcn::Label(_("Name:"));
gcn::Label *passLabel = new gcn::Label(_("Password:"));
gcn::Label *serverLabel = new gcn::Label(_("Server:"));
+ gcn::Label *portLabel = new gcn::Label(_("Port:"));
+ gcn::Label *dropdownLabel = new gcn::Label(_("Recent:"));
+ std::vector<std::string> dfltServer;
+ dfltServer.push_back("server.themanaworld.org");
+ dfltServer.push_back("server.themanaworld.org");
+ std::vector<std::string> dfltPort;
+ dfltPort.push_back("21001");
+ dfltPort.push_back("22001");
+ dfltPort.push_back("21001");
+ mServerList = new DropDownList("MostRecent00", dfltServer, dfltPort,
+ MAX_SERVER_LIST_SIZE);
+ mServerListBox = new gcn::ListBox(mServerList);
+ mServerScrollArea = new ScrollArea();
+
mUserField = new TextField(mLoginData->username);
mPassField = new PasswordField(mLoginData->password);
- mServerField = new TextField(mLoginData->hostname);
+ mServerField = new TextField(mServerList->getServerAt(0));
+ mPortField = new TextField(mServerList->getPortAt(0));
+ mServerDropDown = new DropDown(mServerList,
+ mServerScrollArea,
+ mServerListBox);
+
mKeepCheck = new CheckBox(_("Remember Username"), mLoginData->remember);
- mOkButton = new Button(_("Ok"), "ok", this);
+ mOkButton = new Button(_("OK"), "ok", this);
mCancelButton = new Button(_("Cancel"), "cancel", this);
mRegisterButton = new Button(_("Register"), "register", this);
mUserField->setActionEventId("ok");
mPassField->setActionEventId("ok");
mServerField->setActionEventId("ok");
+ mServerDropDown->setActionEventId("changeSelection");
mUserField->addKeyListener(this);
mPassField->addKeyListener(this);
mServerField->addKeyListener(this);
+ mPortField->addKeyListener(this);
+ mServerDropDown->addKeyListener(this);
mUserField->addActionListener(this);
mPassField->addActionListener(this);
mServerField->addActionListener(this);
+ mPortField->addActionListener(this);
+ mServerDropDown->addActionListener(this);
mKeepCheck->addActionListener(this);
place(0, 0, userLabel);
place(0, 1, passLabel);
place(0, 2, serverLabel);
- place(1, 0, mUserField, 3).setPadding(2);
- place(1, 1, mPassField, 3).setPadding(2);
- place(1, 2, mServerField, 3).setPadding(2);
- place(0, 3, mKeepCheck, 4);
- place(0, 4, mRegisterButton).setHAlign(LayoutCell::LEFT);
- place(2, 4, mOkButton);
- place(3, 4, mCancelButton);
+ place(0, 3, portLabel);
+ place(0, 4, dropdownLabel);
+ place(1, 0, mUserField, 3).setPadding(1);
+ place(1, 1, mPassField, 3).setPadding(1);
+ place(1, 2, mServerField, 3).setPadding(1);
+ place(1, 3, mPortField, 3).setPadding(1);
+ place(1, 4, mServerDropDown, 3).setPadding(1);
+ place(0, 5, mKeepCheck, 4);
+ place(0, 6, mRegisterButton).setHAlign(LayoutCell::LEFT);
+ place(2, 6, mCancelButton);
+ place(3, 6, mOkButton);
reflowLayout(250, 0);
setLocationRelativeTo(getParent());
@@ -90,6 +125,9 @@ LoginDialog::LoginDialog(LoginData *loginData):
LoginDialog::~LoginDialog()
{
+ delete mServerList;
+ delete mServerListBox;
+ delete mServerScrollArea;
}
void LoginDialog::action(const gcn::ActionEvent &event)
@@ -97,6 +135,7 @@ void LoginDialog::action(const gcn::ActionEvent &event)
if (event.getId() == "ok" && canSubmit())
{
mLoginData->hostname = mServerField->getText();
+ mLoginData->port = getUShort(mPortField->getText());
mLoginData->username = mUserField->getText();
mLoginData->password = mPassField->getText();
mLoginData->remember = mKeepCheck->isSelected();
@@ -104,9 +143,15 @@ void LoginDialog::action(const gcn::ActionEvent &event)
mOkButton->setEnabled(false);
mRegisterButton->setEnabled(false);
-
+ mServerList->save(mServerField->getText(), mPortField->getText());
state = ACCOUNT_STATE;
}
+ else if (event.getId() == "changeSelection")
+ {
+ int selected = mServerListBox->getSelected();
+ mServerField->setText(mServerList->getServerAt(selected));
+ mPortField->setText(mServerList->getPortAt(selected));
+ }
else if (event.getId() == "cancel")
{
state = EXIT_STATE;
@@ -115,6 +160,14 @@ void LoginDialog::action(const gcn::ActionEvent &event)
{
// Transfer these fields on to the register dialog
mLoginData->hostname = mServerField->getText();
+ if (isUShort(mPortField->getText()))
+ {
+ mLoginData->port = getUShort(mPortField->getText());
+ }
+ else
+ {
+ mLoginData->port = 6901;
+ }
mLoginData->username = mUserField->getText();
mLoginData->password = mPassField->getText();
@@ -132,5 +185,138 @@ bool LoginDialog::canSubmit()
return !mUserField->getText().empty() &&
!mPassField->getText().empty() &&
!mServerField->getText().empty() &&
+ isUShort(mPortField->getText()) &&
state == LOGIN_STATE;
}
+
+bool LoginDialog::isUShort(const std::string &str)
+{
+ if (str == "")
+ {
+ return false;
+ }
+ unsigned long l = 0;
+ for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end();
+ strPtr != strEnd; ++strPtr)
+ {
+ if (*strPtr < '0' || *strPtr > '9')
+ {
+ return false;
+ }
+ l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative
+ if (l > 65535)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+unsigned short LoginDialog::getUShort(const std::string &str)
+{
+ unsigned long l = 0;
+ for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end();
+ strPtr != strEnd; ++strPtr)
+ {
+ l = l * 10 + (*strPtr - '0');
+ }
+ return static_cast<unsigned short>(l);
+}
+
+/**
+ * LoginDialog::DropDownList
+ */
+
+void LoginDialog::DropDownList::saveEntry(const std::string &server,
+ const std::string &port, int &saved)
+{
+ if (saved < MAX_SERVER_LIST_SIZE && server != "")
+ {
+ config.setValue(mConfigPrefix + "Server" + toString(saved), server);
+ config.setValue(mConfigPrefix + "Port" + toString(saved), port);
+ ++saved;
+ }
+}
+
+LoginDialog::DropDownList::DropDownList(std::string prefix,
+ std::vector<std::string> dflt,
+ std::vector<std::string> dfltPort,
+ int maxEntries) :
+ mConfigPrefix(prefix),
+ mMaxEntries(maxEntries)
+{
+ for (int i = 0; i < maxEntries; ++i)
+ {
+ std::string server = config.getValue(mConfigPrefix + "Server" +
+ toString(i), "");
+ if (server == "") // Just in case had original config entries
+ {
+ server = config.getValue(mConfigPrefix + "ServerList" +
+ toString(i), "");
+ }
+ std::string port = config.getValue(mConfigPrefix + "Port" +
+ toString(i), dfltPort.front());
+
+ if (server != "")
+ {
+ mServers.push_back(server);
+ mPorts.push_back(port);
+ }
+ }
+ if (mServers.size() == 0)
+ {
+ mServers.assign(dflt.begin(), dflt.end());
+ mPorts.assign(dfltPort.begin(), dfltPort.end());
+ }
+}
+
+void LoginDialog::DropDownList::save(const std::string &server,
+ const std::string &port)
+{
+ int position = 0;
+ saveEntry(server, port, position);
+ for (std::vector<std::string>::const_iterator sPtr = mServers.begin(),
+ sEnd = mServers.end(),
+ pPtr = mPorts.begin(),
+ pEnd = mPorts.end();
+ sPtr != sEnd && pPtr != pEnd;
+ ++sPtr, ++pPtr)
+ {
+ if (*sPtr != server || *pPtr != port)
+ {
+ saveEntry(*sPtr, *pPtr, position);
+ }
+ }
+}
+
+int LoginDialog::DropDownList::getNumberOfElements()
+{
+ return mServers.size();
+}
+
+std::string LoginDialog::DropDownList::getElementAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return getServerAt(i) + ":" + getPortAt(i);
+}
+
+std::string LoginDialog::DropDownList::getServerAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return mServers.at(i);
+}
+
+std::string LoginDialog::DropDownList::getPortAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return mPorts.at(i);
+}
diff --git a/src/gui/login.h b/src/gui/login.h
index 7dd59a96..b85e5ae1 100644
--- a/src/gui/login.h
+++ b/src/gui/login.h
@@ -23,10 +23,17 @@
#define LOGIN_H
#include <iosfwd>
+#include <string>
+#include <vector>
+
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
+#include "scrollarea.h"
#include "window.h"
+
+#include "widgets/dropdown.h"
+
#include "../guichanfwd.h"
class LoginData;
@@ -67,18 +74,66 @@ class LoginDialog : public Window, public gcn::ActionListener,
* Returns whether submit can be enabled. This is true in the login
* state, when all necessary fields have some text.
*/
- bool
- canSubmit();
+ bool canSubmit();
+
+ /**
+ * Function to decide whether string is an unsigned short or not
+ *
+ * @param str the string to parse
+ *
+ * @return true is str is an unsigned short, false otherwise
+ */
+ static bool isUShort(const std::string &str);
+
+ /**
+ * Converts string to an unsigned short (undefined if invalid)
+ *
+ * @param str the string to parse
+ *
+ * @return the value str represents
+ */
+ static unsigned short getUShort(const std::string &str);
+ DropDown *mServerDropDown;
gcn::TextField *mUserField;
gcn::TextField *mPassField;
gcn::TextField *mServerField;
+ gcn::TextField *mPortField;
gcn::CheckBox *mKeepCheck;
gcn::Button *mOkButton;
gcn::Button *mCancelButton;
gcn::Button *mRegisterButton;
LoginData *mLoginData;
+
+ /**
+ * Helper class to keep a list of all the recent entries for the
+ * dropdown
+ */
+ class DropDownList : public gcn::ListModel
+ {
+ private:
+ std::vector<std::string> mServers;
+ std::vector<std::string> mPorts;
+ std::string mConfigPrefix;
+ int mMaxEntries;
+ void saveEntry(const std::string &server,
+ const std::string &port, int &saved);
+ public:
+ DropDownList(std::string prefix,
+ std::vector<std::string> dfltServer,
+ std::vector<std::string> dfltPort,
+ int maxEntries);
+ void save(const std::string &server, const std::string &port);
+ int getNumberOfElements();
+ std::string getElementAt(int i);
+ std::string getServerAt(int i);
+ std::string getPortAt(int i);
+ };
+ DropDownList *mServerList;
+ gcn::ListBox *mServerListBox;
+ ScrollArea *mServerScrollArea;
+
};
#endif
diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp
index e19cc3e8..0dcc999f 100644
--- a/src/gui/menuwindow.cpp
+++ b/src/gui/menuwindow.cpp
@@ -19,23 +19,24 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "menuwindow.h"
-
#include <string>
#include <guichan/actionlistener.hpp>
#include "button.h"
+#include "menuwindow.h"
#include "windowcontainer.h"
#include "../utils/gettext.h"
-extern Window *setupWindow;
-extern Window *inventoryWindow;
+extern Window *chatWindow;
extern Window *equipmentWindow;
+extern Window *inventoryWindow;
+extern Window *itemShortcutWindow;
+extern Window *emoteWindow;
+extern Window *setupWindow;
extern Window *skillDialog;
extern Window *statusWindow;
-extern Window *itemShortcutWindow;
namespace {
struct MenuWindowListener : public gcn::ActionListener
@@ -58,12 +59,14 @@ MenuWindow::MenuWindow():
// Buttons
static const char *buttonNames[] =
{
- N_("Status"),
- N_("Equipment"),
- N_("Inventory"),
- N_("Skills"),
- N_("Shortcut"),
- N_("Setup"),
+ _("Chat"),
+ _("Status"),
+ _("Equipment"),
+ _("Inventory"),
+ _("Skills"),
+ _("Shortcut"),
+ _("Emote"),
+ _("Setup"),
0
};
int x = 0, h = 0;
@@ -91,27 +94,35 @@ void MenuWindowListener::action(const gcn::ActionEvent &event)
{
Window *window = NULL;
- if (event.getId() == "Status")
+ if (event.getId() == _("Chat"))
+ {
+ window = chatWindow;
+ }
+ else if (event.getId() == _("Status"))
{
window = statusWindow;
}
- else if (event.getId() == "Equipment")
+ else if (event.getId() == _("Equipment"))
{
window = equipmentWindow;
}
- else if (event.getId() == "Inventory")
+ else if (event.getId() == _("Inventory"))
{
window = inventoryWindow;
}
- else if (event.getId() == "Skills")
+ else if (event.getId() == _("Skills"))
{
window = skillDialog;
}
- else if (event.getId() == "Shortcut")
+ else if (event.getId() == _("Shortcut"))
{
window = itemShortcutWindow;
}
- else if (event.getId() == "Setup")
+ else if (event.getId() == _("Emote"))
+ {
+ window = emoteWindow;
+ }
+ else if (event.getId() == _("Setup"))
{
window = setupWindow;
}
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index f5c0c1e6..7802b583 100644
--- a/src/gui/minimap.cpp
+++ b/src/gui/minimap.cpp
@@ -19,10 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <guichan/font.hpp>
+
#include "minimap.h"
#include "../being.h"
#include "../beingmanager.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../localplayer.h"
@@ -30,13 +33,17 @@
#include "../utils/gettext.h"
+bool Minimap::mShow = true;
+
Minimap::Minimap():
Window(_("MiniMap")),
- mMapImage(NULL)
+ mMapImage(NULL),
+ mProportion(0.5)
{
- setWindowName("MiniMap");
+ setWindowName(_("MiniMap"));
+ mShow = config.getValue(getWindowName() + "Visible", true);
setDefaultSize(5, 25, 100, 100);
- loadWindowState();
+ setResizable(true);
}
Minimap::~Minimap()
@@ -53,13 +60,57 @@ void Minimap::setMapImage(Image *img)
mMapImage = img;
if (mMapImage)
- mMapImage->setAlpha(0.7);
+ {
+ const int offsetX = 2 * getPadding();
+ const int offsetY = getTitleBarHeight() + getPadding();
+ const int titleWidth = getFont()->getWidth(getCaption()) + 15;
+ const int mapWidth = mMapImage->getWidth() < 100 ?
+ mMapImage->getWidth() + offsetX : 100;
+ const int mapHeight = mMapImage->getHeight() < 100 ?
+ mMapImage->getHeight() + offsetY : 100;
+
+ setMinWidth(mapWidth > titleWidth ? mapWidth : titleWidth);
+ setMinHeight(mapHeight);
+ setMaxWidth(mMapImage->getWidth() + offsetX);
+ setMaxHeight(mMapImage->getHeight() + offsetY);
+
+ mMapImage->setAlpha(config.getValue("guialpha", 0.8));
+
+ // Set content size to be within the minimum and maximum boundaries
+ setWidth(getMinWidth() < getWidth() ? getWidth() : getMinWidth());
+ if (getMaxWidth() > getWidth())
+ setWidth(getMaxWidth());
+ setHeight(getMinHeight() < getHeight() ? getHeight() : getMinHeight());
+ if (getMaxHeight() > getHeight())
+ setHeight(getMaxHeight());
+
+ setDefaultSize(getX(), getY(), getWidth(), getHeight());
+ resetToDefaultSize();
+
+ loadWindowState();
+ setVisible(mShow);
+ }
+ else
+ {
+ setVisible(false);
+ }
+}
+
+void Minimap::toggle()
+{
+ mShow = !mShow;
+ config.setValue(getWindowName() + "Visible", mShow);
}
void Minimap::draw(gcn::Graphics *graphics)
{
+ setVisible(mShow);
+
Window::draw(graphics);
+ if (!mShow)
+ return;
+
const gcn::Rectangle a = getChildrenArea();
graphics->pushClipArea(a);
@@ -72,8 +123,8 @@ void Minimap::draw(gcn::Graphics *graphics)
if (mMapImage->getWidth() > a.width ||
mMapImage->getHeight() > a.height)
{
- mapOriginX = (a.width - player_node->mX) / 2;
- mapOriginY = (a.height - player_node->mY) / 2;
+ mapOriginX = (int) (((a.width) / 2) - (player_node->mX * mProportion));
+ mapOriginY = (int) (((a.height) / 2) - (player_node->mY * mProportion));
const int minOriginX = a.width - mMapImage->getWidth();
const int minOriginY = a.height - mMapImage->getHeight();
@@ -87,6 +138,7 @@ void Minimap::draw(gcn::Graphics *graphics)
if (mapOriginY > 0)
mapOriginY = 0;
}
+
static_cast<Graphics*>(graphics)->
drawImage(mMapImage, mapOriginX, mapOriginY);
}
@@ -122,10 +174,11 @@ void Minimap::draw(gcn::Graphics *graphics)
continue;
}
- const int offset = (dotSize - 1) / 2;
+ const int offset = (int) ((dotSize - 1) * mProportion);
+
graphics->fillRectangle(gcn::Rectangle(
- being->mX / 2 + mapOriginX - offset,
- being->mY / 2 + mapOriginY - offset,
+ (int) (being->mX * mProportion) + mapOriginX - offset,
+ (int) (being->mY * mProportion) + mapOriginY - offset,
dotSize, dotSize));
}
diff --git a/src/gui/minimap.h b/src/gui/minimap.h
index 67f5eb18..b4574ad5 100644
--- a/src/gui/minimap.h
+++ b/src/gui/minimap.h
@@ -24,6 +24,8 @@
#include "window.h"
+#include "../guichanfwd.h"
+
class Image;
/**
@@ -50,12 +52,24 @@ class Minimap : public Window
void setMapImage(Image *img);
/**
+ * Sets the map proportion (1 means 1 tile to one pixel, .5 means 2 tiles to 1 pixel, etc.)
+ */
+ void setProportion(float proportion) { mProportion = proportion; }
+
+ /**
+ * Toggles the displaying of the minimap.
+ */
+ void toggle();
+
+ /**
* Draws the minimap.
*/
void draw(gcn::Graphics *graphics);
private:
Image *mMapImage;
+ float mProportion;
+ static bool mShow;
};
extern Minimap *minimap;
diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp
index e613a745..915db961 100644
--- a/src/gui/ministatus.cpp
+++ b/src/gui/ministatus.cpp
@@ -19,14 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "ministatus.h"
-
#include "gui.h"
+#include "ministatus.h"
#include "progressbar.h"
-#include "../localplayer.h"
#include "../configuration.h"
#include "../graphics.h"
+#include "../localplayer.h"
#include "../utils/tostring.h"
@@ -90,24 +89,22 @@ void MiniStatusWindow::update()
mHpBar->setColor(0, 171, 34); // Green
}
+ float xp = (float) player_node->getXp() / player_node->mXpForNextLevel;
+
+ if (xp != xp) xp = 0.0f; // check for NaN
+ if (xp < 0.0f) xp = 0.0f; // make sure the experience isn't negative (uninitialized pointer most likely)
+ if (xp > 1.0f) xp = 1.0f;
+
mHpBar->setProgress((float) player_node->mHp / player_node->mMaxHp);
mMpBar->setProgress((float) player_node->mMp / player_node->mMaxMp);
- if (player_node->MATK <= 0)
- mMpBar->setColor(100, 100, 100); // grey, to indicate that we lack magic
- else
- mMpBar->setColor(26, 102, 230); // blue, to indicate that we have magic
-
- mXpBar->setProgress(
- (float) player_node->getXp() / player_node->mXpForNextLevel);
+ mXpBar->setProgress(xp);
// Update labels
mHpBar->setText(toString(player_node->mHp));
mMpBar->setText(toString(player_node->mMp));
std::stringstream updatedText;
- updatedText << (int) (
- (float) player_node->getXp() /
- player_node->mXpForNextLevel * 100) << "%";
+ updatedText << (float) ((int) (xp * 10000.0f)) / 100.0f << "%";
// Displays the number of monsters to next lvl
// (disabled for now but interesting idea)
diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp
index 6ad698bc..a2e043d1 100644
--- a/src/gui/npc_text.cpp
+++ b/src/gui/npc_text.cpp
@@ -19,14 +19,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npc_text.h"
-
#include <string>
+#include "npc_text.h"
#include "browserbox.h"
#include "button.h"
#include "scrollarea.h"
+#include "widgets/layout.h"
+
#include "../npc.h"
#include "../utils/gettext.h"
@@ -39,24 +40,24 @@ NpcTextDialog::NpcTextDialog():
setMinWidth(200);
setMinHeight(150);
+ setDefaultSize(0, 0, 260, 200);
+
mBrowserBox = new BrowserBox(BrowserBox::AUTO_WRAP);
- mBrowserBox->setOpaque(true);
+ mBrowserBox->setOpaque(false);
scrollArea = new ScrollArea(mBrowserBox);
okButton = new Button(_("OK"), "ok", this);
- setContentSize(260, 175);
scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
scrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS);
- scrollArea->setDimension(gcn::Rectangle(
- 5, 5, 250, 160 - okButton->getHeight()));
- okButton->setPosition(
- 260 - 5 - okButton->getWidth(),
- 175 - 5 - okButton->getHeight());
- add(scrollArea);
- add(okButton);
+ place(0, 0, scrollArea, 5).setPadding(3);
+ place(4, 1, okButton);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
+ loadWindowState();
setLocationRelativeTo(getParent());
}
@@ -76,21 +77,6 @@ void NpcTextDialog::addText(const std::string &text)
mBrowserBox->addRow(text);
}
-void NpcTextDialog::widgetResized(const gcn::Event &event)
-{
- Window::widgetResized(event);
-
- const gcn::Rectangle &area = getChildrenArea();
- const int width = area.width;
- const int height = area.height;
-
- scrollArea->setDimension(gcn::Rectangle(
- 5, 5, width - 10, height - 15 - okButton->getHeight()));
- okButton->setPosition(
- width - 5 - okButton->getWidth(),
- height - 5 - okButton->getHeight());
-}
-
void NpcTextDialog::action(const gcn::ActionEvent &event)
{
if (event.getId() == "ok")
diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h
index c881467a..b4b6f1af 100644
--- a/src/gui/npc_text.h
+++ b/src/gui/npc_text.h
@@ -23,8 +23,10 @@
#define NPC_TEXT_H
#include <iosfwd>
+
#include <guichan/actionlistener.hpp>
+#include "scrollarea.h"
#include "window.h"
class BrowserBox;
@@ -45,13 +47,6 @@ class NpcTextDialog : public Window, public gcn::ActionListener
NpcTextDialog();
/**
- * Called when resizing the window.
- *
- * @param event The calling event
- */
- void widgetResized(const gcn::Event &event);
-
- /**
* Called when receiving actions from the widgets.
*/
void action(const gcn::ActionEvent &event);
diff --git a/src/gui/npcintegerdialog.cpp b/src/gui/npcintegerdialog.cpp
index ec91d736..65a1a7f1 100644
--- a/src/gui/npcintegerdialog.cpp
+++ b/src/gui/npcintegerdialog.cpp
@@ -107,5 +107,6 @@ void NpcIntegerDialog::action(const gcn::ActionEvent &event)
setVisible(false);
current_npc->integerInput(mValueField->getValue());
current_npc = 0;
+ mValueField->reset();
}
}
diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp
index 4b05df5a..bb815680 100644
--- a/src/gui/npclistdialog.cpp
+++ b/src/gui/npclistdialog.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npclistdialog.h"
-
#include <sstream>
-#include "button.h"
-#include "scrollarea.h"
#include "listbox.h"
+#include "npclistdialog.h"
+
+#include "widgets/layout.h"
#include "../npc.h"
@@ -39,6 +38,8 @@ NpcListDialog::NpcListDialog():
setMinWidth(200);
setMinHeight(150);
+ setDefaultSize(0, 0, 260, 200);
+
mItemList = new ListBox(this);
scrollArea = new ScrollArea(mItemList);
okButton = new Button(_("OK"), "ok", this);
@@ -46,23 +47,15 @@ NpcListDialog::NpcListDialog():
setContentSize(260, 175);
scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
- scrollArea->setDimension(gcn::Rectangle(
- 5, 5, 250, 160 - okButton->getHeight()));
- cancelButton->setPosition(
- 260 - 5 - cancelButton->getWidth(),
- 175 - 5 - cancelButton->getHeight());
- okButton->setPosition(
- cancelButton->getX() - 5 - okButton->getWidth(),
- cancelButton->getY());
- mItemList->setActionEventId("item");
+ place(0, 0, scrollArea, 5).setPadding(3);
+ place(3, 1, okButton);
+ place(4, 1, cancelButton);
- mItemList->addActionListener(this);
-
- add(scrollArea);
- add(okButton);
- add(cancelButton);
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
+ loadWindowState();
setLocationRelativeTo(getParent());
}
@@ -90,24 +83,6 @@ void NpcListDialog::reset()
mItems.clear();
}
-void NpcListDialog::widgetResized(const gcn::Event &event)
-{
- Window::widgetResized(event);
-
- const gcn::Rectangle &area = getChildrenArea();
- const int width = area.width;
- const int height = area.height;
-
- scrollArea->setDimension(gcn::Rectangle(
- 5, 5, width - 10, height - 15 - okButton->getHeight()));
- cancelButton->setPosition(
- width - 5 - cancelButton->getWidth(),
- height - 5 - cancelButton->getHeight());
- okButton->setPosition(
- cancelButton->getX() - 5 - okButton->getWidth(),
- cancelButton->getY());
-}
-
void NpcListDialog::action(const gcn::ActionEvent &event)
{
int choice = 0;
diff --git a/src/gui/npclistdialog.h b/src/gui/npclistdialog.h
index 2ae4aae3..ffeced3d 100644
--- a/src/gui/npclistdialog.h
+++ b/src/gui/npclistdialog.h
@@ -28,6 +28,8 @@
#include <guichan/actionlistener.hpp>
#include <guichan/listmodel.hpp>
+#include "button.h"
+#include "scrollarea.h"
#include "window.h"
#include "../guichanfwd.h"
@@ -49,13 +51,6 @@ class NpcListDialog : public Window, public gcn::ActionListener,
NpcListDialog();
/**
- * Called when resizing the window
- *
- * @param event The calling event
- */
- void widgetResized(const gcn::Event &event);
-
- /**
* Called when receiving actions from the widgets.
*/
void action(const gcn::ActionEvent &event);
diff --git a/src/gui/npcstringdialog.cpp b/src/gui/npcstringdialog.cpp
index 1c92d620..ccb3c411 100644
--- a/src/gui/npcstringdialog.cpp
+++ b/src/gui/npcstringdialog.cpp
@@ -42,8 +42,8 @@ NpcStringDialog::NpcStringDialog():
cancelButton = new Button(_("Cancel"), "cancel", this);
place(0, 0, mValueField, 3);
- place(1, 1, okButton);
- place(2, 1, cancelButton);
+ place(1, 1, cancelButton);
+ place(2, 1, okButton);
reflowLayout(175, 0);
setLocationRelativeTo(getParent());
@@ -69,6 +69,7 @@ void NpcStringDialog::action(const gcn::ActionEvent &event)
setVisible(false);
current_npc->stringInput(mValueField->getText());
current_npc = 0;
+ mValueField->setText("");
}
bool NpcStringDialog::isInputFocused()
diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp
index a2134d5d..dc66a900 100644
--- a/src/gui/ok_dialog.cpp
+++ b/src/gui/ok_dialog.cpp
@@ -20,9 +20,8 @@
*/
#include "ok_dialog.h"
-#include "textbox.h"
-#include "button.h"
-#include "scrollarea.h"
+
+#include <guichan/font.hpp>
#include "../utils/gettext.h"
@@ -30,25 +29,45 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg,
Window *parent):
Window(title, true, parent)
{
- TextBox *textBox = new TextBox();
- textBox->setEditable(false);
+ mTextBox = new TextBox();
+ mTextBox->setEditable(false);
+ mTextBox->setOpaque(false);
+
+ mTextArea = new ScrollArea(mTextBox);
+ okButton = new Button(_("Ok"), "ok", this);
+
+ mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextArea->setOpaque(false);
- gcn::ScrollArea *scrollArea = new ScrollArea(textBox);
- gcn::Button *okButton = new Button(_("Ok"), "ok", this);
+ mTextBox->setMinWidth(260);
+ mTextBox->setTextWrapped(msg);
- setContentSize(260, 175);
- scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
- scrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS);
- scrollArea->setDimension(gcn::Rectangle(
- 5, 5, 250, 160 - okButton->getHeight()));
+ int numRows = mTextBox->getNumberOfRows();
- textBox->setTextWrapped(msg);
+ if (numRows > 1)
+ {
+ // 15 == height of each line of text (based on font heights)
+ // 14 == row top + bottom graphic pixel heights
+ setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + okButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5,
+ 3 + (numRows * 14)));
+ }
+ else
+ {
+ int width = getFont()->getWidth(title);
+ if (width < getFont()->getWidth(msg))
+ width = getFont()->getWidth(msg);
+ if (width < okButton->getWidth())
+ width = okButton->getWidth();
+ setContentSize(width + 15, 30 + okButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17));
+ }
- okButton->setPosition(
- 260 - 5 - okButton->getWidth(),
- 175 - 5 - okButton->getHeight());
+ okButton->setPosition((mTextBox->getMinWidth() - okButton->getWidth()) / 2,
+ (numRows * 14) + okButton->getHeight() - 8);
- add(scrollArea);
+ add(mTextArea);
add(okButton);
setLocationRelativeTo(getParent());
@@ -56,6 +75,11 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg,
okButton->requestFocus();
}
+unsigned int OkDialog::getNumRows()
+{
+ return mTextBox->getNumberOfRows();
+}
+
void OkDialog::action(const gcn::ActionEvent &event)
{
// Proxy button events to our listeners
diff --git a/src/gui/ok_dialog.h b/src/gui/ok_dialog.h
index 44dc6bb9..78b3d44f 100644
--- a/src/gui/ok_dialog.h
+++ b/src/gui/ok_dialog.h
@@ -24,8 +24,13 @@
#include <guichan/actionlistener.hpp>
+#include "button.h"
+#include "scrollarea.h"
+#include "textbox.h"
#include "window.h"
+#include "../guichanfwd.h"
+
/**
* An 'Ok' button dialog.
*
@@ -41,10 +46,17 @@ class OkDialog : public Window, public gcn::ActionListener {
OkDialog(const std::string &title, const std::string &msg,
Window *parent = NULL);
+ unsigned int getNumRows();
+
/**
* Called when receiving actions from the widgets.
*/
void action(const gcn::ActionEvent &event);
+
+ private:
+ TextBox *mTextBox;
+ ScrollArea *mTextArea;
+ gcn::Button *okButton;
};
#endif
diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h
index d6082e3f..e01bedbd 100644
--- a/src/gui/passwordfield.h
+++ b/src/gui/passwordfield.h
@@ -24,12 +24,15 @@
#include "textfield.h"
+#include "../guichanfwd.h"
+
/**
* A password field.
*
* \ingroup GUI
*/
-class PasswordField : public TextField {
+class PasswordField : public TextField
+{
public:
/**
* Constructor, initializes the password field with the given string.
diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp
index 8f698df5..c22d407c 100644
--- a/src/gui/playerbox.cpp
+++ b/src/gui/playerbox.cpp
@@ -23,8 +23,10 @@
#include "playerbox.h"
-#include "../player.h"
+#include "../animatedsprite.h"
+#include "../configuration.h"
#include "../graphics.h"
+#include "../player.h"
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
@@ -54,6 +56,7 @@ PlayerBox::PlayerBox(const Player *player):
bggridx[x], bggridy[y],
bggridx[x + 1] - bggridx[x] + 1,
bggridy[y + 1] - bggridy[y] + 1);
+ background.grid[a]->setAlpha(config.getValue("guialpha", 0.8));
a++;
}
}
@@ -83,7 +86,13 @@ void PlayerBox::draw(gcn::Graphics *graphics)
bs = getFrameSize();
x = getWidth() / 2 - 16 + bs;
y = getHeight() / 2 + bs;
- mPlayer->draw(static_cast<Graphics*>(graphics), x, y);
+ for (int i = 0; i < Being::VECTOREND_SPRITE; i++)
+ {
+ if (mPlayer->getSprite(i) != NULL)
+ {
+ mPlayer->getSprite(i)->draw(static_cast<Graphics*>(graphics), x, y);
+ }
+ }
}
}
diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h
index d66db4d4..5aacd26f 100644
--- a/src/gui/playerbox.h
+++ b/src/gui/playerbox.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/scrollarea.hpp>
+#include "../guichanfwd.h"
+
class ImageRect;
class Player;
@@ -51,8 +53,7 @@ class PlayerBox : public gcn::ScrollArea
* player to <code>NULL</code> causes the box not to draw any
* character.
*/
- void
- setPlayer(const Player *player) { mPlayer = player; }
+ void setPlayer(const Player *player) { mPlayer = player; }
/**
* Draws the scroll area.
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 06a2ad87..9b0c2370 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -19,16 +19,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "popupmenu.h"
-
#include <cassert>
#include <iostream>
#include <guichan/focushandler.hpp>
#include "browserbox.h"
+#include "chat.h"
#include "inventorywindow.h"
#include "item_amount.h"
+#include "popupmenu.h"
#include "windowcontainer.h"
#include "../being.h"
@@ -39,8 +39,11 @@
#include "../npc.h"
#include "../player_relations.h"
-#include "../resources/iteminfo.h"
+#include "../net/messageout.h"
+#include "../net/protocol.h"
+
#include "../resources/itemdb.h"
+#include "../resources/iteminfo.h"
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
@@ -72,51 +75,53 @@ void PopupMenu::showPopup(int x, int y, Being *being)
switch (being->getType())
{
- case Being::PLAYER:
- {
- // Players can be traded with. Later also attack, follow and
- // add as buddy will be options in this menu.
- const std::string &name = being->getName();
- mBrowserBox->addRow(
- strprintf(_("@@trade|Trade With %s@@"), name.c_str()));
- mBrowserBox->addRow(
- strprintf(_("@@attack|Attack %s@@"), name.c_str()));
-
- mBrowserBox->addRow("##3---");
-
- switch (player_relations.getRelation(name)) {
- case PlayerRelation::NEUTRAL:
- mBrowserBox->addRow("@@friend|Befriend " + name + "@@");
-
- case PlayerRelation::FRIEND:
- mBrowserBox->addRow("@@disregard|Disregard " + name + "@@");
- mBrowserBox->addRow("@@ignore|Ignore " + name + "@@");
- break;
-
- case PlayerRelation::DISREGARDED:
- mBrowserBox->addRow("@@unignore|Un-Ignore " + name + "@@");
- mBrowserBox->addRow("@@ignore|Completely ignore " + name + "@@");
- break;
-
- case PlayerRelation::IGNORED:
- mBrowserBox->addRow("@@unignore|Un-Ignore " + name + "@@");
- break;
- }
-
- //mBrowserBox->addRow("@@follow|Follow " + name + "@@");
- //mBrowserBox->addRow("@@buddy|Add " + name + " to Buddy List@@");
- }
- break;
-
- case Being::NPC:
- // NPCs can be talked to (single option, candidate for removal
- // unless more options would be added)
- mBrowserBox->addRow(_("@@talk|Talk To NPC@@"));
- break;
-
- default:
- /* Other beings aren't interesting... */
- break;
+ case Being::PLAYER:
+ {
+ // Players can be traded with. Later also attack, follow and
+ // add as buddy will be options in this menu.
+ const std::string &name = being->getName();
+ mBrowserBox->addRow(_("@@trade|Trade With ") + name + "@@");
+ mBrowserBox->addRow(_("@@attack|Attack ") + name + "@@");
+
+ mBrowserBox->addRow("##3---");
+
+ switch (player_relations.getRelation(name)) {
+ case PlayerRelation::NEUTRAL:
+ mBrowserBox->addRow(_("@@friend|Befriend ") + name + "@@");
+
+ case PlayerRelation::FRIEND:
+ mBrowserBox->addRow(_("@@disregard|Disregard ") + name + "@@");
+ mBrowserBox->addRow(_("@@ignore|Ignore ") + name + "@@");
+ break;
+
+ case PlayerRelation::DISREGARDED:
+ mBrowserBox->addRow(_("@@unignore|Un-Ignore ") + name + "@@");
+ mBrowserBox->addRow(_("@@ignore|Completely ignore ") + name + "@@");
+ break;
+
+ case PlayerRelation::IGNORED:
+ mBrowserBox->addRow(_("@@unignore|Un-Ignore ") + name + "@@");
+ break;
+ }
+
+ //mBrowserBox->addRow(_("@@follow|Follow ") + name + "@@");
+ //mBrowserBox->addRow(_("@@buddy|Add ") + name + " to Buddy List@@");
+
+ mBrowserBox->addRow("##3---");
+ mBrowserBox->addRow(_("@@party-invite|Invite ") + name +
+ " to party@@");
+ }
+ break;
+
+ case Being::NPC:
+ // NPCs can be talked to (single option, candidate for removal
+ // unless more options would be added)
+ mBrowserBox->addRow(_("@@talk|Talk To NPC@@"));
+ break;
+
+ default:
+ /* Other beings aren't interesting... */
+ break;
}
//browserBox->addRow("@@look|Look To@@");
@@ -148,28 +153,28 @@ void PopupMenu::handleLink(const std::string& link)
// Talk To action
if (link == "talk" &&
- being != NULL &&
- being->getType() == Being::NPC &&
- current_npc == 0)
+ being != NULL &&
+ being->getType() == Being::NPC &&
+ current_npc == 0)
{
- dynamic_cast<NPC*>(being)->talk();
+ dynamic_cast<NPC*>(being)->talk();
}
// Trade action
else if (link == "trade" &&
- being != NULL &&
- being->getType() == Being::PLAYER)
+ being != NULL &&
+ being->getType() == Being::PLAYER)
{
- player_node->trade(being);
- tradePartnerName = being->getName();
+ player_node->trade(being);
+ tradePartnerName = being->getName();
}
// Attack action
else if (link == "attack" &&
- being != NULL &&
- being->getType() == Being::PLAYER)
+ being != NULL &&
+ being->getType() == Being::PLAYER)
{
- player_node->attack(being, true);
+ player_node->attack(being, true);
}
else if (link == "unignore" &&
@@ -194,10 +199,10 @@ void PopupMenu::handleLink(const std::string& link)
}
else if (link == "friend" &&
- being != NULL &&
- being->getType() == Being::PLAYER)
+ being != NULL &&
+ being->getType() == Being::PLAYER)
{
- player_relations.setRelation(being->getName(), PlayerRelation::FRIEND);
+ player_relations.setRelation(being->getName(), PlayerRelation::FRIEND);
}
/*
@@ -210,16 +215,16 @@ void PopupMenu::handleLink(const std::string& link)
// Add Buddy action
else if ((link == "buddy") && being != NULL && being->isPlayer())
{
- if (!buddyWindow->isVisible())
- buddyWindow->setVisible(true);
+ if (!buddyWindow->isVisible())
+ buddyWindow->setVisible(true);
- buddyWindow->addBuddy(being->getName());
+ buddyWindow->addBuddy(being->getName());
}*/
// Pick Up Floor Item action
else if ((link == "pickup") && mFloorItem != NULL)
{
- player_node->pickUp(mFloorItem);
+ player_node->pickUp(mFloorItem);
}
// Look To action
@@ -229,39 +234,46 @@ void PopupMenu::handleLink(const std::string& link)
else if (link == "use")
{
- assert(mItem);
- if (mItem->isEquipment())
- {
- if (mItem->isEquipped())
- {
- player_node->unequipItem(mItem);
- }
- else
- {
- player_node->equipItem(mItem);
- }
- }
- else
- {
- player_node->useItem(mItem);
- }
+ assert(mItem);
+ if (mItem->isEquipment())
+ {
+ if (mItem->isEquipped())
+ {
+ player_node->unequipItem(mItem);
+ }
+ else
+ {
+ player_node->equipItem(mItem);
+ }
+ }
+ else
+ {
+ player_node->useItem(mItem);
+ }
}
- else if (link == "drop")
+ else if (link == "chat")
{
- new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem);
+ chatWindow->addItemText(mItem->getId(), mItem->getInfo().getName());
}
- else if (link == "description")
+ else if (link == "drop")
+ {
+ new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem);
+ }
+ else if (link == "party-invite" &&
+ being != NULL &&
+ being->getType() == Being::PLAYER)
{
- // do nothing for now, I need to write
- // a window for the description first
+ MessageOut outMsg(player_node->getNetwork());
+ outMsg.writeInt16(CMSG_PARTY_INVITE);
+ outMsg.writeInt32(being->getId());
}
// Unknown actions
else
{
- std::cout << link << std::endl;
+ std::cout << link << std::endl;
}
setVisible(false);
@@ -288,7 +300,7 @@ void PopupMenu::showPopup(int x, int y, Item *item)
mBrowserBox->addRow(_("@@use|Use@@"));
mBrowserBox->addRow(_("@@drop|Drop@@"));
- mBrowserBox->addRow(_("@@description|Description@@"));
+ mBrowserBox->addRow(_("@@chat|Add to Chat@@"));
mBrowserBox->addRow("##3---");
mBrowserBox->addRow(_("@@cancel|Cancel@@"));
@@ -299,9 +311,9 @@ void PopupMenu::showPopup(int x, int y)
{
setContentSize(mBrowserBox->getWidth() + 8, mBrowserBox->getHeight() + 8);
if (windowContainer->getWidth() < (x + getWidth() + 5))
- x = windowContainer->getWidth() - getWidth();
+ x = windowContainer->getWidth() - getWidth();
if (windowContainer->getHeight() < (y + getHeight() + 5))
- y = windowContainer->getHeight() - getHeight();
+ y = windowContainer->getHeight() - getHeight();
setPosition(x, y);
setVisible(true);
requestMoveToTop();
diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h
index 1165bcb2..2694abd8 100644
--- a/src/gui/popupmenu.h
+++ b/src/gui/popupmenu.h
@@ -24,15 +24,14 @@
#include <SDL.h> // for Uint32
-#include "window.h"
#include "linkhandler.h"
+#include "window.h"
class Being;
class BrowserBox;
class FloorItem;
class Item;
-
/**
* Window showing popup menu.
*/
diff --git a/src/gui/progressbar.cpp b/src/gui/progressbar.cpp
index d877bfbc..ecc0017d 100644
--- a/src/gui/progressbar.cpp
+++ b/src/gui/progressbar.cpp
@@ -19,6 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "gui.h"
#include "progressbar.h"
#include "../graphics.h"
@@ -105,7 +106,7 @@ void ProgressBar::draw(gcn::Graphics *graphics)
// The label
if (!mText.empty()) {
- gcn::Font *f = getFont();
+ gcn::Font *f = boldFont;
const int textX = getWidth() / 2;
const int textY = (getHeight() - f->getHeight()) / 2;
diff --git a/src/gui/progressbar.h b/src/gui/progressbar.h
index a4b30b04..ee0a5f81 100644
--- a/src/gui/progressbar.h
+++ b/src/gui/progressbar.h
@@ -25,9 +25,10 @@
#include <guichan/widget.hpp>
#include <SDL_types.h>
-
#include <string>
+#include "../guichanfwd.h"
+
class ImageRect;
/**
@@ -81,12 +82,12 @@ class ProgressBar : public gcn::Widget
Uint8 getRed() const { return mRed; }
/**
- * Returns the red value of color.
+ * Returns the green value of color.
*/
Uint8 getGreen() const { return mGreen; }
/**
- * Returns the red value of color.
+ * Returns the blue value of color.
*/
Uint8 getBlue() const { return mBlue; }
diff --git a/src/gui/radiobutton.h b/src/gui/radiobutton.h
index 2d2bdbb7..dcd62802 100644
--- a/src/gui/radiobutton.h
+++ b/src/gui/radiobutton.h
@@ -24,8 +24,9 @@
#include <guichan/widgets/radiobutton.hpp>
-class Image;
+#include "../guichanfwd.h"
+class Image;
/*
* Guichan based RadioButton with custom look
diff --git a/src/gui/register.cpp b/src/gui/register.cpp
index 5605ef96..9c337d9e 100644
--- a/src/gui/register.cpp
+++ b/src/gui/register.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "register.h"
-
#include <string>
#include <sstream>
@@ -34,10 +32,13 @@
#include "button.h"
#include "checkbox.h"
#include "login.h"
+#include "ok_dialog.h"
#include "passwordfield.h"
#include "radiobutton.h"
+#include "register.h"
#include "textfield.h"
-#include "ok_dialog.h"
+
+#include "../utils/tostring.h"
#include "widgets/layout.h"
@@ -80,10 +81,12 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
gcn::Label *passwordLabel = new gcn::Label(_("Password:"));
gcn::Label *confirmLabel = new gcn::Label(_("Confirm:"));
gcn::Label *serverLabel = new gcn::Label(_("Server:"));
+ gcn::Label *portLabel = new gcn::Label(_("Port:"));
mUserField = new TextField(loginData->username);
mPasswordField = new PasswordField(loginData->password);
mConfirmField = new PasswordField;
mServerField = new TextField(loginData->hostname);
+ mPortField = new TextField(toString(loginData->port));
mMaleButton = new RadioButton(_("Male"), "sex", true);
mFemaleButton = new RadioButton(_("Female"), "sex", false);
mRegisterButton = new Button(_("Register"), "register", this);
@@ -97,10 +100,12 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
place(1, 3, mMaleButton);
place(2, 3, mFemaleButton);
place(0, 4, serverLabel);
+ place(0, 5, portLabel);
place(1, 0, mUserField, 3).setPadding(2);
place(1, 1, mPasswordField, 3).setPadding(2);
place(1, 2, mConfirmField, 3).setPadding(2);
place(1, 4, mServerField, 3).setPadding(2);
+ place(1, 5, mPortField, 3).setPadding(2);
place = getPlacer(0, 2);
place(1, 0, mRegisterButton);
place(2, 0, mCancelButton);
@@ -110,6 +115,7 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
mPasswordField->addKeyListener(this);
mConfirmField->addKeyListener(this);
mServerField->addKeyListener(this);
+ mPortField->addKeyListener(this);
/* TODO:
* This is a quick and dirty way to respond to the ENTER key, regardless of
@@ -120,10 +126,13 @@ RegisterDialog::RegisterDialog(LoginData *loginData):
mPasswordField->setActionEventId("register");
mConfirmField->setActionEventId("register");
mServerField->setActionEventId("register");
+ mPortField->setActionEventId("register");
+
mUserField->addActionListener(this);
mPasswordField->addActionListener(this);
mConfirmField->addActionListener(this);
mServerField->addActionListener(this);
+ mPortField->addActionListener(this);
setLocationRelativeTo(getParent());
setVisible(true);
@@ -147,7 +156,7 @@ void RegisterDialog::action(const gcn::ActionEvent &event)
else if (event.getId() == "register" && canSubmit())
{
const std::string user = mUserField->getText();
- logger->log("RegisterDialog::register Username is %s", user.c_str());
+ logger->log(_("RegisterDialog::register Username is %s"), user.c_str());
std::string errorMsg;
int error = 0;
@@ -216,7 +225,7 @@ void RegisterDialog::action(const gcn::ActionEvent &event)
mRegisterButton->setEnabled(false);
mLoginData->hostname = mServerField->getText();
- mLoginData->port = (short) config.getValue("port", 0);
+ mLoginData->port = getUShort(mPortField->getText());
mLoginData->username = mUserField->getText();
mLoginData->password = mPasswordField->getText();
mLoginData->username += mFemaleButton->isSelected() ? "_F" : "_M";
@@ -238,5 +247,40 @@ bool RegisterDialog::canSubmit() const
!mPasswordField->getText().empty() &&
!mConfirmField->getText().empty() &&
!mServerField->getText().empty() &&
+ isUShort(mPortField->getText()) &&
state == REGISTER_STATE;
}
+
+bool RegisterDialog::isUShort(const std::string &str)
+{
+ if (str == "")
+ {
+ return false;
+ }
+ unsigned long l = 0;
+ for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end();
+ strPtr != strEnd; ++strPtr)
+ {
+ if (*strPtr < '0' || *strPtr > '9')
+ {
+ return false;
+ }
+ l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative
+ if (l > 65535)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+unsigned short RegisterDialog::getUShort(const std::string &str)
+{
+ unsigned long l = 0;
+ for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end();
+ strPtr != strEnd; ++strPtr)
+ {
+ l = l * 10 + (*strPtr - '0');
+ }
+ return static_cast<unsigned short>(l);
+}
diff --git a/src/gui/register.h b/src/gui/register.h
index 3dddae0f..4b95a07b 100644
--- a/src/gui/register.h
+++ b/src/gui/register.h
@@ -23,10 +23,12 @@
#define REGISTER_H
#include <iosfwd>
+
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
#include "window.h"
+
#include "../guichanfwd.h"
class LoginData;
@@ -72,10 +74,29 @@ class RegisterDialog : public Window, public gcn::ActionListener,
*/
bool canSubmit() const;
+ /**
+ * Function to decide whether string is an unsigned short or not
+ *
+ * @param str the string to parse
+ *
+ * @return true if str is an unsigned short, false otherwise
+ */
+ static bool isUShort(const std::string &str);
+
+ /**
+ * Converts string to an unsigned short (undefined if invalid)
+ *
+ * @param str the string to parse
+ *
+ * @return the value str represents
+ */
+ static unsigned short getUShort(const std::string &str);
+
gcn::TextField *mUserField;
gcn::TextField *mPasswordField;
gcn::TextField *mConfirmField;
gcn::TextField *mServerField;
+ gcn::TextField *mPortField;
gcn::Button *mRegisterButton;
gcn::Button *mCancelButton;
diff --git a/src/gui/scrollarea.cpp b/src/gui/scrollarea.cpp
index 8a74cd72..1d7f8472 100644
--- a/src/gui/scrollarea.cpp
+++ b/src/gui/scrollarea.cpp
@@ -23,6 +23,7 @@
#include "scrollarea.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../resources/image.h"
@@ -94,6 +95,7 @@ void ScrollArea::init()
bggridx[x], bggridy[y],
bggridx[x + 1] - bggridx[x] + 1,
bggridy[y + 1] - bggridy[y] + 1);
+ background.grid[a]->setAlpha(config.getValue("guialpha", 0.8));
a++;
}
}
@@ -106,12 +108,15 @@ void ScrollArea::init()
int vsgridy[4] = {0, 4, 15, 19};
a = 0;
- for (y = 0; y < 3; y++) {
- for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
vMarker.grid[a] = vscroll->getSubImage(
vsgridx[x], vsgridy[y],
vsgridx[x + 1] - vsgridx[x],
vsgridy[y + 1] - vsgridy[y]);
+ vMarker.grid[a]->setAlpha(config.getValue("guialpha", 0.8));
a++;
}
}
@@ -197,7 +202,8 @@ void ScrollArea::drawFrame(gcn::Graphics *graphics)
int w = getWidth() + bs * 2;
int h = getHeight() + bs * 2;
- if (mOpaque) {
+ if (mOpaque)
+ {
static_cast<Graphics*>(graphics)->
drawImageRect(0, 0, w, h, background);
}
@@ -207,10 +213,12 @@ void ScrollArea::setOpaque(bool opaque)
{
mOpaque = opaque;
- if (mOpaque) {
+ if (mOpaque)
+ {
setFrameSize(2);
}
- else {
+ else
+ {
setFrameSize(0);
}
}
@@ -220,7 +228,8 @@ void ScrollArea::drawButton(gcn::Graphics *graphics, BUTTON_DIR dir)
int state = 0;
gcn::Rectangle dim;
- switch(dir) {
+ switch(dir)
+ {
case UP:
state = mUpButtonPressed ? 1 : 0;
dim = getUpButtonDimension();
diff --git a/src/gui/scrollarea.h b/src/gui/scrollarea.h
index 1641f318..4fababfa 100644
--- a/src/gui/scrollarea.h
+++ b/src/gui/scrollarea.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/scrollarea.hpp>
+#include "../guichanfwd.h"
+
class Image;
class ImageRect;
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index cc6f02d5..7976e32e 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "sell.h"
-
#include <cassert>
#include <guichan/widgets/label.hpp>
@@ -28,6 +26,7 @@
#include "button.h"
#include "shoplistbox.h"
#include "scrollarea.h"
+#include "sell.h"
#include "shop.h"
#include "slider.h"
@@ -36,13 +35,14 @@
#include "../item.h"
#include "../npc.h"
-#include "../resources/iteminfo.h"
-
#include "../net/messageout.h"
#include "../net/protocol.h"
+#include "../resources/iteminfo.h"
+
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
+#include "../utils/tostring.h"
SellDialog::SellDialog(Network *network):
Window(_("Sell")),
diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp
index d38fb2e3..d18f365c 100644
--- a/src/gui/setup.cpp
+++ b/src/gui/setup.cpp
@@ -19,31 +19,33 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup.h"
+#include <algorithm>
+#include <iostream>
#include "button.h"
+#include "setup.h"
#include "setup_audio.h"
+#include "setup_colours.h"
#include "setup_joystick.h"
-#include "setup_video.h"
#include "setup_keyboard.h"
#include "setup_players.h"
+#include "setup_video.h"
#include "widgets/tabbedarea.h"
#include "../utils/dtor.h"
#include "../utils/gettext.h"
-#include <algorithm>
-#include <iostream>
-
-extern Window *statusWindow;
-extern Window *minimap;
extern Window *chatWindow;
-extern Window *inventoryWindow;
extern Window *equipmentWindow;
extern Window *helpWindow;
+extern Window *inventoryWindow;
+extern Window *minimap;
extern Window *skillDialog;
+extern Window *statusWindow;
extern Window *itemShortcutWindow;
+extern Window *emoteShortcutWindow;
+extern Window *emoteWindow;
extern Window *tradeWindow;
Setup::Setup():
@@ -58,7 +60,8 @@ Setup::Setup():
N_("Apply"), N_("Cancel"), N_("Reset Windows"), 0
};
int x = width;
- for (const char **curBtn = buttonNames; *curBtn; ++curBtn) {
+ for (const char **curBtn = buttonNames; *curBtn; ++curBtn)
+ {
Button *btn = new Button(gettext(*curBtn), *curBtn, this);
x -= btn->getWidth() + 5;
btn->setPosition(x, height - btn->getHeight() - 5);
@@ -90,6 +93,10 @@ Setup::Setup():
panel->addTab(_("Keyboard"), tab);
mTabs.push_back(tab);
+ tab = new Setup_Colours();
+ panel->addTab(_("Colors"), tab);
+ mTabs.push_back(tab);
+
tab = new Setup_Players();
panel->addTab(_("Players"), tab);
mTabs.push_back(tab);
@@ -131,6 +138,8 @@ void Setup::action(const gcn::ActionEvent &event)
helpWindow->resetToDefaultSize();
skillDialog->resetToDefaultSize();
itemShortcutWindow->resetToDefaultSize();
+ emoteShortcutWindow->resetToDefaultSize();
+ emoteWindow->resetToDefaultSize();
tradeWindow->resetToDefaultSize();
}
}
diff --git a/src/gui/setup.h b/src/gui/setup.h
index 881961f6..e4eb0902 100644
--- a/src/gui/setup.h
+++ b/src/gui/setup.h
@@ -28,6 +28,8 @@
#include "window.h"
+#include "../guichanfwd.h"
+
class SetupTab;
/**
@@ -51,8 +53,7 @@ class Setup : public Window, public gcn::ActionListener
/**
* Event handling method.
*/
- void
- action(const gcn::ActionEvent &event);
+ void action(const gcn::ActionEvent &event);
private:
std::list<SetupTab*> mTabs;
diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp
index b9fc1d2d..7090136e 100644
--- a/src/gui/setup_audio.cpp
+++ b/src/gui/setup_audio.cpp
@@ -19,12 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup_audio.h"
-
#include <guichan/widgets/label.hpp>
#include "checkbox.h"
#include "ok_dialog.h"
+#include "setup_audio.h"
#include "slider.h"
#include "widgets/layouthelper.h"
diff --git a/src/gui/setup_audio.h b/src/gui/setup_audio.h
index 5345d3cf..2f5cd736 100644
--- a/src/gui/setup_audio.h
+++ b/src/gui/setup_audio.h
@@ -22,10 +22,10 @@
#ifndef GUI_SETUP_AUDIO_H
#define GUI_SETUP_AUDIO_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
+#include "setuptab.h"
+
#include "../guichanfwd.h"
class Setup_Audio : public SetupTab, public gcn::ActionListener
diff --git a/src/gui/setup_colours.cpp b/src/gui/setup_colours.cpp
new file mode 100644
index 00000000..c08c94ef
--- /dev/null
+++ b/src/gui/setup_colours.cpp
@@ -0,0 +1,226 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <vector>
+
+#include <guichan/listmodel.hpp>
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/slider.hpp>
+
+#include "colour.h"
+#include "scrollarea.h"
+#include "setup_colours.h"
+#include "slider.h"
+#include "textfield.h"
+
+#include "widgets/layouthelper.h"
+
+#include "../configuration.h"
+
+#include "../utils/gettext.h"
+
+Setup_Colours::Setup_Colours() :
+ mSelected(-1)
+{
+ setOpaque(false);
+
+ mColourBox = new gcn::ListBox(textColour);
+ mColourBox->setActionEventId("colour_box");
+ mColourBox->addActionListener(this);
+
+ mScroll = new ScrollArea(mColourBox);
+ mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mScroll->setWidth(90);
+
+ mRedLabel = new gcn::Label(_("Red: "));
+
+ mRedText = new TextField();
+ mRedText->setWidth(40);
+ mRedText->setRange(0, 255);
+ mRedText->setNumeric(true);
+ mRedText->addListener(this);
+
+ mRedSlider = new Slider(0, 255);
+ mRedSlider->setWidth(90);
+ mRedSlider->setValue(mRedText->getValue());
+ mRedSlider->setActionEventId("slider_red");
+ mRedSlider->addActionListener(this);
+
+ mGreenLabel = new gcn::Label(_("Green: "));
+
+ mGreenText = new TextField();
+ mGreenText->setWidth(40);
+ mGreenText->setRange(0, 255);
+ mGreenText->setNumeric(true);
+ mGreenText->addListener(this);
+
+ mGreenSlider = new Slider(0, 255);
+ mGreenSlider->setWidth(90);
+ mGreenSlider->setValue(mGreenText->getValue());
+ mGreenSlider->setActionEventId("slider_green");
+ mGreenSlider->addActionListener(this);
+
+ mBlueLabel = new gcn::Label(_("Blue: "));
+
+ mBlueText = new TextField();
+ mBlueText->setWidth(40);
+ mBlueText->setRange(0, 255);
+ mBlueText->setNumeric(true);
+ mBlueText->addListener(this);
+
+ mBlueSlider = new Slider(0, 255);
+ mBlueSlider->setWidth(90);
+ mBlueSlider->setValue(mBlueText->getValue());
+ mBlueSlider->setActionEventId("slider_blue");
+ mBlueSlider->addActionListener(this);
+
+ setOpaque(false);
+
+ // Do the layout
+ LayoutHelper h(this);
+ ContainerPlacer place = h.getPlacer(0, 0);
+
+ place(0, 0, mScroll, 1, 3).setPadding(2);
+ place(1, 0, mRedLabel, 2);
+ place(3, 0, mRedSlider);
+ place(4, 0, mRedText).setPadding(1);
+ place(1, 1, mGreenLabel, 2);
+ place(3, 1, mGreenSlider);
+ place(4, 1, mGreenText).setPadding(1);
+ place(1, 2, mBlueLabel, 2);
+ place(3, 2, mBlueSlider);
+ place(4, 2, mBlueText).setPadding(1);
+
+ setDimension(gcn::Rectangle(0, 0, 290, 150));
+}
+
+Setup_Colours::~Setup_Colours()
+{
+ delete mRedLabel;
+ delete mRedSlider;
+ delete mRedText;
+
+ delete mGreenLabel;
+ delete mGreenSlider;
+ delete mGreenText;
+
+ delete mBlueLabel;
+ delete mBlueSlider;
+ delete mBlueText;
+
+ delete mScroll;
+}
+
+void Setup_Colours::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "colour_box")
+ {
+ mSelected = mColourBox->getSelected();
+ int col = textColour->getColourAt(mSelected);
+ setEntry(mRedSlider, mRedText, col >> 16);
+ setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff);
+ setEntry(mBlueSlider, mBlueText, col & 0xff);
+ return;
+ }
+
+ if (event.getId() == "slider_red")
+ {
+ char buffer[30];
+ std::sprintf(buffer, "%d", static_cast<int>(mRedSlider->getValue()));
+ mRedText->setText(buffer);
+ updateColour();
+ return;
+ }
+
+ if (event.getId() == "slider_green")
+ {
+ char buffer[30];
+ std::sprintf(buffer, "%d", static_cast<int>(mGreenSlider->getValue()));
+ mGreenText->setText(buffer);
+ updateColour();
+ return;
+ }
+
+ if (event.getId() == "slider_blue")
+ {
+ char buffer[30];
+ std::sprintf(buffer, "%d", static_cast<int>(mBlueSlider->getValue()));
+ mBlueText->setText(buffer);
+ updateColour();
+ return;
+ }
+}
+
+void Setup_Colours::setEntry(Slider *s, TextField *t, int value)
+{
+ s->setValue(value);
+ char buffer[100];
+ sprintf(buffer, "%d", value);
+ t->setText(buffer);
+}
+
+void Setup_Colours::apply()
+{
+ textColour->commit();
+}
+
+void Setup_Colours::cancel()
+{
+ textColour->rollback();
+ int col = textColour->getColourAt(mSelected);
+ setEntry(mRedSlider, mRedText, col >> 16);
+ setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff);
+ setEntry(mBlueSlider, mBlueText, col & 0xff);
+}
+
+void Setup_Colours::listen(const TextField *tf)
+{
+ if (tf == mRedText)
+ {
+ mRedSlider->setValue(tf->getValue());
+ updateColour();
+ return;
+ }
+ if (tf == mGreenText)
+ {
+ mGreenSlider->setValue(tf->getValue());
+ updateColour();
+ return;
+ }
+ if (tf == mBlueText)
+ {
+ mBlueSlider->setValue(tf->getValue());
+ updateColour();
+ return;
+ }
+}
+
+void Setup_Colours::updateColour()
+{
+ if (mSelected == -1)
+ {
+ return;
+ }
+ int rgb = static_cast<int>(mRedSlider->getValue()) << 16 |
+ static_cast<int>(mGreenSlider->getValue()) << 8 |
+ static_cast<int>(mBlueSlider->getValue());
+ textColour->setColourAt(mSelected, rgb);
+}
diff --git a/src/gui/setup_colours.h b/src/gui/setup_colours.h
new file mode 100644
index 00000000..628efb43
--- /dev/null
+++ b/src/gui/setup_colours.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef _SETUP_COLOURS_H
+#define _SETUP_COLOURS_H
+
+#include <string>
+#include <vector>
+
+#include <guichan/actionlistener.hpp>
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/listbox.hpp>
+
+#include "scrollarea.h"
+#include "setuptab.h"
+#include "slider.h"
+#include "textfield.h"
+
+#include "../guichanfwd.h"
+
+class Setup_Colours : public SetupTab, public gcn::ActionListener,
+ public TextFieldListener
+{
+ public:
+ Setup_Colours();
+ ~Setup_Colours();
+ void apply();
+ void cancel();
+ void action(const gcn::ActionEvent &event);
+
+ void listen(const TextField *tf);
+ private:
+ gcn::ListBox *mColourBox;
+ ScrollArea *mScroll;
+ int mSelected;
+
+ gcn::Label *mRedLabel;
+ Slider *mRedSlider;
+ TextField *mRedText;
+ int mRedValue;
+
+ gcn::Label *mGreenLabel;
+ Slider *mGreenSlider;
+ TextField *mGreenText;
+ int mGreenValue;
+
+ gcn::Label *mBlueLabel;
+ Slider *mBlueSlider;
+ TextField *mBlueText;
+ int mBlueValue;
+
+ void setEntry(Slider *s, TextField *t, int value);
+ void updateColour();
+};
+#endif
diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp
index f8fc194f..2c726b87 100644
--- a/src/gui/setup_joystick.cpp
+++ b/src/gui/setup_joystick.cpp
@@ -19,12 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup_joystick.h"
-
#include <guichan/widgets/label.hpp>
#include "button.h"
#include "checkbox.h"
+#include "setup_joystick.h"
#include "widgets/layouthelper.h"
@@ -62,7 +61,8 @@ Setup_Joystick::Setup_Joystick():
void Setup_Joystick::action(const gcn::ActionEvent &event)
{
- if (!joystick) {
+ if (!joystick)
+ {
return;
}
@@ -72,12 +72,15 @@ void Setup_Joystick::action(const gcn::ActionEvent &event)
}
else
{
- if (joystick->isCalibrating()) {
+ if (joystick->isCalibrating())
+ {
mCalibrateButton->setCaption(_("Calibrate"));
mCalibrateLabel->setCaption
(_("Press the button to start calibration"));
joystick->finishCalibration();
- } else {
+ }
+ else
+ {
mCalibrateButton->setCaption(_("Stop"));
mCalibrateLabel->setCaption(_("Rotate the stick"));
joystick->startCalibration();
diff --git a/src/gui/setup_joystick.h b/src/gui/setup_joystick.h
index dd8c331f..2dc56439 100644
--- a/src/gui/setup_joystick.h
+++ b/src/gui/setup_joystick.h
@@ -22,10 +22,10 @@
#ifndef GUI_SETUP_JOYSTICK_H
#define GUI_SETUP_JOYSTICK_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
+#include "setuptab.h"
+
#include "../guichanfwd.h"
class Setup_Joystick : public SetupTab, public gcn::ActionListener
diff --git a/src/gui/setup_keyboard.cpp b/src/gui/setup_keyboard.cpp
index cf44731c..c6b6869a 100644
--- a/src/gui/setup_keyboard.cpp
+++ b/src/gui/setup_keyboard.cpp
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup_keyboard.h"
+#include <SDL_keyboard.h>
#include <guichan/widgets/label.hpp>
#include <guichan/listmodel.hpp>
@@ -28,6 +28,9 @@
#include "listbox.h"
#include "ok_dialog.h"
#include "scrollarea.h"
+#include "setup_keyboard.h"
+
+#include "widgets/layouthelper.h"
#include "widgets/layouthelper.h"
@@ -37,8 +40,6 @@
#include "../utils/gettext.h"
#include "../utils/tostring.h"
-#include <SDL_keyboard.h>
-
/**
* The list model for key function list.
*
diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h
index f04be792..d4966053 100644
--- a/src/gui/setup_keyboard.h
+++ b/src/gui/setup_keyboard.h
@@ -22,14 +22,14 @@
#ifndef GUI_SETUP_KEYBOARD_H
#define GUI_SETUP_KEYBOARD_H
-#include "setuptab.h"
-#include "button.h"
-#include "../guichanfwd.h"
+#include <string>
#include <guichan/actionlistener.hpp>
+#include "button.h"
+#include "setuptab.h"
-#include <string>
+#include "../guichanfwd.h"
class Setup_Keyboard : public SetupTab, public gcn::ActionListener
{
diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp
index 1d8649eb..9a7fb441 100644
--- a/src/gui/setup_players.cpp
+++ b/src/gui/setup_players.cpp
@@ -19,11 +19,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup_players.h"
+#include <vector>
+
+#include <guichan/widgets/dropdown.hpp>
+#include <guichan/widgets/label.hpp>
#include "button.h"
#include "checkbox.h"
#include "ok_dialog.h"
+#include "setup_players.h"
#include "widgets/layouthelper.h"
@@ -34,11 +38,6 @@
#include "../utils/gettext.h"
-#include <guichan/widgets/dropdown.hpp>
-#include <guichan/widgets/label.hpp>
-
-#include <vector>
-
#define COLUMNS_NR 2 // name plus listbox
#define NAME_COLUMN 0
#define RELATION_CHOICE_COLUMN 1
@@ -198,7 +197,7 @@ public:
virtual std::string getElementAt(int i)
{
if (i >= getNumberOfElements()) {
- return "???";
+ return _("???");
}
return (*player_relations.getPlayerIgnoreStrategies())[i]->mDescription;
}
diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h
index d380d9f6..22c8a9b6 100644
--- a/src/gui/setup_players.h
+++ b/src/gui/setup_players.h
@@ -22,15 +22,14 @@
#ifndef GUI_SETUP_PLAYERS_H
#define GUI_SETUP_PLAYERS_H
-#include "setuptab.h"
+#include <guichan/actionlistener.hpp>
-#include "scrollarea.h"
#include "button.h"
+#include "scrollarea.h"
+#include "setuptab.h"
#include "table.h"
-#include <guichan/actionlistener.hpp>
#include "../guichanfwd.h"
-
#include "../player_relations.h"
class PlayerTableModel;
diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp
index 53041a9c..2381ab41 100644
--- a/src/gui/setup_video.cpp
+++ b/src/gui/setup_video.cpp
@@ -19,11 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup_video.h"
-
+#include <SDL.h>
#include <string>
#include <vector>
-#include <SDL.h>
#include <guichan/key.hpp>
#include <guichan/listmodel.hpp>
@@ -34,6 +32,7 @@
#include "listbox.h"
#include "ok_dialog.h"
#include "scrollarea.h"
+#include "setup_video.h"
#include "slider.h"
#include "textfield.h"
@@ -41,6 +40,7 @@
#include "../configuration.h"
#include "../graphics.h"
+#include "../localplayer.h"
#include "../log.h"
#include "../main.h"
#include "../particle.h"
@@ -89,9 +89,9 @@ ModeListModel::ModeListModel()
/* Check which modes are available */
if (modes == (SDL_Rect **)0) {
- logger->log("No modes available");
+ logger->log(_("No modes available"));
} else if (modes == (SDL_Rect **)-1) {
- logger->log("All resolutions available");
+ logger->log(_("All resolutions available"));
} else {
//logger->log("Available Modes");
for (int i = 0; modes[i]; ++i) {
@@ -107,6 +107,9 @@ Setup_Video::Setup_Video():
mFullScreenEnabled(config.getValue("screen", 0)),
mOpenGLEnabled(config.getValue("opengl", 0)),
mCustomCursorEnabled(config.getValue("customcursor", 1)),
+ mParticleEffectsEnabled(config.getValue("particleeffects", 1)),
+ mSpeechBubbleEnabled(config.getValue("speechbubble", 1)),
+ mNameEnabled(config.getValue("showownname", 0)),
mOpacity(config.getValue("guialpha", 0.8)),
mFps((int) config.getValue("fpslimit", 0)),
mModeListModel(new ModeListModel),
@@ -114,6 +117,9 @@ Setup_Video::Setup_Video():
mFsCheckBox(new CheckBox(_("Full screen"), mFullScreenEnabled)),
mOpenGLCheckBox(new CheckBox(_("OpenGL"), mOpenGLEnabled)),
mCustomCursorCheckBox(new CheckBox(_("Custom cursor"), mCustomCursorEnabled)),
+ mParticleEffectsCheckBox(new CheckBox(_("Particle effects"), mParticleEffectsEnabled)),
+ mSpeechBubbleCheckBox(new CheckBox(_("Speech bubbles"), mSpeechBubbleEnabled)),
+ mNameCheckBox(new CheckBox(_("Show name"), mNameEnabled)),
mAlphaSlider(new Slider(0.2, 1.0)),
mFpsCheckBox(new CheckBox(_("FPS Limit:"))),
mFpsSlider(new Slider(10, 200)),
@@ -137,13 +143,12 @@ Setup_Video::Setup_Video():
scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
gcn::Label *alphaLabel = new gcn::Label(_("Gui opacity"));
-
gcn::Label *scrollRadiusLabel = new gcn::Label(_("Scroll radius"));
gcn::Label *scrollLazinessLabel = new gcn::Label(_("Scroll laziness"));
gcn::Label *overlayDetailLabel = new gcn::Label(_("Ambient FX"));
gcn::Label *particleDetailLabel = new gcn::Label(_("Particle Detail"));
- mModeList->setEnabled(false);
+ mModeList->setEnabled(true);
#ifndef USE_OPENGL
mOpenGLCheckBox->setEnabled(false);
#endif
@@ -159,7 +164,11 @@ Setup_Video::Setup_Video():
mFpsSlider->setEnabled(mFps > 0);
mFpsCheckBox->setSelected(mFps > 0);
+ mModeList->setActionEventId("videomode");
mCustomCursorCheckBox->setActionEventId("customcursor");
+ mParticleEffectsCheckBox->setActionEventId("particleeffects");
+ mSpeechBubbleCheckBox->setActionEventId("speechbubble");
+ mNameCheckBox->setActionEventId("showownname");
mAlphaSlider->setActionEventId("guialpha");
mFpsCheckBox->setActionEventId("fpslimitcheckbox");
mFpsSlider->setActionEventId("fpslimitslider");
@@ -172,7 +181,11 @@ Setup_Video::Setup_Video():
mParticleDetailSlider->setActionEventId("particledetailslider");
mParticleDetailField->setActionEventId("particledetailfield");
+ mModeList->addActionListener(this);
mCustomCursorCheckBox->addActionListener(this);
+ mParticleEffectsCheckBox->addActionListener(this);
+ mSpeechBubbleCheckBox->addActionListener(this);
+ mNameCheckBox->addActionListener(this);
mAlphaSlider->addActionListener(this);
mFpsCheckBox->addActionListener(this);
mFpsSlider->addActionListener(this);
@@ -227,30 +240,33 @@ Setup_Video::Setup_Video():
LayoutHelper h(this);
ContainerPlacer place = h.getPlacer(0, 0);
- place(0, 0, scrollArea, 1, 4).setPadding(2);
+ place(0, 0, scrollArea, 1, 6).setPadding(2);
place(1, 0, mFsCheckBox, 3);
place(1, 1, mOpenGLCheckBox, 3);
place(1, 2, mCustomCursorCheckBox, 3);
-
- place(0, 4, mAlphaSlider);
- place(0, 5, mFpsSlider);
- place(0, 6, mScrollRadiusSlider);
- place(0, 7, mScrollLazinessSlider);
- place(0, 8, mOverlayDetailSlider);
- place(0, 9, mParticleDetailSlider);
-
- place(1, 4, alphaLabel, 2);
- place(1, 5, mFpsCheckBox).setPadding(3);
- place(1, 6, scrollRadiusLabel);
- place(1, 7, scrollLazinessLabel);
- place(1, 8, overlayDetailLabel);
- place(1, 9, particleDetailLabel);
-
- place(2, 5, mFpsField).setPadding(1);
- place(2, 6, mScrollRadiusField).setPadding(1);
- place(2, 7, mScrollLazinessField).setPadding(1);
- place(2, 8, mOverlayDetailField, 2).setPadding(2);
- place(2, 9, mParticleDetailField, 2).setPadding(2);
+ place(1, 3, mSpeechBubbleCheckBox, 3);
+ place(1, 4, mNameCheckBox, 3);
+ place(1, 5, mParticleEffectsCheckBox, 3);
+
+ place(0, 7, mAlphaSlider);
+ place(0, 8, mFpsSlider);
+ place(0, 9, mScrollRadiusSlider);
+ place(0, 10, mScrollLazinessSlider);
+ place(0, 11, mOverlayDetailSlider);
+ place(0, 12, mParticleDetailSlider);
+
+ place(1, 7, alphaLabel, 2);
+ place(1, 8, mFpsCheckBox).setPadding(3);
+ place(1, 9, scrollRadiusLabel);
+ place(1, 10, scrollLazinessLabel);
+ place(1, 11, overlayDetailLabel);
+ place(1, 12, particleDetailLabel);
+
+ place(2, 8, mFpsField).setPadding(1);
+ place(2, 9, mScrollRadiusField).setPadding(1);
+ place(2, 10, mScrollLazinessField).setPadding(1);
+ place(2, 11, mOverlayDetailField, 2).setPadding(2);
+ place(2, 12, mParticleDetailField, 2).setPadding(2);
setDimension(gcn::Rectangle(0, 0, 295, 250));
}
@@ -284,9 +300,9 @@ void Setup_Video::apply()
if (!graphics->setFullscreen(fullscreen))
{
std::stringstream error;
- error << "Failed to switch to " <<
- (fullscreen ? "windowed" : "fullscreen") <<
- "mode and restoration of old mode also failed!" <<
+ error << _("Failed to switch to ") <<
+ (fullscreen ? _("windowed") : _("fullscreen")) <<
+ _("mode and restoration of old mode also failed!") <<
std::endl;
logger->error(error.str());
}
@@ -316,8 +332,11 @@ void Setup_Video::apply()
// We sync old and new values at apply time
mFullScreenEnabled = config.getValue("screen", 0);
mCustomCursorEnabled = config.getValue("customcursor", 1);
+ mParticleEffectsEnabled = config.getValue("particleeffects", 1);
+ mSpeechBubbleEnabled = config.getValue("speechbubble", 1);
+ mNameEnabled = config.getValue("showownname", 0);
mOpacity = config.getValue("guialpha", 0.8);
- mOverlayDetail = (int)config.getValue("OverlayDetail", 2);
+ mOverlayDetail = (int) config.getValue("OverlayDetail", 2);
mOpenGLEnabled = config.getValue("opengl", 0);
}
@@ -346,6 +365,9 @@ void Setup_Video::cancel()
mFsCheckBox->setSelected(mFullScreenEnabled);
mOpenGLCheckBox->setSelected(mOpenGLEnabled);
mCustomCursorCheckBox->setSelected(mCustomCursorEnabled);
+ mParticleEffectsCheckBox->setSelected(mParticleEffectsEnabled);
+ mSpeechBubbleCheckBox->setSelected(mSpeechBubbleEnabled);
+ mNameCheckBox->setSelected(mNameEnabled);
mAlphaSlider->setValue(mOpacity);
mOverlayDetailSlider->setValue(mOverlayDetail);
mParticleDetailSlider->setValue(mParticleDetail);
@@ -357,13 +379,46 @@ void Setup_Video::cancel()
config.setValue("screen", mFullScreenEnabled ? 1 : 0);
config.setValue("customcursor", mCustomCursorEnabled ? 1 : 0);
+ config.setValue("particleeffects", mParticleEffectsEnabled ? 1 : 0);
+ config.setValue("speechbubble", mSpeechBubbleEnabled ? 1 : 0);
+ config.setValue("showownname", mNameEnabled ? 1 : 0);
config.setValue("guialpha", mOpacity);
config.setValue("opengl", mOpenGLEnabled ? 1 : 0);
}
void Setup_Video::action(const gcn::ActionEvent &event)
{
- if (event.getId() == "guialpha")
+ if (event.getId() == "videomode")
+ {
+ const std::string mode = mModeListModel->getElementAt(mModeList->getSelected());
+ const int width = atoi(mode.substr(0, mode.find("x")).c_str());
+ const int height = atoi(mode.substr(mode.find("x") + 1).c_str());
+ const int bpp = 0;
+ const bool fullscreen = ((int) config.getValue("screen", 0) == 1);
+ const bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1);
+
+ // Try to set the desired video mode
+ if (!graphics->setVideoMode(width, height, bpp, fullscreen, hwaccel))
+ {
+ std::cerr << _("Couldn't set ")
+ << width << "x" << height << "x" << bpp << _(" video mode: ")
+ << SDL_GetError() << std::endl;
+ exit(1);
+ }
+
+ // Initialize for drawing
+ graphics->_endDraw();
+ graphics->_beginDraw();
+ graphics->updateScreen();
+
+ // TODO: Find out why the drawing area doesn't resize without a restart.
+ new OkDialog(_("Screen resolution changed"),
+ _("Restart your client for the change to take effect."));
+
+ config.setValue("screenwidth", width);
+ config.setValue("screenheight", height);
+ }
+ else if (event.getId() == "guialpha")
{
config.setValue("guialpha", mAlphaSlider->getValue());
}
@@ -372,6 +427,27 @@ void Setup_Video::action(const gcn::ActionEvent &event)
config.setValue("customcursor",
mCustomCursorCheckBox->isSelected() ? 1 : 0);
}
+ else if (event.getId() == "particleeffects")
+ {
+ config.setValue("particleeffects",
+ mParticleEffectsCheckBox->isSelected() ? 1 : 0);
+ new OkDialog(_("Particle effect settings changed"),
+ _("Restart your client or change maps for the change to take effect."));
+ }
+ else if (event.getId() == "speechbubble")
+ {
+ config.setValue("speechbubble",
+ mSpeechBubbleCheckBox->isSelected() ? 1 : 0);
+ }
+ else if (event.getId() == "showownname")
+ {
+ // Notify the local player that settings have changed for the name
+ // and requires an update
+ if (player_node)
+ player_node->mUpdateName = true;
+ config.setValue("showownname",
+ mNameCheckBox->isSelected() ? 1 : 0);
+ }
else if (event.getId() == "fpslimitslider")
{
mFps = (int) mFpsSlider->getValue();
diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h
index b7011186..d863fb64 100644
--- a/src/gui/setup_video.h
+++ b/src/gui/setup_video.h
@@ -22,11 +22,11 @@
#ifndef GUI_SETUP_VIDEO_H
#define GUI_SETUP_VIDEO_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
+#include "setuptab.h"
+
#include "../guichanfwd.h"
class Setup_Video : public SetupTab, public gcn::ActionListener,
@@ -53,6 +53,9 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
bool mFullScreenEnabled;
bool mOpenGLEnabled;
bool mCustomCursorEnabled;
+ bool mParticleEffectsEnabled;
+ bool mSpeechBubbleEnabled;
+ bool mNameEnabled;
double mOpacity;
int mFps;
@@ -62,6 +65,9 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
gcn::CheckBox *mFsCheckBox;
gcn::CheckBox *mOpenGLCheckBox;
gcn::CheckBox *mCustomCursorCheckBox;
+ gcn::CheckBox *mParticleEffectsCheckBox;
+ gcn::CheckBox *mSpeechBubbleCheckBox;
+ gcn::CheckBox *mNameCheckBox;
gcn::Slider *mAlphaSlider;
gcn::CheckBox *mFpsCheckBox;
diff --git a/src/gui/shop.h b/src/gui/shop.h
index 4a03b2bc..22b649d0 100644
--- a/src/gui/shop.h
+++ b/src/gui/shop.h
@@ -27,10 +27,11 @@
#include <guichan/listmodel.hpp>
-#include "../resources/image.h"
-
+#include "../guichanfwd.h"
#include "../shopitem.h"
+#include "../resources/image.h"
+
class ShopItems : public gcn::ListModel
{
public:
diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp
index 2517d749..765b9f08 100644
--- a/src/gui/shoplistbox.cpp
+++ b/src/gui/shoplistbox.cpp
@@ -19,14 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "shoplistbox.h"
-
+#include <guichan/basiccontainer.hpp>
#include <guichan/font.hpp>
#include <guichan/graphics.hpp>
+#include <guichan/imagefont.hpp>
#include <guichan/listmodel.hpp>
#include <guichan/mouseinput.hpp>
-#include <guichan/imagefont.hpp>
-#include <guichan/basiccontainer.hpp>
+
+#include "shoplistbox.h"
#include "../graphics.h"
@@ -72,7 +72,7 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics)
if (i == mSelected)
{
- backgroundColor = gcn::Color(110, 160, 255);
+ backgroundColor = gcn::Color(235, 200, 115);
}
else if (mShopItems &&
mPlayerMoney < mShopItems->at(i)->getPrice() && mPriceCheck)
diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h
index bad848d6..733af4eb 100644
--- a/src/gui/shoplistbox.h
+++ b/src/gui/shoplistbox.h
@@ -25,6 +25,8 @@
#include "listbox.h"
#include "shop.h"
+#include "../guichanfwd.h"
+
/**
* A list box, meant to be used inside a scroll area. Same as the Guichan list
* box except this one doesn't have a background, instead completely relying
diff --git a/src/gui/shortcutcontainer.cpp b/src/gui/shortcutcontainer.cpp
new file mode 100644
index 00000000..d03bc809
--- /dev/null
+++ b/src/gui/shortcutcontainer.cpp
@@ -0,0 +1,76 @@
+/*
+ * The Mana World
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "shortcutcontainer.h"
+
+#include "../graphics.h"
+#include "../inventory.h"
+#include "../item.h"
+#include "../itemshortcut.h"
+#include "../keyboardconfig.h"
+#include "../localplayer.h"
+
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+
+#include "../utils/tostring.h"
+
+ShortcutContainer::ShortcutContainer():
+ mGridWidth(1),
+ mGridHeight(1)
+{
+}
+
+
+void ShortcutContainer::widgetResized(const gcn::Event &event)
+{
+ mGridWidth = getWidth() / mBoxWidth;
+ if (mGridWidth < 1)
+ {
+ mGridWidth = 1;
+ }
+
+ setHeight((mMaxItems / mGridWidth +
+ (mMaxItems % mGridWidth > 0 ? 1 : 0)) * mBoxHeight);
+
+ mGridHeight = getHeight() / mBoxHeight;
+ if (mGridHeight < 1)
+ {
+ mGridHeight = 1;
+ }
+}
+
+int ShortcutContainer::getIndexFromGrid(int pointX, int pointY) const
+{
+ const gcn::Rectangle tRect = gcn::Rectangle(
+ 0, 0, mGridWidth * mBoxWidth, mGridHeight * mBoxHeight);
+ if (!tRect.isPointInRect(pointX, pointY))
+ {
+ return -1;
+ }
+ const int index = ((pointY / mBoxHeight) * mGridWidth) +
+ pointX / mBoxWidth;
+ if (index >= mMaxItems)
+ {
+ return -1;
+ }
+ return index;
+}
diff --git a/src/gui/shortcutcontainer.h b/src/gui/shortcutcontainer.h
new file mode 100644
index 00000000..66aca6c3
--- /dev/null
+++ b/src/gui/shortcutcontainer.h
@@ -0,0 +1,107 @@
+/*
+ * The Mana World
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef SHORTCUTCONTAINER_H__
+#define SHORTCUTCONTAINER_H__
+
+#include <guichan/mouselistener.hpp>
+#include <guichan/widget.hpp>
+#include <guichan/widgetlistener.hpp>
+
+#include "../guichanfwd.h"
+
+class Image;
+
+/**
+ * An item shortcut container. Used to quickly use items.
+ *
+ * \ingroup GUI
+ */
+class ShortcutContainer : public gcn::Widget,
+ public gcn::WidgetListener,
+ public gcn::MouseListener
+{
+ public:
+ /**
+ * Constructor. Initializes the graphic.
+ */
+ ShortcutContainer();
+
+ /**
+ * Destructor.
+ */
+ ~ShortcutContainer(){}
+
+ /**
+ * Draws the items.
+ */
+ virtual void draw(gcn::Graphics *graphics) = 0;
+
+ /**
+ * Invoked when a widget changes its size. This is used to determine
+ * the new height of the container.
+ */
+ virtual void widgetResized(const gcn::Event &event);
+
+ /**
+ * Handles mouse when dragged.
+ */
+ virtual void mouseDragged(gcn::MouseEvent &event) = 0;
+
+ /**
+ * Handles mouse when pressed.
+ */
+ virtual void mousePressed(gcn::MouseEvent &event) = 0;
+
+ /**
+ * Handles mouse release.
+ */
+ virtual void mouseReleased(gcn::MouseEvent &event) = 0;
+
+ virtual int getMaxItems()
+ { return mMaxItems; }
+
+ virtual int getBoxWidth()
+ { return mBoxWidth; }
+
+ virtual int getBoxHeight()
+ { return mBoxHeight; }
+
+ protected:
+ /**
+ * Gets the index from the grid provided the point is in an item box.
+ *
+ * @param pointX X coordinate of the point.
+ * @param pointY Y coordinate of the point.
+ * @return index on success, -1 on failure.
+ */
+ int getIndexFromGrid(int pointX, int pointY) const;
+
+ Image *mBackgroundImg;
+
+ int mMaxItems;
+ int mBoxWidth;
+ int mBoxHeight;
+ int mCursorPosX, mCursorPosY;
+ int mGridWidth, mGridHeight;
+};
+
+#endif
diff --git a/src/gui/itemshortcutwindow.cpp b/src/gui/shortcutwindow.cpp
index 6fe1a10b..3a7cf0e0 100644
--- a/src/gui/itemshortcutwindow.cpp
+++ b/src/gui/shortcutwindow.cpp
@@ -19,23 +19,23 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "itemshortcutwindow.h"
-
-#include "itemshortcutcontainer.h"
+#include "shortcutcontainer.h"
+#include "shortcutwindow.h"
#include "scrollarea.h"
+#include "../configuration.h"
+
static const int SCROLL_PADDING = 0;
-ItemShortcutWindow::ItemShortcutWindow()
+ShortcutWindow::ShortcutWindow(const char *title, ShortcutContainer *content)
{
- setWindowName("ItemShortcut");
+ setWindowName(title);
// no title presented, title bar is padding so window can be moved.
gcn::Window::setTitleBarHeight(gcn::Window::getPadding());
setShowTitle(false);
setResizable(true);
- setDefaultSize(758, 174, 42, 426);
- mItems = new ItemShortcutContainer;
+ mItems = content;
const int border = SCROLL_PADDING * 2 + getPadding() * 2;
setMinWidth(mItems->getBoxWidth() + border);
@@ -43,6 +43,14 @@ ItemShortcutWindow::ItemShortcutWindow()
setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border);
setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border);
+ const int width = (int) config.getValue("screenwidth", 800);
+ const int height = (int) config.getValue("screenheight", 600);
+
+ setDefaultSize(width - mItems->getBoxWidth() - border,
+ height - (mItems->getBoxHeight() * mItems->getMaxItems()) -
+ border, mItems->getBoxWidth() + border,
+ (mItems->getBoxHeight() * mItems->getMaxItems()) + border);
+
mScrollArea = new ScrollArea(mItems);
mScrollArea->setPosition(SCROLL_PADDING, SCROLL_PADDING);
mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
@@ -53,13 +61,13 @@ ItemShortcutWindow::ItemShortcutWindow()
loadWindowState();
}
-ItemShortcutWindow::~ItemShortcutWindow()
+ShortcutWindow::~ShortcutWindow()
{
delete mItems;
delete mScrollArea;
}
-void ItemShortcutWindow::widgetResized(const gcn::Event &event)
+void ShortcutWindow::widgetResized(const gcn::Event &event)
{
Window::widgetResized(event);
diff --git a/src/gui/itemshortcutwindow.h b/src/gui/shortcutwindow.h
index baa34b13..0168669e 100644
--- a/src/gui/itemshortcutwindow.h
+++ b/src/gui/shortcutwindow.h
@@ -19,12 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef ITEMSHORTCUTWINDOW_H
-#define ITEMSHORTCUTWINDOW_H
+#ifndef SHORTCUTWINDOW_H
+#define SHORTCUTWINDOW_H
#include "window.h"
-class ItemShortcutContainer;
+#include "../guichanfwd.h"
+
+class ShortcutContainer;
class ScrollArea;
/**
@@ -32,18 +34,18 @@ class ScrollArea;
*
* \ingroup Interface
*/
-class ItemShortcutWindow : public Window
+class ShortcutWindow : public Window
{
public:
/**
* Constructor.
*/
- ItemShortcutWindow();
+ ShortcutWindow(const char *title, ShortcutContainer *content);
/**
* Destructor.
*/
- ~ItemShortcutWindow();
+ ~ShortcutWindow();
/**
* Called whenever the widget changes size.
@@ -51,11 +53,13 @@ class ItemShortcutWindow : public Window
void widgetResized(const gcn::Event &event);
private:
- ItemShortcutContainer *mItems;
+ ShortcutWindow();
+ ShortcutContainer *mItems;
ScrollArea *mScrollArea;
};
-extern ItemShortcutWindow *itemShortcutWindow;
+extern ShortcutWindow *itemShortcutWindow;
+extern ShortcutWindow *emoteShortcutWindow;
#endif
diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp
index 4afd913d..304719b6 100644
--- a/src/gui/skill.cpp
+++ b/src/gui/skill.cpp
@@ -21,13 +21,13 @@
#include <guichan/widgets/label.hpp>
-#include "skill.h"
-
#include "button.h"
#include "listbox.h"
-#include "scrollarea.h"
+#include "skill.h"
#include "windowcontainer.h"
+#include "widgets/layout.h"
+
#include "../localplayer.h"
#include "../log.h"
@@ -36,7 +36,7 @@
#include "../utils/strprintf.h"
#include "../utils/xml.h"
-static const char *SKILLS_FILE = "skills.xml";
+static const char *SKILLS_FILE = _("skills.xml");
struct SkillInfo {
std::string name;
@@ -51,21 +51,24 @@ class SkillGuiTableModel : public StaticTableModel
{
public:
SkillGuiTableModel(SkillDialog *dialog) :
- StaticTableModel(0, 3)
+ StaticTableModel(0, 3, 0xbdb5aa)
{
mEntriesNr = 0;
mDialog = dialog;
update();
}
- virtual int getRows() { return mEntriesNr; }
+ virtual int getRows(void)
+ {
+ return mEntriesNr;
+ }
virtual int getColumnWidth(int index)
{
- switch (index) {
- case 0: return 160;
- default: return 35;
- }
+ if (index == 0)
+ return 160;
+
+ return 35;
}
virtual int getRowHeight()
@@ -83,7 +86,8 @@ public:
mEntriesNr = mDialog->getSkills().size();
resize();
- for (int i = 0; i < mEntriesNr; i++) {
+ for (int i = 0; i < mEntriesNr; i++)
+ {
SKILL *skill = mDialog->getSkills()[i];
SkillInfo const *info;
char tmp[128];
@@ -123,31 +127,33 @@ SkillDialog::SkillDialog():
mTable.setModel(mTableModel);
mTable.setLinewiseSelection(true);
- setWindowName("Skills");
+ setWindowName(_("Skills"));
setCloseButton(true);
setDefaultSize(windowContainer->getWidth() - 260, 25, 255, 260);
+ setMinHeight(50 + mTableModel->getHeight());
+ setMinWidth(200);
+
// mSkillListBox = new ListBox(this);
ScrollArea *skillScrollArea = new ScrollArea(&mTable);
mPointsLabel = new gcn::Label(strprintf(_("Skill points: %d"), 0));
- mIncButton = new Button(_("Up"), "inc", this);
- mUseButton = new Button(_("Use"), "use", this);
+ mIncButton = new Button(_("Up"), _("inc"), this);
+ mUseButton = new Button(_("Use"), _("use"), this);
mUseButton->setEnabled(false);
// mSkillListBox->setActionEventId("skill");
mTable.setActionEventId("skill");
skillScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
- skillScrollArea->setDimension(gcn::Rectangle(5, 5, 230, 180));
- mPointsLabel->setDimension(gcn::Rectangle(8, 190, 200, 16));
- mIncButton->setPosition(skillScrollArea->getX(), 210);
- mUseButton->setPosition(mIncButton->getX() + mIncButton->getWidth() + 5,
- 210);
+ skillScrollArea->setOpaque(false);
+
+ place(0, 0, skillScrollArea, 5).setPadding(3);
+ place(0, 1, mPointsLabel, 2);
+ place(3, 2, mIncButton);
+ place(4, 2, mUseButton);
- add(skillScrollArea);
- add(mPointsLabel);
- add(mIncButton);
- add(mUseButton);
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
// mSkillListBox->addActionListener(this);
mTable.addActionListener(this);
@@ -167,9 +173,7 @@ void SkillDialog::action(const gcn::ActionEvent &event)
// Increment skill
int selectedSkill = mTable.getSelectedRow();//mSkillListBox->getSelected();
if (selectedSkill >= 0)
- {
player_node->raiseSkill(mSkillList[selectedSkill]->id);
- }
}
else if (event.getId() == "skill")
{
@@ -178,9 +182,7 @@ void SkillDialog::action(const gcn::ActionEvent &event)
player_node->mSkillPoint > 0);
}
else if (event.getId() == "close")
- {
setVisible(false);
- }
}
void SkillDialog::update()
@@ -190,7 +192,8 @@ void SkillDialog::update()
int selectedSkill = mTable.getSelectedRow();
- if (selectedSkill >= 0) {
+ if (selectedSkill >= 0)
+ {
int skillId = mSkillList[selectedSkill]->id;
bool modifiable;
@@ -201,10 +204,12 @@ void SkillDialog::update()
mIncButton->setEnabled(modifiable
&& player_node->mSkillPoint > 0);
- } else
+ }
+ else
mIncButton->setEnabled(false);
mTableModel->update();
+ setMinHeight(50 + mTableModel->getHeight());
}
int SkillDialog::getNumberOfElements()
@@ -214,10 +219,10 @@ int SkillDialog::getNumberOfElements()
bool SkillDialog::hasSkill(int id)
{
- for (unsigned int i = 0; i < mSkillList.size(); i++) {
- if (mSkillList[i]->id == id) {
+ for (unsigned int i = 0; i < mSkillList.size(); i++)
+ {
+ if (mSkillList[i]->id == id)
return true;
- }
}
return false;
}
@@ -233,8 +238,10 @@ void SkillDialog::addSkill(int id, int lvl, int mp)
void SkillDialog::setSkill(int id, int lvl, int mp)
{
- for (unsigned int i = 0; i < mSkillList.size(); i++) {
- if (mSkillList[i]->id == id) {
+ for (unsigned int i = 0; i < mSkillList.size(); i++)
+ {
+ if (mSkillList[i]->id == id)
+ {
mSkillList[i]->lv = lvl;
mSkillList[i]->sp = mp;
}
@@ -256,7 +263,7 @@ static void initSkillinfo()
if (!root || !xmlStrEqual(root->name, BAD_CAST "skills"))
{
- logger->log("Error loading skills file: %s", SKILLS_FILE);
+ logger->log(_("Error loading skills file: %s"), SKILLS_FILE);
skill_db.resize(2, emptySkillInfo);
skill_db[1].name = "Basic";
skill_db[1].modifiable = true;
diff --git a/src/gui/skill.h b/src/gui/skill.h
index 893a61e7..582892f0 100644
--- a/src/gui/skill.h
+++ b/src/gui/skill.h
@@ -24,9 +24,11 @@
#include <vector>
-#include <guichan/listmodel.hpp>
#include <guichan/actionlistener.hpp>
+#include <guichan/listmodel.hpp>
+#include "scrollarea.h"
+#include "table.h"
#include "window.h"
#include "table.h"
@@ -72,6 +74,7 @@ class SkillDialog : public Window, public gcn::ActionListener
private:
GuiTable mTable;//gcn::ListBox *mSkillListBox;
+ ScrollArea *skillScrollArea;
SkillGuiTableModel *mTableModel;
gcn::Label *mPointsLabel;
gcn::Button *mIncButton;
diff --git a/src/gui/slider.h b/src/gui/slider.h
index 1fe668c5..c14c5be9 100644
--- a/src/gui/slider.h
+++ b/src/gui/slider.h
@@ -24,8 +24,9 @@
#include <guichan/widgets/slider.hpp>
-class Image;
+#include "../guichanfwd.h"
+class Image;
/**
* Slider widget. Same as the Guichan slider but with custom look.
diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp
new file mode 100644
index 00000000..a6bb5563
--- /dev/null
+++ b/src/gui/speechbubble.cpp
@@ -0,0 +1,111 @@
+/*
+ * The Legend of Mazzeroth
+ * Copyright (C) 2008, The Legend of Mazzeroth Development Team
+ *
+ * This file is part of The Legend of Mazzeroth based on original code
+ * from The Mana World.
+ *
+ * The Legend of Mazzeroth is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Legend of Mazzeroth is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Legend of Mazzeroth; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/font.hpp>
+
+#include <guichan/widgets/label.hpp>
+
+#include "gui.h"
+#include "speechbubble.h"
+
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+
+#include "../utils/gettext.h"
+
+// TODO: Fix windows so that they can each load their own skins without the
+// other windows overriding another window's skin.
+SpeechBubble::SpeechBubble():
+ Window(_("Speech"), false, NULL, "graphics/gui/speechbubble.xml")
+{
+ // Height == Top Graphic (14px) + 1 Row of Text (15px) + Bottom Graphic (17px)
+ setContentSize(140, 46);
+ setShowTitle(false);
+ setTitleBarHeight(0);
+
+ mCaption = new gcn::Label("");
+ mCaption->setFont(boldFont);
+ mCaption->setPosition(5, 3);
+
+ mSpeechBox = new TextBox();
+ mSpeechBox->setEditable(false);
+ mSpeechBox->setOpaque(false);
+
+ mSpeechArea = new ScrollArea(mSpeechBox);
+
+ mSpeechArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mSpeechArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mSpeechArea->setDimension(gcn::Rectangle(4, boldFont->getHeight() + 3,
+ 130, 28));
+ mSpeechArea->setOpaque(false);
+
+ add(mCaption);
+ add(mSpeechArea);
+
+ setLocationRelativeTo(getParent());
+
+ // LEEOR / TODO: This causes an exception error.
+ //moveToBottom(getParent());
+
+ mSpeechBox->setTextWrapped( "" );
+}
+
+void SpeechBubble::setCaption(const std::string &name, const gcn::Color &color)
+{
+ mCaption->setCaption(name);
+ mCaption->adjustSize();
+ mCaption->setForegroundColor(color);
+}
+
+void SpeechBubble::setText(std::string mText)
+{
+ mSpeechBox->setMinWidth(140);
+ mSpeechBox->setTextWrapped(mText);
+
+ const int fontHeight = getFont()->getHeight();
+ const int numRows = mSpeechBox->getNumberOfRows() + 1;
+
+ if (numRows > 2)
+ {
+ // 15 == height of each line of text (based on font heights)
+ // 14 == speechbubble Top + Bottom graphic pixel heights
+ setContentSize(mSpeechBox->getMinWidth() + fontHeight,
+ (numRows * fontHeight) + 6);
+ mSpeechArea->setDimension(gcn::Rectangle(4, fontHeight + 3,
+ mSpeechBox->getMinWidth() + 5,
+ (numRows * fontHeight)));
+ }
+ else
+ {
+ int width = mCaption->getWidth() + 3;
+ if (width < getFont()->getWidth(mText))
+ width = getFont()->getWidth(mText);
+ setContentSize(width + fontHeight, (fontHeight * 2) + 6);
+ mSpeechArea->setDimension(gcn::Rectangle(4, fontHeight + 3,
+ width, fontHeight));
+ }
+}
+
+unsigned int SpeechBubble::getNumRows()
+{
+ return mSpeechBox->getNumberOfRows();
+}
diff --git a/src/gui/speechbubble.h b/src/gui/speechbubble.h
new file mode 100644
index 00000000..23733813
--- /dev/null
+++ b/src/gui/speechbubble.h
@@ -0,0 +1,48 @@
+/*
+ * The Legend of Mazzeroth
+ * Copyright (C) 2008, The Legend of Mazzeroth Development Team
+ *
+ * This file is part of The Legend of Mazzeroth based on original code
+ * from The Mana World.
+ *
+ * The Legend of Mazzeroth is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Legend of Mazzeroth is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Legend of Mazzeroth; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _LOM_SPEECHBUBBLE_H__
+#define _LOM_SPEECHBUBBLE_H__
+
+#include "scrollarea.h"
+#include "textbox.h"
+#include "window.h"
+
+class SpeechBubble : public Window
+{
+ public:
+
+ SpeechBubble();
+
+ void setCaption(const std::string &name,
+ const gcn::Color &color = 0x000000);
+ void setText(std::string mText);
+ void setLocation(int x, int y);
+ unsigned int getNumRows();
+
+ private:
+ gcn::Label *mCaption;
+ TextBox *mSpeechBox;
+ ScrollArea *mSpeechArea;
+};
+
+#endif
diff --git a/src/gui/status.cpp b/src/gui/status.cpp
index b95a1eb8..bd6048f3 100644
--- a/src/gui/status.cpp
+++ b/src/gui/status.cpp
@@ -19,12 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "status.h"
-
#include <guichan/widgets/label.hpp>
#include "button.h"
#include "progressbar.h"
+#include "status.h"
#include "windowcontainer.h"
#include "../localplayer.h"
@@ -37,11 +36,10 @@ StatusWindow::StatusWindow(LocalPlayer *player):
Window(player->getName()),
mPlayer(player)
{
- setWindowName("Status");
- setResizable(true);
+ setWindowName(_("Status"));
setCloseButton(true);
setDefaultSize((windowContainer->getWidth() - 365) / 2,
- (windowContainer->getHeight() - 255) / 2, 365, 275);
+ (windowContainer->getHeight() - 255) / 2, 400, 275);
loadWindowState();
// ----------------------
@@ -52,19 +50,19 @@ StatusWindow::StatusWindow(LocalPlayer *player):
mGpLabel = new gcn::Label(strprintf(_("Job: %d"), 0));
mJobLvlLabel = new gcn::Label(strprintf(_("Money: %d GP"), 0));
- mHpLabel = new gcn::Label("HP:");
+ mHpLabel = new gcn::Label(_("HP:"));
mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34);
mHpValueLabel = new gcn::Label;
- mXpLabel = new gcn::Label("Exp:");
+ mXpLabel = new gcn::Label(_("Exp:"));
mXpBar = new ProgressBar(1.0f, 80, 15, 143, 192, 211);
mXpValueLabel = new gcn::Label;
- mMpLabel = new gcn::Label("MP:");
+ mMpLabel = new gcn::Label(_("MP:"));
mMpBar = new ProgressBar(1.0f, 80, 15, 26, 102, 230);
mMpValueLabel = new gcn::Label;
- mJobXpLabel = new gcn::Label("Job:");
+ mJobXpLabel = new gcn::Label(_("Job:"));
mJobXpBar = new ProgressBar(1.0f, 80, 15, 220, 135, 203);
mJobValueLabel = new gcn::Label;
diff --git a/src/gui/status.h b/src/gui/status.h
index 6d360caf..14a7617e 100644
--- a/src/gui/status.h
+++ b/src/gui/status.h
@@ -33,7 +33,6 @@
class LocalPlayer;
class ProgressBar;
-
/**
* The player status dialog.
*
diff --git a/src/gui/table.cpp b/src/gui/table.cpp
index f6678737..7e855523 100644
--- a/src/gui/table.cpp
+++ b/src/gui/table.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "table.h"
+#include <cassert>
#include <guichan/graphics.hpp>
#include <guichan/actionlistener.hpp>
-#include <cassert>
-
+#include "table.h"
class GuiTableActionListener : public gcn::ActionListener
{
@@ -100,6 +99,7 @@ void GuiTable::setModel(TableModel *new_model)
mModel->removeListener(this);
}
+
mModel = new_model;
installActionListeners();
@@ -109,7 +109,6 @@ void GuiTable::setModel(TableModel *new_model)
}
}
-
void GuiTable::recomputeDimensions()
{
int rows_nr = mModel->getRows();
@@ -296,7 +295,6 @@ void GuiTable::keyPressed(gcn::KeyEvent& keyEvent)
{
}
-
// -- MouseListener notifications
void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent)
{
@@ -386,7 +384,6 @@ int GuiTable::getColumnForX(int x)
return column;
}
-
void GuiTable::_setFocusHandler(gcn::FocusHandler* focusHandler)
{
gcn::Widget::_setFocusHandler(focusHandler);
diff --git a/src/gui/table.h b/src/gui/table.h
index c7ede36c..9dde8900 100644
--- a/src/gui/table.h
+++ b/src/gui/table.h
@@ -31,6 +31,7 @@
#include <guichan/widget.hpp>
#include "table_model.h"
+
#include "../guichanfwd.h"
class GuiTableActionListener;
diff --git a/src/gui/table_model.cpp b/src/gui/table_model.cpp
index 7bc29b47..e69ee808 100644
--- a/src/gui/table_model.cpp
+++ b/src/gui/table_model.cpp
@@ -19,10 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "table_model.h"
+#include <cstdlib>
+#include <guichan/graphics.hpp>
#include <guichan/widget.hpp>
-#include <cstdlib>
+
+#include "table_model.h"
#include "../utils/dtor.h"
@@ -49,14 +51,16 @@ void TableModel::signalAfterUpdate()
}
-
#define WIDGET_AT(row, column) (((row) * mColumns) + (column))
#define DYN_SIZE(h) ((h) >= 0) // determines whether this size is tagged for auto-detection
-StaticTableModel::StaticTableModel(int row, int column) :
+StaticTableModel::StaticTableModel(int row, int column,
+ gcn::Color backgroundColor, bool opacity) :
mRows(row),
mColumns(column),
- mHeight(1)
+ mHeight(1),
+ mOpaque(opacity),
+ mBackgroundColor(backgroundColor)
{
mTableModel.resize(row * column, NULL);
mWidths.resize(column, 1);
@@ -143,3 +147,42 @@ int StaticTableModel::getColumns()
{
return mColumns;
}
+
+int StaticTableModel::getWidth(void)
+{
+ int width = 0;
+
+ for (unsigned int i = 0; i < mWidths.size(); i++)
+ {
+ width += mWidths[i];
+ }
+
+ return width;
+}
+
+int StaticTableModel::getHeight(void)
+{
+ return (mColumns * mHeight);
+}
+
+void StaticTableModel::drawBackground(gcn::Graphics *graphics)
+{
+ if (isOpaque())
+ {
+ for (unsigned int i = 0; i < mTableModel.size(); i++)
+ {
+ mTableModel[i]->setBackgroundColor(mBackgroundColor);
+ }
+ }
+}
+
+void StaticTableModel::setOpaque(bool opaque)
+{
+ mOpaque = opaque;
+}
+
+bool StaticTableModel::isOpaque() const
+{
+ return mOpaque;
+}
+
diff --git a/src/gui/table_model.h b/src/gui/table_model.h
index d245d7bd..03b69dba 100644
--- a/src/gui/table_model.h
+++ b/src/gui/table_model.h
@@ -22,12 +22,13 @@
#ifndef TABLE_MODEL_H
#define TABLE_MODEL_H
-#include "../guichanfwd.h"
+#include <set>
+#include <vector>
+#include <guichan/color.hpp>
#include <guichan/gui.hpp>
-#include <set>
-#include <vector>
+#include "../guichanfwd.h"
class TableModelListener
{
@@ -100,7 +101,8 @@ private:
class StaticTableModel : public TableModel
{
public:
- StaticTableModel(int width, int height);
+ StaticTableModel(int width, int height, gcn::Color background = 0xffffff,
+ bool opacity = true);
virtual ~StaticTableModel();
/**
@@ -130,17 +132,49 @@ public:
*/
virtual void resize();
+ /**
+ * Sets the table to be opaque, that is sets the table
+ * to display its background.
+ *
+ * @param opaque True if the table should be opaque, false otherwise.
+ */
+ virtual void setOpaque(bool opaque);
+
+ /**
+ * Checks if the scroll area is opaque, that is if the scroll area
+ * displays its background.
+ *
+ * @return True if the scroll area is opaque, false otherwise.
+ */
+ virtual bool isOpaque() const;
+
virtual int getRows();
virtual int getColumns();
virtual int getRowHeight();
+ virtual int getWidth();
+ virtual int getHeight();
virtual int getColumnWidth(int index);
virtual gcn::Widget *getElementAt(int row, int column);
protected:
int mRows, mColumns;
int mHeight;
+ bool mOpaque;
std::vector<gcn::Widget *> mTableModel;
std::vector<int> mWidths;
+
+ /**
+ * Holds the background color of the table.
+ */
+ gcn::Color mBackgroundColor;
+
+ /**
+ * Draws the background of the table, that is
+ * the area behind the content.
+ *
+ * @param graphics a Graphics object to draw with.
+ */
+ virtual void drawBackground(gcn::Graphics *graphics);
};
#endif /* !defined(TABLE_MODEL_H) */
diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp
index 75f0b5a1..ee03c79d 100644
--- a/src/gui/textbox.cpp
+++ b/src/gui/textbox.cpp
@@ -19,13 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "textbox.h"
-
#include <sstream>
#include <guichan/basiccontainer.hpp>
#include <guichan/font.hpp>
+#include "textbox.h"
+
TextBox::TextBox():
gcn::TextBox()
{
@@ -43,6 +43,8 @@ void TextBox::setTextWrapped(const std::string &text)
std::stringstream wrappedStream;
std::string::size_type newlinePos, lastNewlinePos = 0;
+ int minWidth = 0;
+ int xpos;
do
{
@@ -57,7 +59,7 @@ void TextBox::setTextWrapped(const std::string &text)
std::string line =
text.substr(lastNewlinePos, newlinePos - lastNewlinePos);
std::string::size_type spacePos, lastSpacePos = 0;
- int xpos = 0;
+ xpos = 0;
do
{
@@ -73,7 +75,7 @@ void TextBox::setTextWrapped(const std::string &text)
int width = getFont()->getWidth(word);
- if (xpos != 0 && xpos + width < getWidth())
+ if (xpos != 0 && xpos + width + getFont()->getWidth(" ") <= mMinWidth)
{
xpos += width + getFont()->getWidth(" ");
wrappedStream << " " << word;
@@ -85,10 +87,30 @@ void TextBox::setTextWrapped(const std::string &text)
}
else
{
+ if (xpos > minWidth)
+ {
+ minWidth = xpos;
+ }
+ // The window wasn't big enough. Resize it and try again.
+ if (minWidth > mMinWidth)
+ {
+ mMinWidth = minWidth;
+ wrappedStream.clear();
+ wrappedStream.str("");
+ spacePos = 0;
+ lastNewlinePos = 0;
+ newlinePos = text.find("\n", lastNewlinePos);
+ line = text.substr(lastNewlinePos, newlinePos -
+ lastNewlinePos);
+ width = 0;
+ break;
+ }
+ else
+ {
+ wrappedStream << "\n" << word;
+ }
xpos = width;
- wrappedStream << "\n" << word;
}
-
lastSpacePos = spacePos + 1;
}
while (spacePos != line.size());
@@ -97,10 +119,15 @@ void TextBox::setTextWrapped(const std::string &text)
{
wrappedStream << "\n";
}
-
lastNewlinePos = newlinePos + 1;
}
while (newlinePos != text.size());
+ if (xpos > minWidth)
+ {
+ minWidth = xpos;
+ }
+ mMinWidth = minWidth;
+
gcn::TextBox::setText(wrappedStream.str());
}
diff --git a/src/gui/textbox.h b/src/gui/textbox.h
index a42562ea..98b60402 100644
--- a/src/gui/textbox.h
+++ b/src/gui/textbox.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/textbox.hpp>
+#include "../guichanfwd.h"
+
/**
* A text box, meant to be used inside a scroll area. Same as the Guichan text
* box except this one doesn't have a background or border, instead completely
@@ -42,6 +44,19 @@ class TextBox : public gcn::TextBox {
* Sets the text after wrapping it to the current width of the widget.
*/
void setTextWrapped(const std::string &text);
+
+ /**
+ * Get the minimum text width for the text box.
+ */
+ int getMinWidth() { return mMinWidth; }
+
+ /**
+ * Set the minimum text width for the text box.
+ */
+ void setMinWidth(int width) { mMinWidth = width; }
+
+ private:
+ int mMinWidth;
};
#endif
diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp
index f7b02cbf..3369195d 100644
--- a/src/gui/textfield.cpp
+++ b/src/gui/textfield.cpp
@@ -19,14 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "textfield.h"
-
#include <algorithm>
#include <guichan/font.hpp>
#include "sdlinput.h"
+#include "textfield.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../resources/image.h"
@@ -40,7 +40,9 @@ int TextField::instances = 0;
ImageRect TextField::skin;
TextField::TextField(const std::string& text):
- gcn::TextField(text)
+ gcn::TextField(text),
+ mNumeric(false),
+ mListener(0)
{
setFrameSize(2);
@@ -62,6 +64,7 @@ TextField::TextField(const std::string& text):
gridx[x], gridy[y],
gridx[x + 1] - gridx[x] + 1,
gridy[y + 1] - gridy[y] + 1);
+ skin.grid[a]->setAlpha(config.getValue("guialpha", 0.8));
a++;
}
}
@@ -105,6 +108,42 @@ void TextField::drawFrame(gcn::Graphics *graphics)
static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin);
}
+void TextField::setNumeric(bool numeric)
+{
+ mNumeric = numeric;
+ if (!numeric)
+ {
+ return;
+ }
+ const char *text = mText.c_str();
+ for (const char *textPtr = text; *textPtr; ++textPtr)
+ {
+ if (*textPtr < '0' || *textPtr > '9')
+ {
+ setText(mText.substr(0, textPtr - text));
+ return;
+ }
+ }
+}
+
+int TextField::getValue() const
+{
+ if (!mNumeric)
+ {
+ return 0;
+ }
+ int value = atoi(mText.c_str());
+ if (value < mMinimum)
+ {
+ return mMinimum;
+ }
+ if (value > mMaximum)
+ {
+ return mMaximum;
+ }
+ return value;
+}
+
void TextField::keyPressed(gcn::KeyEvent &keyEvent)
{
int val = keyEvent.getKey().getValue();
diff --git a/src/gui/textfield.h b/src/gui/textfield.h
index 3570f89d..a2432175 100644
--- a/src/gui/textfield.h
+++ b/src/gui/textfield.h
@@ -24,7 +24,16 @@
#include <guichan/widgets/textfield.hpp>
+#include "../guichanfwd.h"
+
class ImageRect;
+class TextField;
+
+class TextFieldListener
+{
+ public:
+ virtual void listen(const TextField *value) = 0;
+};
/**
* A text field.
@@ -54,13 +63,47 @@ class TextField : public gcn::TextField {
void drawFrame(gcn::Graphics *graphics);
/**
+ * Determine whether the field should be numeric or not
+ */
+ void setNumeric(bool numeric);
+
+ /**
+ * Set the range on the field if it is numeric
+ */
+ void setRange(int min, int max) {mMinimum = min; mMaximum = max; }
+
+ /**
* Processes one keypress.
*/
void keyPressed(gcn::KeyEvent &keyEvent);
+ /**
+ * Set the minimum value for a range
+ */
+ void setMinimum(int min) {mMinimum = min; }
+
+ /**
+ * Set the maximum value for a range
+ */
+ void setMaximum(int max) {mMaximum = max; }
+
+ /**
+ * Return the value for a numeric field
+ */
+ int getValue() const;
+
+ /**
+ * Add a listener
+ */
+ void addListener(TextFieldListener *listener) {mListener = listener; }
+
private:
static int instances;
static ImageRect skin;
+ bool mNumeric;
+ int mMinimum;
+ int mMaximum;
+ TextFieldListener *mListener;
};
#endif
diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp
index 66df55b8..c89e55a2 100644
--- a/src/gui/trade.cpp
+++ b/src/gui/trade.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "trade.h"
-
#include <sstream>
#include <guichan/widgets/label.hpp>
@@ -32,9 +30,13 @@
#include "itemcontainer.h"
#include "scrollarea.h"
#include "textfield.h"
+#include "trade.h"
+
+#include "widgets/layout.h"
#include "../inventory.h"
#include "../item.h"
+#include "../localplayer.h"
#include "../net/messageout.h"
#include "../net/protocol.h"
@@ -46,12 +48,12 @@
#include "../utils/tostring.h"
TradeWindow::TradeWindow(Network *network):
- Window("Trade: You"),
+ Window(_("Trade: You")),
mNetwork(network),
- mMyInventory(new Inventory),
- mPartnerInventory(new Inventory)
+ mMyInventory(new Inventory(INVENTORY_SIZE)),
+ mPartnerInventory(new Inventory(INVENTORY_SIZE))
{
- setWindowName("Trade");
+ setWindowName(_("Trade"));
setDefaultSize(115, 227, 342, 209);
setResizable(true);
@@ -63,47 +65,43 @@ TradeWindow::TradeWindow(Network *network):
mCancelButton = new Button(_("Cancel"), "cancel", this);
mTradeButton = new Button(_("Trade"), "trade", this);
- mMyItemContainer = new ItemContainer(mMyInventory.get());
+ mTradeButton->setEnabled(false);
+
+ mMyItemContainer = new ItemContainer(mMyInventory.get(), 2);
+ mMyItemContainer->setWidth(160);
mMyItemContainer->addSelectionListener(this);
- mMyItemContainer->setPosition(2, 2);
mMyScroll = new ScrollArea(mMyItemContainer);
- mMyScroll->setPosition(8, 8);
- mPartnerItemContainer = new ItemContainer(mPartnerInventory.get());
+ mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 2);
+ mPartnerItemContainer->setWidth(160);
mPartnerItemContainer->addSelectionListener(this);
- mPartnerItemContainer->setPosition(2, 58);
mPartnerScroll = new ScrollArea(mPartnerItemContainer);
- mPartnerScroll->setPosition(8, 64);
mMoneyLabel = new gcn::Label(strprintf(_("You get %d GP."), 0));
mMoneyLabel2 = new gcn::Label(_("You give:"));
mMoneyField = new TextField;
mMoneyField->setWidth(50);
- mAddButton->adjustSize();
- mOkButton->adjustSize();
- mCancelButton->adjustSize();
- mTradeButton->adjustSize();
-
- mTradeButton->setEnabled(false);
-
- mItemNameLabel = new gcn::Label(strprintf(_("Name: %s"), ""));
- mItemDescriptionLabel = new gcn::Label(
- strprintf(_("Description: %s"), ""));
-
- add(mMyScroll);
- add(mPartnerScroll);
- add(mAddButton);
- add(mOkButton);
- add(mCancelButton);
- add(mTradeButton);
- add(mItemNameLabel);
- add(mItemDescriptionLabel);
- add(mMoneyLabel2);
- add(mMoneyField);
- add(mMoneyLabel);
+ place(1, 0, mMoneyLabel);
+ place(0, 1, mMyScroll).setPadding(3);
+ place(1, 1, mPartnerScroll).setPadding(3);
+ ContainerPlacer place;
+ place = getPlacer(0, 0);
+ place(0, 0, mMoneyLabel2);
+ place(1, 0, mMoneyField);
+ place = getPlacer(0, 2);
+ place(0, 0, mAddButton);
+ place(1, 0, mOkButton);
+ place(2, 0, mTradeButton);
+ place(3, 0, mCancelButton);
+ Layout &layout = getLayout();
+ layout.extend(0, 2, 2, 1);
+ layout.setRowHeight(1, Layout::AUTO_SET);
+ layout.setRowHeight(2, 0);
+ layout.setColWidth(0, Layout::AUTO_SET);
+ layout.setColWidth(1, Layout::AUTO_SET);
loadWindowState();
}
@@ -114,48 +112,13 @@ TradeWindow::~TradeWindow()
void TradeWindow::widgetResized(const gcn::Event &event)
{
- Window::widgetResized(event);
+ mMyItemContainer->setWidth(mMyScroll->getWidth());
+ mPartnerItemContainer->setWidth(mPartnerScroll->getWidth());
- const gcn::Rectangle &area = getChildrenArea();
- const int width = area.width;
- const int height = area.height;
-
- mMoneyLabel2->setPosition(8, height - 8 - mMoneyLabel2->getHeight());
- mMoneyField->setPosition(
- 8 + mMoneyLabel2->getWidth(),
- height - 8 - mMoneyField->getHeight());
- mMoneyLabel->setPosition(
- mMoneyField->getX() + mMoneyField->getWidth() + 6,
- mMoneyLabel2->getY());
-
- mCancelButton->setPosition(width - 8 - mCancelButton->getWidth(),
- height - 8 - mCancelButton->getHeight());
- mTradeButton->setPosition(
- mCancelButton->getX() - 4 - mTradeButton->getWidth(),
- mCancelButton->getY());
- mOkButton->setPosition(mTradeButton->getX() - 4 - mOkButton->getWidth(),
- mCancelButton->getY());
- mAddButton->setPosition(mOkButton->getX() - 4 - mAddButton->getWidth(),
- mCancelButton->getY());
-
- mItemDescriptionLabel->setPosition(8,
- mOkButton->getY() - mItemDescriptionLabel->getHeight() - 4);
- mItemNameLabel->setPosition(8,
- mItemDescriptionLabel->getY() - mItemNameLabel->getHeight() - 4);
-
- const int remaining = mItemNameLabel->getY() - 4 - 8 - 8;
- const int itemContainerHeight = remaining / 2;
-
- mMyItemContainer->setSize(width - 24 - 12 - 1,
- (INVENTORY_SIZE * 24) / (width / 24) - 1);
- mMyScroll->setSize(width - 16, itemContainerHeight);
-
- mPartnerItemContainer->setSize(width - 24 - 12 - 1,
- (INVENTORY_SIZE * 24) / (width / 24) - 1);
- mPartnerScroll->setSize(width - 16, itemContainerHeight);
- mPartnerScroll->setPosition(8, 8 + itemContainerHeight + 8);
+ Window::widgetResized(event);
}
+
void TradeWindow::addMoney(int amount)
{
mMoneyLabel->setCaption(strprintf(_("You get %d GP."), amount));
@@ -164,38 +127,40 @@ void TradeWindow::addMoney(int amount)
void TradeWindow::addItem(int id, bool own, int quantity, bool equipment)
{
- if (own) {
+ if (own)
+ {
+ mMyItemContainer->setWidth(mMyScroll->getWidth());
mMyInventory->addItem(id, quantity, equipment);
- } else {
+ }
+ else
+ {
+ mPartnerItemContainer->setWidth(mPartnerScroll->getWidth());
mPartnerInventory->addItem(id, quantity, equipment);
}
}
void TradeWindow::removeItem(int id, bool own)
{
- if (own) {
+ if (own)
mMyInventory->removeItem(id);
- } else {
+ else
mPartnerInventory->removeItem(id);
- }
}
void TradeWindow::changeQuantity(int index, bool own, int quantity)
{
- if (own) {
+ if (own)
mMyInventory->getItem(index)->setQuantity(quantity);
- } else {
+ else
mPartnerInventory->getItem(index)->setQuantity(quantity);
- }
}
void TradeWindow::increaseQuantity(int index, bool own, int quantity)
{
- if (own) {
+ if (own)
mMyInventory->getItem(index)->increaseQuantity(quantity);
- } else {
+ else
mPartnerInventory->getItem(index)->increaseQuantity(quantity);
- }
}
void TradeWindow::reset()
@@ -218,21 +183,30 @@ void TradeWindow::setTradeButton(bool enabled)
void TradeWindow::receivedOk(bool own)
{
- if (own) {
+ if (own)
+ {
mOkMe = true;
- if (mOkOther) {
+ if (mOkOther)
+ {
mTradeButton->setEnabled(true);
mOkButton->setEnabled(false);
- } else {
+ }
+ else
+ {
mTradeButton->setEnabled(false);
mOkButton->setEnabled(false);
}
- } else {
+ }
+ else
+ {
mOkOther = true;
- if (mOkMe) {
+ if (mOkMe)
+ {
mTradeButton->setEnabled(true);
mOkButton->setEnabled(false);
- } else {
+ }
+ else
+ {
mTradeButton->setEnabled(false);
mOkButton->setEnabled(true);
}
@@ -256,22 +230,9 @@ void TradeWindow::valueChanged(const gcn::SelectionEvent &event)
*/
if (event.getSource() == mMyItemContainer &&
(item = mMyItemContainer->getSelectedItem()))
- {
mPartnerItemContainer->selectNone();
- }
else if ((item = mPartnerItemContainer->getSelectedItem()))
- {
mMyItemContainer->selectNone();
- }
-
- // Update name and description
- ItemInfo const *info = item ? &item->getInfo() : NULL;
- mItemNameLabel->setCaption(strprintf(_("Name: %s"),
- info ? info->getName().c_str() : ""));
- mItemNameLabel->adjustSize();
- mItemDescriptionLabel->setCaption(strprintf(_("Description: %s"),
- info ? info->getDescription().c_str() : ""));
- mItemDescriptionLabel->adjustSize();
}
void TradeWindow::action(const gcn::ActionEvent &event)
@@ -286,16 +247,19 @@ void TradeWindow::action(const gcn::ActionEvent &event)
if (mMyInventory->getFreeSlot() < 1)
return;
- if (mMyInventory->contains(item)) {
+ if (mMyInventory->contains(item))
+ {
chatWindow->chatLog(_("Failed adding item. You can not "
"overlap one kind of item on the window."), BY_SERVER);
return;
}
- if (item->getQuantity() == 1) {
+ if (item->getQuantity() == 1)
+ {
tradeItem(item, 1);
}
- else {
+ else
+ {
// Choose amount of items to trade
new ItemAmountWindow(AMOUNT_TRADE_ADD, this, item);
}
@@ -317,7 +281,9 @@ void TradeWindow::action(const gcn::ActionEvent &event)
outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST);
outMsg.writeInt16(0);
outMsg.writeInt32(tempInt);
- } else {
+ }
+ else
+ {
mMoneyField->setText("");
}
mMoneyField->setEnabled(false);
diff --git a/src/gui/trade.h b/src/gui/trade.h
index 3129c4b9..df724038 100644
--- a/src/gui/trade.h
+++ b/src/gui/trade.h
@@ -128,8 +128,6 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener
ItemContainer *mMyItemContainer;
ItemContainer *mPartnerItemContainer;
- gcn::Label *mItemNameLabel;
- gcn::Label *mItemDescriptionLabel;
gcn::Label *mMoneyLabel;
gcn::Label *mMoneyLabel2;
gcn::Button *mAddButton, *mOkButton, *mCancelButton, *mTradeButton;
diff --git a/src/gui/truetypefont.cpp b/src/gui/truetypefont.cpp
index f65b3446..66855b77 100644
--- a/src/gui/truetypefont.cpp
+++ b/src/gui/truetypefont.cpp
@@ -19,12 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "truetypefont.h"
-
#include <list>
#include <guichan/exception.hpp>
+#include "truetypefont.h"
+
#include "../graphics.h"
#include "../resources/image.h"
@@ -74,7 +74,6 @@ class TextChunk
gcn::Color color;
};
-
// Word surfaces cache
static std::list<TextChunk> cache;
typedef std::list<TextChunk>::iterator CacheIterator;
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index 96c2e95c..67e05bbd 100644
--- a/src/gui/updatewindow.cpp
+++ b/src/gui/updatewindow.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "updatewindow.h"
-
#include <iostream>
#include <SDL.h>
#include <SDL_thread.h>
@@ -32,6 +30,9 @@
#include "button.h"
#include "progressbar.h"
#include "scrollarea.h"
+#include "updatewindow.h"
+
+#include "widgets/layout.h"
// Curl should be included after Guichan to avoid Windows redefinitions
#include <curl/curl.h>
@@ -40,11 +41,11 @@
#include "../log.h"
#include "../main.h"
+#include "../resources/resourcemanager.h"
+
#include "../utils/gettext.h"
#include "../utils/tostring.h"
-#include "../resources/resourcemanager.h"
-
/**
* Calculates the Alder-32 checksum for the given file.
*/
@@ -68,14 +69,13 @@ static unsigned long fadler32(FILE *file)
/**
* Load the given file into a vector of strings.
*/
-std::vector<std::string>
-loadTextFile(const std::string &fileName)
+std::vector<std::string> loadTextFile(const std::string &fileName)
{
std::vector<std::string> lines;
std::ifstream fin(fileName.c_str());
if (!fin) {
- logger->log("Couldn't load text file: %s", fileName.c_str());
+ logger->log(_("Couldn't load text file: %s"), fileName.c_str());
return lines;
}
@@ -107,34 +107,29 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost,
{
mCurlError[0] = 0;
- const int h = 240;
- const int w = 320;
- setContentSize(w, h);
-
mBrowserBox = new BrowserBox();
mScrollArea = new ScrollArea(mBrowserBox);
mLabel = new gcn::Label(_("Connecting..."));
- mProgressBar = new ProgressBar(0.0, w - 10, 20, 37, 70, 200);
+ mProgressBar = new ProgressBar(0.0, 310, 20, 168, 116, 31);
mCancelButton = new Button(_("Cancel"), "cancel", this);
mPlayButton = new Button(_("Play"), "play", this);
mBrowserBox->setOpaque(false);
mPlayButton->setEnabled(false);
- mCancelButton->setPosition(5, h - 5 - mCancelButton->getHeight());
- mPlayButton->setPosition(
- mCancelButton->getX() + mCancelButton->getWidth() + 5,
- h - 5 - mPlayButton->getHeight());
- mProgressBar->setPosition(5, mCancelButton->getY() - 20 - 5);
- mLabel->setPosition(5, mProgressBar->getY() - mLabel->getHeight() - 5);
+ ContainerPlacer place;
+ place = getPlacer(0, 0);
+
+ place(0, 0, mScrollArea, 5, 3).setPadding(3);
+ place(0, 3, mLabel, 5);
+ place(0, 4, mProgressBar, 5);
+ place(3, 5, mCancelButton);
+ place(4, 5, mPlayButton);
- mScrollArea->setDimension(gcn::Rectangle(5, 5, 310, mLabel->getY() - 12));
+ reflowLayout(320, 240);
- add(mScrollArea);
- add(mLabel);
- add(mProgressBar);
- add(mCancelButton);
- add(mPlayButton);
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
setLocationRelativeTo(getParent());
setVisible(true);
@@ -198,7 +193,7 @@ void UpdaterWindow::loadNews()
{
if (!mMemoryBuffer)
{
- logger->log("Couldn't load news");
+ logger->log(_("Couldn't load news"));
return;
}
@@ -246,8 +241,7 @@ int UpdaterWindow::updateProgress(void *ptr,
return 0;
}
-size_t
-UpdaterWindow::memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
+size_t UpdaterWindow::memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
UpdaterWindow *uw = reinterpret_cast<UpdaterWindow *>(stream);
size_t totalMem = size * nmemb;
@@ -330,8 +324,8 @@ int UpdaterWindow::downloadThread(void *ptr)
{
case CURLE_COULDNT_CONNECT:
default:
- std::cerr << "curl error " << res << ": "
- << uw->mCurlError << " host: " << url.c_str()
+ std::cerr << _("curl error ") << res << ": "
+ << uw->mCurlError << _(" host: ") << url.c_str()
<< std::endl;
break;
}
@@ -366,7 +360,7 @@ int UpdaterWindow::downloadThread(void *ptr)
// Remove the corrupted file
::remove(outFilename.c_str());
logger->log(
- "Checksum for file %s failed: (%lx/%lx)",
+ _("Checksum for file %s failed: (%lx/%lx)"),
uw->mCurrentFile.c_str(),
adler, uw->mCurrentChecksum);
attempts++;
@@ -416,7 +410,7 @@ void UpdaterWindow::download()
if (mThread == NULL)
{
- logger->log("Unable to create mThread");
+ logger->log(_("Unable to create mThread"));
mDownloadStatus = UPDATE_ERROR;
}
}
@@ -454,9 +448,9 @@ void UpdaterWindow::logic()
mThread = NULL;
}
mBrowserBox->addRow("");
- mBrowserBox->addRow("##1 The update process is incomplete.");
- mBrowserBox->addRow("##1 It is strongly recommended that");
- mBrowserBox->addRow("##1 you try again later");
+ mBrowserBox->addRow(_("##1 The update process is incomplete."));
+ mBrowserBox->addRow(_("##1 It is strongly recommended that"));
+ mBrowserBox->addRow(_("##1 you try again later"));
mBrowserBox->addRow(mCurlError);
mScrollArea->setVerticalScrollAmount(
mScrollArea->getVerticalMaxScroll());
@@ -510,7 +504,7 @@ void UpdaterWindow::logic()
}
else
{
- logger->log("%s already here", mCurrentFile.c_str());
+ logger->log(_("%s already here"), mCurrentFile.c_str());
}
mLineIndex++;
}
diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h
index 3acbfb7e..6450ece2 100644
--- a/src/gui/updatewindow.h
+++ b/src/gui/updatewindow.h
@@ -23,6 +23,7 @@
#define _UPDATERWINDOW_H
#include <guichan/actionlistener.hpp>
+
#include <string>
#include <vector>
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index ff0883f7..326a7189 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -19,17 +19,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "viewport.h"
+#include <cassert>
#include "gui.h"
-#include "popupmenu.h"
#include "ministatus.h"
+#include "popupmenu.h"
+#include "viewport.h"
-#include "../simpleanimation.h"
#include "../beingmanager.h"
#include "../configuration.h"
#include "../flooritemmanager.h"
#include "../graphics.h"
+#include "../keyboardconfig.h"
#include "../localplayer.h"
#include "../map.h"
#include "../monster.h"
@@ -37,15 +38,13 @@
#include "../textmanager.h"
#include "../resources/animation.h"
-#include "../resources/monsterinfo.h"
-#include "../resources/resourcemanager.h"
#include "../resources/image.h"
#include "../resources/imageset.h"
+#include "../resources/monsterinfo.h"
+#include "../resources/resourcemanager.h"
#include "../utils/tostring.h"
-#include <cassert>
-
extern volatile int tick_time;
Viewport::Viewport():
@@ -70,76 +69,21 @@ Viewport::Viewport():
config.addListener("ScrollRadius", this);
mPopupMenu = new PopupMenu();
-
- // Load target cursors
- loadTargetCursor("graphics/gui/target-cursor-blue-s.png", 44, 35,
- false, Being::TC_SMALL);
- loadTargetCursor("graphics/gui/target-cursor-red-s.png", 44, 35,
- true, Being::TC_SMALL);
- loadTargetCursor("graphics/gui/target-cursor-blue-m.png", 62, 44,
- false, Being::TC_MEDIUM);
- loadTargetCursor("graphics/gui/target-cursor-red-m.png", 62, 44,
- true, Being::TC_MEDIUM);
- loadTargetCursor("graphics/gui/target-cursor-blue-l.png", 82, 60,
- false, Being::TC_LARGE);
- loadTargetCursor("graphics/gui/target-cursor-red-l.png", 82, 60,
- true, Being::TC_LARGE);
-}
-
-void
-Viewport::loadTargetCursor(std::string filename, int width, int height,
- bool outRange, Being::TargetCursorSize size)
-{
- assert(size > -1);
- assert(size < 3);
-
- ImageSet* currentImageSet;
- SimpleAnimation* currentCursor;
-
- ResourceManager *resman = ResourceManager::getInstance();
-
- currentImageSet = resman->getImageSet(filename, width, height);
- Animation *anim = new Animation();
- for (unsigned int i = 0; i < currentImageSet->size(); ++i)
- {
- anim->addFrame(currentImageSet->get(i), 75, 0, 0);
- }
- currentCursor = new SimpleAnimation(anim);
-
- if (outRange)
- {
- mOutRangeImages[size] = currentImageSet;
- mTargetCursorOutRange[size] = currentCursor;
- }
- else {
- mInRangeImages[size] = currentImageSet;
- mTargetCursorInRange[size] = currentCursor;
- }
}
Viewport::~Viewport()
{
delete mPopupMenu;
-
- for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++)
- {
- delete mTargetCursorInRange[i];
- delete mTargetCursorOutRange[i];
- mInRangeImages[i]->decRef();
- mOutRangeImages[i]->decRef();
- }
}
-void
-Viewport::setMap(Map *map)
+void Viewport::setMap(Map *map)
{
mMap = map;
}
extern MiniStatusWindow *miniStatusWindow;
-void
-Viewport::draw(gcn::Graphics *gcnGraphics)
+void Viewport::draw(gcn::Graphics *gcnGraphics)
{
static int lastTick = tick_time;
@@ -148,6 +92,10 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
Graphics *graphics = static_cast<Graphics*>(gcnGraphics);
+ // Ensure the client doesn't freak out if a feature localplayer uses
+ // is dependent on a map.
+ player_node->mMapInitialized = true;
+
// Avoid freaking out when tick_time overflows
if (tick_time < lastTick)
{
@@ -225,37 +173,39 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
if (mMap)
{
mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY);
- drawTargetCursor(graphics); // TODO: Draw the cursor with the sprite
- }
- // Find a path from the player to the mouse, and draw it. This is for debug
- // purposes.
- if (mShowDebugPath && mMap)
- {
- // Get the current mouse position
- int mouseX, mouseY;
- SDL_GetMouseState(&mouseX, &mouseY);
+ // Find a path from the player to the mouse, and draw it. This is for debug
+ // purposes.
+ if (mShowDebugPath)
+ {
+ // Get the current mouse position
+ int mouseX, mouseY;
+ SDL_GetMouseState(&mouseX, &mouseY);
- int mouseTileX = mouseX / 32 + mTileViewX;
- int mouseTileY = mouseY / 32 + mTileViewY;
+ int mouseTileX = mouseX / 32 + mTileViewX;
+ int mouseTileY = mouseY / 32 + mTileViewY;
- Path debugPath = mMap->findPath(
- player_node->mX, player_node->mY,
- mouseTileX, mouseTileY);
+ Path debugPath = mMap->findPath(player_node->mX, player_node->mY, mouseTileX, mouseTileY);
- graphics->setColor(gcn::Color(255, 0, 0));
- for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++)
- {
- int squareX = i->x * 32 - (int) mPixelViewX + 12;
- int squareY = i->y * 32 - (int) mPixelViewY + 12;
+ graphics->setColor(gcn::Color(255, 0, 0));
+ for (PathIterator i = debugPath.begin(); i != debugPath.end(); i++)
+ {
+ int squareX = i->x * 32 - (int) mPixelViewX + 12;
+ int squareY = i->y * 32 - (int) mPixelViewY + 12;
- graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
- graphics->drawText(
- toString(mMap->getMetaTile(i->x, i->y)->Gcost),
- squareX + 4, squareY + 12, gcn::Graphics::CENTER);
+ graphics->fillRectangle(gcn::Rectangle(squareX, squareY, 8, 8));
+ graphics->drawText(toString(mMap->getMetaTile(i->x, i->y)->Gcost), squareX + 4, squareY + 12, gcn::Graphics::CENTER);
+ }
}
}
+ if (player_node->mUpdateName)
+ {
+ player_node->mUpdateName = false;
+ player_node->setName(player_node->getName());
+ }
+
+
// Draw text
if (textManager)
{
@@ -266,6 +216,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
Beings &beings = beingManager->getAll();
for (BeingIterator i = beings.begin(); i != beings.end(); i++)
{
+ (*i)->drawSpeech(graphics, -(int) mPixelViewX, -(int) mPixelViewY);
(*i)->drawEmotion(graphics, -(int) mPixelViewX, -(int) mPixelViewY);
}
@@ -276,8 +227,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
WindowContainer::draw(gcnGraphics);
}
-void
-Viewport::logic()
+void Viewport::logic()
{
WindowContainer::logic();
@@ -294,49 +244,9 @@ Viewport::logic()
mouseY / 32 + mTileViewY);
mWalkTime = player_node->mWalkTime;
}
-
- for (int i = 0; i < 3; i++)
- {
- mTargetCursorInRange[i]->update(10);
- mTargetCursorOutRange[i]->update(10);
- }
}
-void
-Viewport::drawTargetCursor(Graphics *graphics)
-{
- // Draw target marker if needed
- Being *target = player_node->getTarget();
- if (target)
- {
- // Calculate target circle position
-
- // Find whether target is in range
- int rangeX = abs(target->mX - player_node->mX);
- int rangeY = abs(target->mY - player_node->mY);
- int attackRange = player_node->getAttackRange();
-
- // Get the correct target cursors graphic
- Being::TargetCursorSize cursorSize = target->getTargetCursorSize();
- Image* targetCursor;
- if (rangeX > attackRange || rangeY > attackRange)
- {
- targetCursor = mTargetCursorOutRange[cursorSize]->getCurrentImage();
- }
- else {
- targetCursor = mTargetCursorInRange[cursorSize]->getCurrentImage();
- }
-
- // Draw the target cursor at the correct position
- int posX = target->getPixelX() + 16 - targetCursor->getWidth() / 2 - (int) mPixelViewX;
- int posY = target->getPixelY() + 16 - targetCursor->getHeight() / 2 - (int) mPixelViewY;
-
- graphics->drawImage(targetCursor, posX, posY);
- }
-}
-
-void
-Viewport::mousePressed(gcn::MouseEvent &event)
+void Viewport::mousePressed(gcn::MouseEvent &event)
{
// Check if we are alive and kickin'
if (!mMap || !player_node || player_node->mAction == Being::DEAD)
@@ -348,8 +258,10 @@ Viewport::mousePressed(gcn::MouseEvent &event)
mPlayerFollowMouse = false;
- int tilex = event.getX() / 32 + mTileViewX;
- int tiley = event.getY() / 32 + mTileViewY;
+ const int tilex = event.getX() / 32 + mTileViewX;
+ const int tiley = event.getY() / 32 + mTileViewY;
+ const int x = (int)((float) event.getX() + mPixelViewX);
+ const int y = (int)((float) event.getY() + mPixelViewY);
// Right click might open a popup
if (event.getButton() == gcn::MouseEvent::RIGHT)
@@ -357,11 +269,11 @@ Viewport::mousePressed(gcn::MouseEvent &event)
Being *being;
FloorItem *floorItem;
- if ((being = beingManager->findBeing(tilex, tiley)) &&
- being != player_node)
+ if ((being = beingManager->findBeingByPixel(x, y)) &&
+ being != player_node)
{
- mPopupMenu->showPopup(event.getX(), event.getY(), being);
- return;
+ mPopupMenu->showPopup(event.getX(), event.getY(), being);
+ return;
}
else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley)))
{
@@ -382,11 +294,9 @@ Viewport::mousePressed(gcn::MouseEvent &event)
{
Being *being;
FloorItem *item;
-
+
// Interact with some being
-// if ((being = beingManager->findBeing(tilex, tiley))
- int x = (int)((float) event.getX() + mPixelViewX);
- int y = (int)((float) event.getY() + mPixelViewY);
+// if ((being = beingManager->findBeing(tilex, tiley)))
if ((being = beingManager->findBeingByPixel(x, y)))
{
switch (being->getType())
@@ -400,59 +310,47 @@ Viewport::mousePressed(gcn::MouseEvent &event)
if (being->mAction == Being::DEAD)
break;
- if (player_node->withinAttackRange(being))
+ if (player_node->withinAttackRange(being) || keyboard.isKeyActive(keyboard.KEY_ATTACK))
{
- player_node->attack(being, true);
+ player_node->setGotoTarget(being);
+ player_node->attack(being, !keyboard.isKeyActive(keyboard.KEY_TARGET));
}
else
{
- Uint8 *keys = SDL_GetKeyState(NULL);
- if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]))
- {
- player_node->stopAttack();
- player_node->setGotoTarget(being);
- }
+ player_node->setDestination(tilex, tiley);
}
break;
default:
break;
- }
+ }
}
// Pick up some item
else if ((item = floorItemManager->findByCoordinates(tilex, tiley)))
{
- player_node->pickUp(item);
+ player_node->pickUp(item);
}
// Just walk around
else
{
- // XXX XXX XXX REALLY UGLY!
- Uint8 *keys = SDL_GetKeyState(NULL);
- if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]))
- {
- player_node->setDestination(tilex, tiley);
- player_node->stopAttack();
- }
+ player_node->stopAttack();
+ player_node->setDestination(tilex, tiley);
mPlayerFollowMouse = true;
}
}
else if (event.getButton() == gcn::MouseEvent::MIDDLE)
{
// Find the being nearest to the clicked position
- Being *target = beingManager->findNearestLivingBeing(
- tilex, tiley,
- 20, Being::MONSTER);
-
+ Being *target = beingManager->findBeingByPixel(x, y);
+
if (target)
{
- player_node->setTarget(target);
+ player_node->setTarget(target);
}
}
}
-void
-Viewport::mouseDragged(gcn::MouseEvent &event)
+void Viewport::mouseDragged(gcn::MouseEvent &event)
{
if (!mMap || !player_node)
return;
@@ -465,20 +363,17 @@ Viewport::mouseDragged(gcn::MouseEvent &event)
}
}
-void
-Viewport::mouseReleased(gcn::MouseEvent &event)
+void Viewport::mouseReleased(gcn::MouseEvent &event)
{
mPlayerFollowMouse = false;
}
-void
-Viewport::showPopup(int x, int y, Item *item)
+void Viewport::showPopup(int x, int y, Item *item)
{
mPopupMenu->showPopup(x, y, item);
}
-void
-Viewport::optionChanged(const std::string &name)
+void Viewport::optionChanged(const std::string &name)
{
mScrollLaziness = (int) config.getValue("ScrollLaziness", 32);
mScrollRadius = (int) config.getValue("ScrollRadius", 32);
diff --git a/src/gui/viewport.h b/src/gui/viewport.h
index 8965ad95..5ed40166 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -26,8 +26,9 @@
#include "windowcontainer.h"
-#include "../configlistener.h"
#include "../being.h"
+#include "../configlistener.h"
+#include "../guichanfwd.h"
class Map;
class FloorItem;
@@ -35,7 +36,6 @@ class ImageSet;
class Item;
class PopupMenu;
class Graphics;
-class SimpleAnimation;
/**
* The viewport on the map. Displays the current map and handles mouse input
@@ -62,97 +62,65 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
/**
* Sets the map displayed by the viewport.
*/
- void
- setMap(Map *map);
+ void setMap(Map *map);
/**
* Draws the viewport.
*/
- void
- draw(gcn::Graphics *graphics);
+ void draw(gcn::Graphics *graphics);
/**
* Implements player to keep following mouse.
*/
- void
- logic();
+ void logic();
/**
* Toggles whether the path debug graphics are shown
*/
- void
- toggleDebugPath() { mShowDebugPath = !mShowDebugPath; }
+ void toggleDebugPath() { mShowDebugPath = !mShowDebugPath; }
/**
* Handles mouse press on map.
*/
- void
- mousePressed(gcn::MouseEvent &event);
+ void mousePressed(gcn::MouseEvent &event);
/**
* Handles mouse move on map
*/
- void
- mouseDragged(gcn::MouseEvent &event);
+ void mouseDragged(gcn::MouseEvent &event);
/**
* Handles mouse button release on map.
*/
- void
- mouseReleased(gcn::MouseEvent &event);
+ void mouseReleased(gcn::MouseEvent &event);
/**
* Shows a popup for an item.
* TODO Find some way to get rid of Item here
*/
- void
- showPopup(int x, int y, Item *item);
+ void showPopup(int x, int y, Item *item);
/**
* A relevant config option changed.
*/
- void
- optionChanged(const std::string &name);
+ void optionChanged(const std::string &name);
/**
- * Returns camera x offset in tiles.
+ * Returns camera x offset in pixels.
*/
- int
- getCameraX() { return mTileViewX; }
+ int getCameraX() const { return (int) mPixelViewX; }
/**
- * Returns camera y offset in tiles.
+ * Returns camera y offset in pixels.
*/
- int
- getCameraY() { return mTileViewY; }
+ int getCameraY() const { return (int) mPixelViewY; }
/**
* Changes viewpoint by relative pixel coordinates.
*/
- void
- scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; }
+ void scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; }
private:
- /**
- * Helper function for loading target cursors
- */
- void
- loadTargetCursor(std::string filename, int width, int height,
- bool outRange, Being::TargetCursorSize size);
-
- /**
- * Draws range based target cursor
- */
- void
- drawTargetCursor(Graphics *graphics);
-
- /**
- * Draws target name
- */
- void
- drawTargetName(Graphics *graphics);
-
-
Map *mMap; /**< The current map. */
int mScrollRadius;
@@ -165,18 +133,6 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
int mTileViewY; /**< Current viewpoint in tiles. */
bool mShowDebugPath; /**< Show a path from player to pointer. */
- /** Images of in range target cursor. */
- ImageSet *mInRangeImages[Being::NUM_TC];
-
- /** Images of out of range target cursor. */
- ImageSet *mOutRangeImages[Being::NUM_TC];
-
- /** Animated in range target cursor. */
- SimpleAnimation *mTargetCursorInRange[Being::NUM_TC];
-
- /** Animated out of range target cursor. */
- SimpleAnimation *mTargetCursorOutRange[Being::NUM_TC];
-
bool mPlayerFollowMouse;
int mWalkTime;
diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp
new file mode 100644
index 00000000..88a12d68
--- /dev/null
+++ b/src/gui/widgets/dropdown.cpp
@@ -0,0 +1,167 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <algorithm>
+
+#include "dropdown.h"
+
+#include "../../graphics.h"
+
+#include "../../resources/image.h"
+#include "../../resources/resourcemanager.h"
+
+#include "../../utils/dtor.h"
+
+int DropDown::instances = 0;
+Image *DropDown::buttons[2][2];
+ImageRect DropDown::skin;
+
+DropDown::DropDown(gcn::ListModel *listModel,
+ gcn::ScrollArea *scrollArea,
+ gcn::ListBox *listBox):
+ gcn::DropDown::DropDown(listModel,
+ scrollArea, listBox)
+{
+ setFrameSize(2);
+
+ // Initialize graphics
+ if (instances == 0)
+ {
+ // Load the background skin
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ // Get the button skin
+ buttons[1][0] =
+ resman->getImage("graphics/gui/vscroll_up_default.png");
+ buttons[0][0] =
+ resman->getImage("graphics/gui/vscroll_down_default.png");
+ buttons[1][1] =
+ resman->getImage("graphics/gui/vscroll_up_pressed.png");
+ buttons[0][1] =
+ resman->getImage("graphics/gui/vscroll_down_pressed.png");
+
+ // get the border skin
+ Image *boxBorder = resman->getImage("graphics/gui/deepbox.png");
+ int gridx[4] = {0, 3, 28, 31};
+ int gridy[4] = {0, 3, 28, 31};
+ int a = 0, x, y;
+
+ for (y = 0; y < 3; y++) {
+ for (x = 0; x < 3; x++) {
+ skin.grid[a] = boxBorder->getSubImage(
+ gridx[x], gridy[y],
+ gridx[x + 1] - gridx[x] + 1,
+ gridy[y + 1] - gridy[y] + 1);
+ a++;
+ }
+ }
+
+ boxBorder->decRef();
+ }
+
+ instances++;
+}
+
+DropDown::~DropDown()
+{
+ instances--;
+ // Free images memory
+ if (instances == 0)
+ {
+ buttons[0][0]->decRef();
+ buttons[0][1]->decRef();
+ buttons[1][0]->decRef();
+ buttons[1][1]->decRef();
+
+ for_each(skin.grid, skin.grid + 9, dtor<Image*>());
+ }
+}
+
+void DropDown::draw(gcn::Graphics* graphics)
+{
+ int h;
+
+ if (mDroppedDown)
+ {
+ h = mFoldedUpHeight;
+ }
+ else
+ {
+ h = getHeight();
+ }
+
+ int alpha = getBaseColor().a;
+ gcn::Color faceColor = getBaseColor();
+ faceColor.a = alpha;
+ gcn::Color highlightColor = faceColor + 0x303030;
+ highlightColor.a = alpha;
+ gcn::Color shadowColor = faceColor - 0x303030;
+ shadowColor.a = alpha;
+
+
+ graphics->setColor(getBackgroundColor());
+ graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h));
+
+ graphics->setColor(getForegroundColor());
+ graphics->setFont(getFont());
+
+ if (mListBox->getListModel() && mListBox->getSelected() >= 0)
+ {
+ graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0);
+ }
+
+ if (isFocused())
+ {
+ graphics->setColor(highlightColor);
+ graphics->drawRectangle(gcn::Rectangle(0, 0, getWidth() - h, h));
+ }
+
+ drawButton(graphics);
+
+ if (mDroppedDown)
+ {
+ drawChildren(graphics);
+
+ // Draw two lines separating the ListBox with se selected
+ // element view.
+ graphics->setColor(highlightColor);
+ graphics->drawLine(0, h, getWidth(), h);
+ graphics->setColor(shadowColor);
+ graphics->drawLine(0, h + 1, getWidth(), h + 1);
+ }
+}
+
+void DropDown::drawFrame(gcn::Graphics *graphics)
+{
+ const int bs = getFrameSize();
+ const int w = getWidth() + bs * 2;
+ const int h = getHeight() + bs * 2;
+
+ static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin);
+}
+
+void DropDown::drawButton(gcn::Graphics *graphics)
+{
+ int height = mDroppedDown ? mFoldedUpHeight : getHeight();
+
+ static_cast<Graphics*>(graphics)->
+ drawImage(buttons[mDroppedDown][mPushed], getWidth() - height + 2, 1);
+}
diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h
new file mode 100644
index 00000000..25ae05f8
--- /dev/null
+++ b/src/gui/widgets/dropdown.h
@@ -0,0 +1,86 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DROPDOWN_H
+#define DROPDOWN_H
+
+#include <iosfwd>
+
+#include <guichan/widgets/dropdown.hpp>
+
+#include "../listbox.h"
+#include "../scrollarea.h"
+
+#include "../../guichanfwd.h"
+
+class Image;
+class ImageRect;
+
+ /**
+ * A drop down box from which you can select different values. It is one of
+ * the most complicated Widgets you will find in Guichan. For drawing the
+ * DroppedDown box it uses one ScrollArea and one ListBox. It also uses an
+ * internal FocusHandler to handle the focus of the internal ScollArea and
+ * ListBox. DropDown uses a ListModel to handle the list. To be able to use
+ * DropDown you must give DropDown an implemented ListModel which represents
+ * your list.
+ */
+class DropDown : public gcn::DropDown
+{
+ public:
+ /**
+ * Contructor.
+ *
+ * @param listModel the ListModel to use.
+ * @param scrollArea the ScrollArea to use.
+ * @param listBox the listBox to use.
+ * @see ListModel, ScrollArea, ListBox.
+ */
+ DropDown(gcn::ListModel *listModel = NULL,
+ gcn::ScrollArea *scrollArea = NULL,
+ gcn::ListBox *listBox = NULL);
+
+ /**
+ * Destructor.
+ */
+ ~DropDown();
+
+ void draw(gcn::Graphics* graphics);
+
+ void drawFrame(gcn::Graphics* graphics);
+
+
+ protected:
+ /**
+ * Draws the button with the little down arrow.
+ *
+ * @param graphics a Graphics object to draw with.
+ */
+ void drawButton(gcn::Graphics *graphics);
+
+ // Add own Images.
+ static int instances;
+ static Image *buttons[2][2];
+ static ImageRect skin;
+};
+
+#endif // end DROPDOWN_H
+
diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp
index 00689575..4b8bb4da 100644
--- a/src/gui/widgets/resizegrip.cpp
+++ b/src/gui/widgets/resizegrip.cpp
@@ -19,10 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "resizegrip.h"
-
#include <guichan/graphics.hpp>
+#include "resizegrip.h"
+
#include "../../graphics.h"
#include "../../resources/image.h"
@@ -31,13 +31,13 @@
Image *ResizeGrip::gripImage = 0;
int ResizeGrip::mInstances = 0;
-ResizeGrip::ResizeGrip()
+ResizeGrip::ResizeGrip(std::string image)
{
if (mInstances == 0)
{
// Load the grip image
ResourceManager *resman = ResourceManager::getInstance();
- gripImage = resman->getImage("graphics/gui/resize.png");
+ gripImage = resman->getImage(image);
}
mInstances++;
@@ -56,8 +56,7 @@ ResizeGrip::~ResizeGrip()
}
}
-void
-ResizeGrip::draw(gcn::Graphics *graphics)
+void ResizeGrip::draw(gcn::Graphics *graphics)
{
static_cast<Graphics*>(graphics)->drawImage(gripImage, 0, 0);
}
diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h
index 5c6ea4bd..7f1329a2 100644
--- a/src/gui/widgets/resizegrip.h
+++ b/src/gui/widgets/resizegrip.h
@@ -24,6 +24,8 @@
#include <guichan/widget.hpp>
+#include "../../guichanfwd.h"
+
class Image;
/**
@@ -39,7 +41,7 @@ class ResizeGrip : public gcn::Widget
/**
* Constructor.
*/
- ResizeGrip();
+ ResizeGrip(std::string image = "graphics/gui/resize.png");
/**
* Destructor.
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index ed5bb8fc..e0e88b31 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -24,11 +24,12 @@
#include <climits>
#include <guichan/exception.hpp>
-#include <guichan/widgets/icon.hpp>
-#include "window.h"
+#include <guichan/widgets/icon.hpp>
#include "gui.h"
+#include "gccontainer.h"
+#include "window.h"
#include "windowcontainer.h"
#include "widgets/layout.h"
@@ -42,24 +43,28 @@
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
+#include "../utils/xml.h"
+
ConfigListener *Window::windowConfigListener = 0;
WindowContainer *Window::windowContainer = 0;
int Window::instances = 0;
int Window::mouseResize = 0;
-ImageRect Window::border;
+//ImageRect Window::border;
Image *Window::closeImage = NULL;
+bool Window::mAlphaChanged = false;
class WindowConfigListener : public ConfigListener
{
void optionChanged(const std::string &)
{
- for_each(Window::border.grid, Window::border.grid + 9,
- std::bind2nd(std::mem_fun(&Image::setAlpha),
- config.getValue("guialpha", 0.8)));
+ Window::mAlphaChanged = true;
+// for_each(Window::border.grid, Window::border.grid + 9,
+// std::bind2nd(std::mem_fun(&Image::setAlpha),
+// config.getValue("guialpha", 0.8)));
}
};
-Window::Window(const std::string& caption, bool modal, Window *parent):
+Window::Window(const std::string& caption, bool modal, Window *parent, const std::string& skin):
gcn::Window(caption),
mGrip(0),
mParent(parent),
@@ -72,31 +77,23 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
mMinWinWidth(100),
mMinWinHeight(40),
mMaxWinWidth(INT_MAX),
- mMaxWinHeight(INT_MAX)
+ mMaxWinHeight(INT_MAX),
+ mSkin(skin)
{
logger->log("Window::Window(\"%s\")", caption.c_str());
- if (!windowContainer) {
+ if (!windowContainer)
+ {
throw GCN_EXCEPTION("Window::Window(): no windowContainer set");
}
+ // Loads the skin
+ loadSkin(mSkin);
+
+ setGuiAlpha();
+
if (instances == 0)
{
- // Load static resources
- ResourceManager *resman = ResourceManager::getInstance();
- Image *dBorders = resman->getImage("graphics/gui/vscroll_grey.png");
- border.grid[0] = dBorders->getSubImage(0, 0, 4, 4);
- border.grid[1] = dBorders->getSubImage(4, 0, 3, 4);
- border.grid[2] = dBorders->getSubImage(7, 0, 4, 4);
- border.grid[3] = dBorders->getSubImage(0, 4, 4, 10);
- border.grid[4] = resman->getImage("graphics/gui/bg_quad_dis.png");
- border.grid[5] = dBorders->getSubImage(7, 4, 4, 10);
- border.grid[6] = dBorders->getSubImage(0, 15, 4, 4);
- border.grid[7] = dBorders->getSubImage(4, 15, 3, 4);
- border.grid[8] = dBorders->getSubImage(7, 15, 4, 4);
- dBorders->decRef();
- closeImage = resman->getImage("graphics/gui/close_button.png");
-
windowConfigListener = new WindowConfigListener();
// Send GUI alpha changed for initialization
windowConfigListener->optionChanged("guialpha");
@@ -130,12 +127,14 @@ Window::~Window()
const std::string &name = mWindowName;
// Saving X, Y and Width and Height for resizables in the config
- if (!name.empty()) {
+ if (!name.empty())
+ {
config.setValue(name + "WinX", getX());
config.setValue(name + "WinY", getY());
config.setValue(name + "Visible", isVisible());
- if (mGrip) {
+ if (mGrip)
+ {
config.setValue(name + "WinWidth", getWidth());
config.setValue(name + "WinHeight", getHeight());
}
@@ -152,22 +151,19 @@ Window::~Window()
instances--;
+ // Clean up static resources
+ for( int i = 0; i < 9; i++ )
+ {
+ delete border.grid[i];
+ border.grid[i] = NULL;
+ }
+
if (instances == 0)
{
config.removeListener("guialpha", windowConfigListener);
delete windowConfigListener;
windowConfigListener = NULL;
- // Clean up static resources
- delete border.grid[0];
- delete border.grid[1];
- delete border.grid[2];
- delete border.grid[3];
- border.grid[4]->decRef();
- delete border.grid[5];
- delete border.grid[6];
- delete border.grid[7];
- delete border.grid[8];
closeImage->decRef();
}
}
@@ -524,6 +520,187 @@ int Window::getResizeHandles(gcn::MouseEvent &event)
return resizeHandles;
}
+void Window::setGuiAlpha()
+{
+ //logger->log("Window::setGuiAlpha: Alpha Value %f", config.getValue("guialpha", 0.8));
+ for(int i = 0; i < 9; i++)
+ {
+ //logger->log("Window::setGuiAlpha: Border Image (%i)", i);
+ border.grid[i]->setAlpha(config.getValue("guialpha", 0.8));
+ }
+
+ mAlphaChanged = false;
+}
+
+void Window::loadSkin(const std::string filename)
+{
+ const std::string windowId = Window::getId();
+
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ logger->log("Loading Window Skin '%s'.", filename.c_str());
+ logger->log("Loading Window ID '%s'.", windowId.c_str());
+
+
+ if(filename == "")
+ logger->error("Window::loadSkin(): Invalid File Name.");
+
+ // TODO:
+ // If there is an error loading the specified file, we should try to revert
+ // to a 'default' skin file. Only if the 'default' skin file can't be loaded
+ // should we have a terminating error.
+ XML::Document doc(filename);
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skinset"))
+ {
+ logger->error("Widget Skinning error");
+ }
+
+ std::string skinSetImage;
+ skinSetImage = XML::getProperty(rootNode, "image", "");
+ Image *dBorders = NULL;
+ if(skinSetImage != "")
+ {
+ logger->log("Window::loadSkin(): <skinset> defines '%s' as a skin image.", skinSetImage.c_str());
+ dBorders = resman->getImage("graphics/gui/" + skinSetImage);//"graphics/gui/speech_bubble.png");
+ }
+ else
+ {
+ logger->error("Window::loadSkin(): Skinset does not define an image!");
+ }
+
+ //iterate <widget>'s
+ for_each_xml_child_node(widgetNode, rootNode)
+ {
+ if (!xmlStrEqual(widgetNode->name, BAD_CAST "widget"))
+ continue;
+
+ std::string widgetType;
+ widgetType = XML::getProperty(widgetNode, "type", "unknown");
+ if (widgetType == "Window")
+ {
+ // Iterate through <part>'s
+ // LEEOR / TODO:
+ // We need to make provisions to load in a CloseButton image. For now it
+ // can just be hard-coded.
+ for_each_xml_child_node(partNode, widgetNode)
+ {
+ if (!xmlStrEqual(partNode->name, BAD_CAST "part"))
+ {
+ continue;
+ }
+
+ std::string partType;
+ partType = XML::getProperty(partNode, "type", "unknown");
+ // TOP ROW
+ if(partType == "top-left-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[0] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "top-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[1] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "top-right-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[2] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // MIDDLE ROW
+ else if(partType == "left-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[3] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bg-quad")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[4] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "right-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[5] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // BOTTOM ROW
+ else if(partType == "bottom-left-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[6] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bottom-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[7] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bottom-right-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[8] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // Part is of an uknown type.
+ else
+ {
+ logger->log("Window::loadSkin(): Unknown Part Type '%s'", partType.c_str());
+ }
+ }
+ }
+ // Widget is of an uknown type.
+ else
+ {
+ logger->log("Window::loadSkin(): Unknown Widget Type '%s'", widgetType.c_str());
+ }
+ }
+ dBorders->decRef();
+
+ logger->log("Finished loading Window Skin.");
+
+ // Hard-coded for now until we update the above code to look for window buttons.
+ closeImage = resman->getImage("graphics/gui/close_button.png");
+}
+
Layout &Window::getLayout()
{
if (!mLayout) mLayout = new Layout;
diff --git a/src/gui/window.h b/src/gui/window.h
index 19d59c26..deaf984c 100644
--- a/src/gui/window.h
+++ b/src/gui/window.h
@@ -22,9 +22,11 @@
#ifndef WINDOW_H
#define WINDOW_H
-#include <guichan/widgets/window.hpp>
#include <guichan/widgetlistener.hpp>
+#include <guichan/widgets/window.hpp>
+
+#include "../graphics.h"
#include "../guichanfwd.h"
class ConfigListener;
@@ -56,9 +58,10 @@ class Window : public gcn::Window, gcn::WidgetListener
* @param parent The parent window. This is the window standing above
* this one in the window hiearchy. When reordering,
* a window will never go below its parent window.
+ * @param skin The location where the window's skin XML can be found.
*/
Window(const std::string &caption = "Window", bool modal = false,
- Window *parent = NULL);
+ Window *parent = NULL, const std::string &skin = "graphics/gui/gui.xml");
/**
* Destructor. Deletes all the added widgets.
@@ -126,6 +129,26 @@ class Window : public gcn::Window, gcn::WidgetListener
void setMaxHeight(unsigned int height);
/**
+ * Gets the minimum width of the window.
+ */
+ int getMinWidth() { return mMinWinWidth; }
+
+ /**
+ * Gets the minimum height of the window.
+ */
+ int getMinHeight() { return mMinWinHeight; }
+
+ /**
+ * Gets the maximum width of the window.
+ */
+ int getMaxWidth() { return mMaxWinWidth; }
+
+ /**
+ * Gets the minimum height of the window.
+ */
+ int getMaxHeight() { return mMaxWinHeight; }
+
+ /**
* Sets flag to show a title or not.
*/
void setShowTitle(bool flag)
@@ -238,6 +261,11 @@ class Window : public gcn::Window, gcn::WidgetListener
void reflowLayout(int w = 0, int h = 0);
/**
+ * Loads a window skin
+ */
+ void loadSkin(const std::string filename);
+
+ /**
* Adds a widget to the window and sets it at given cell.
*/
LayoutCell &place(int x, int y, gcn::Widget *, int w = 1, int h = 1);
@@ -269,6 +297,8 @@ class Window : public gcn::Window, gcn::WidgetListener
*/
int getResizeHandles(gcn::MouseEvent &event);
+ void setGuiAlpha();
+
ResizeGrip *mGrip; /**< Resize grip */
Window *mParent; /**< The parent window */
Layout *mLayout; /**< Layout handler */
@@ -277,6 +307,7 @@ class Window : public gcn::Window, gcn::WidgetListener
bool mModal; /**< Window is modal */
bool mCloseButton; /**< Window has a close button */
bool mSticky; /**< Window resists minimization */
+ static bool mAlphaChanged; /**< Whether the alpha percent was changed */
int mMinWinWidth; /**< Minimum window width */
int mMinWinHeight; /**< Minimum window height */
int mMaxWinWidth; /**< Maximum window width */
@@ -285,6 +316,7 @@ class Window : public gcn::Window, gcn::WidgetListener
int mDefaultY; /**< Default window Y position */
int mDefaultWidth; /**< Default window width */
int mDefaultHeight; /**< Default window height */
+ std::string mSkin; /**< Name of the skin to use */
/**
* The config listener that listens to changes relevant to all windows.
@@ -293,7 +325,7 @@ class Window : public gcn::Window, gcn::WidgetListener
static int mouseResize; /**< Active resize handles */
static int instances; /**< Number of Window instances */
- static ImageRect border; /**< The window border and background */
+ ImageRect border; /**< The window border and background */
static Image *closeImage; /**< Close Button Image */
/**
diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h
index a25f2037..a3e80223 100644
--- a/src/gui/windowcontainer.h
+++ b/src/gui/windowcontainer.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/container.hpp>
+#include "../guichanfwd.h"
+
/**
* A window container. This container adds functionality for more convenient
* widget (windows in particular) destruction.
diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp
index 845cf258..557b3553 100644
--- a/src/imageparticle.cpp
+++ b/src/imageparticle.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "imageparticle.h"
-
#include "graphics.h"
+#include "imageparticle.h"
#include "resources/image.h"
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 7b9ec07c..8824e1ba 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "inventory.h"
-
#include <algorithm>
#include <cassert>
+#include "inventory.h"
#include "item.h"
#include "log.h"
@@ -34,15 +33,16 @@ struct SlotUsed : public std::unary_function<Item*, bool>
}
};
-Inventory::Inventory()
+Inventory::Inventory(int size):
+ mSize(size)
{
- mItems = new Item*[INVENTORY_SIZE];
- std::fill_n(mItems, INVENTORY_SIZE, (Item*) 0);
+ mItems = new Item*[mSize];
+ std::fill_n(mItems, mSize, (Item*) 0);
}
Inventory::~Inventory()
{
- for (int i = 0; i < INVENTORY_SIZE; i++)
+ for (int i = 0; i < mSize; i++)
delete mItems[i];
delete [] mItems;
@@ -58,7 +58,7 @@ Item* Inventory::getItem(int index) const
Item* Inventory::findItem(int itemId) const
{
- for (int i = 0; i < INVENTORY_SIZE; i++)
+ for (int i = 0; i < mSize; i++)
{
if (mItems[i] && mItems[i]->getId() == itemId)
return mItems[i];
@@ -73,19 +73,11 @@ void Inventory::addItem(int id, int quantity, bool equipment)
void Inventory::setItem(int index, int id, int quantity, bool equipment)
{
- if (index < 0 || index >= INVENTORY_SIZE) {
+ if (index < 0 || index >= mSize) {
logger->log("Warning: invalid inventory index: %d", index);
return;
}
- /* TODO: Check where to reenable this code.
- // Dont stack equipment other than arrows.
- if (equipment && !(id == 1199 || id == 529))
- mItems[index].setQuantity(quantity);
- else
- mItems[index].increaseQuantity(quantity);
- */
-
if (!mItems[index] && id > 0) {
Item *item = new Item(id, quantity, equipment);
item->setInvIndex(index);
@@ -101,14 +93,14 @@ void Inventory::setItem(int index, int id, int quantity, bool equipment)
void Inventory::clear()
{
- for (int i = 0; i < INVENTORY_SIZE; i++) {
+ for (int i = 0; i < mSize; i++) {
removeItemAt(i);
}
}
void Inventory::removeItem(int id)
{
- for (int i = 0; i < INVENTORY_SIZE; i++) {
+ for (int i = 0; i < mSize; i++) {
if (mItems[i] && mItems[i]->getId() == id) {
removeItemAt(i);
}
@@ -123,7 +115,7 @@ void Inventory::removeItemAt(int index)
bool Inventory::contains(Item *item) const
{
- for (int i = 0; i < INVENTORY_SIZE; i++) {
+ for (int i = 0; i < mSize; i++) {
if (mItems[i] && mItems[i]->getId() == item->getId()) {
return true;
}
@@ -134,19 +126,19 @@ bool Inventory::contains(Item *item) const
int Inventory::getFreeSlot() const
{
- Item **i = std::find_if(mItems + 2, mItems + INVENTORY_SIZE,
+ Item **i = std::find_if(mItems + 2, mItems + mSize,
std::not1(SlotUsed()));
- return (i == mItems + INVENTORY_SIZE) ? -1 : (i - mItems);
+ return (i == mItems + mSize) ? -1 : (i - mItems);
}
int Inventory::getNumberOfSlotsUsed() const
{
- return count_if(mItems, mItems + INVENTORY_SIZE, SlotUsed());
+ return count_if(mItems, mItems + mSize, SlotUsed());
}
int Inventory::getLastUsedSlot() const
{
- for (int i = INVENTORY_SIZE - 1; i >= 0; i--) {
+ for (int i = mSize - 1; i >= 0; i--) {
if (SlotUsed()(mItems[i])) {
return i;
}
diff --git a/src/inventory.h b/src/inventory.h
index 1d2ba296..2c5d99e3 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -32,7 +32,7 @@ class Inventory
/**
* Constructor.
*/
- Inventory();
+ Inventory(int size);
/**
* Destructor.
@@ -40,6 +40,11 @@ class Inventory
~Inventory();
/**
+ * Returns the size that this instance is configured for
+ */
+ int getSize() { return mSize; }
+
+ /**
* Returns the item at the specified index.
*/
Item* getItem(int index) const;
@@ -104,6 +109,7 @@ class Inventory
protected:
Item **mItems; /**< The holder of items */
+ int mSize; /**< The max number of inventory items */
};
#endif
diff --git a/src/item.h b/src/item.h
index b663880c..3ea4a905 100644
--- a/src/item.h
+++ b/src/item.h
@@ -46,14 +46,12 @@ class Item
/**
* Sets the item id, identifying the item type.
*/
- void
- setId(int id);
+ void setId(int id);
/**
* Returns the item id.
*/
- int
- getId() const { return mId; }
+ int getId() const { return mId; }
/**
* Returns the item image.
@@ -63,62 +61,52 @@ class Item
/**
* Sets the number of items.
*/
- void
- setQuantity(int quantity) { mQuantity = quantity; }
+ void setQuantity(int quantity) { mQuantity = quantity; }
/**
* Increases the number of items by the given amount.
*/
- void
- increaseQuantity(int amount) { mQuantity += amount; }
+ void increaseQuantity(int amount) { mQuantity += amount; }
/**
* Returns the number of items.
*/
- int
- getQuantity() const { return mQuantity; }
+ int getQuantity() const { return mQuantity; }
/**
* Sets whether this item is considered equipment.
*/
- void
- setEquipment(bool equipment) { mEquipment = equipment; }
+ void setEquipment(bool equipment) { mEquipment = equipment; }
/**
* Returns whether this item is considered equipment.
*/
- bool
- isEquipment() const { return mEquipment; }
+ bool isEquipment() const { return mEquipment; }
/**
* Sets whether this item is equipped.
*/
- void
- setEquipped(bool equipped) { mEquipped = equipped; }
+ void setEquipped(bool equipped) { mEquipped = equipped; }
/**
* Returns whether this item is equipped.
*/
- bool
- isEquipped() const { return mEquipped; }
+ bool isEquipped() const { return mEquipped; }
/**
* Sets the inventory index of this item.
*/
- void
- setInvIndex(int index) { mInvIndex = index; }
+ void setInvIndex(int index) { mInvIndex = index; }
/**
* Returns the inventory index of this item.
*/
- int
- getInvIndex() const { return mInvIndex; }
+ int getInvIndex() const { return mInvIndex; }
/**
* Returns information about this item type.
*/
- const ItemInfo&
- getInfo() const { return ItemDB::get(mId); }
+ const ItemInfo& getInfo() const { return ItemDB::get(mId); }
protected:
int mId; /**< Item type id. */
diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp
index ee887c73..7bfbc88e 100644
--- a/src/itemshortcut.cpp
+++ b/src/itemshortcut.cpp
@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "itemshortcut.h"
-
#include "configuration.h"
#include "inventory.h"
#include "item.h"
+#include "itemshortcut.h"
#include "localplayer.h"
#include "utils/tostring.h"
diff --git a/src/itemshortcut.h b/src/itemshortcut.h
index bc3f32ca..95e17f44 100644
--- a/src/itemshortcut.h
+++ b/src/itemshortcut.h
@@ -22,7 +22,7 @@
#ifndef ITEMSHORTCUT_H
#define ITEMSHORTCUT_H
-#define SHORTCUT_ITEMS 10
+#define SHORTCUT_ITEMS 12
class Item;
diff --git a/src/joystick.cpp b/src/joystick.cpp
index 6874e9cd..1233c37f 100644
--- a/src/joystick.cpp
+++ b/src/joystick.cpp
@@ -19,9 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "joystick.h"
+#include <cassert>
#include "configuration.h"
+#include "joystick.h"
#include "log.h"
#include <cassert>
diff --git a/src/joystick.h b/src/joystick.h
index aebd4b5f..a7090293 100644
--- a/src/joystick.h
+++ b/src/joystick.h
@@ -30,7 +30,9 @@ class Joystick
/**
* Number of buttons we can handle.
*/
- enum { MAX_BUTTONS = 6 };
+ enum {
+ MAX_BUTTONS = 6
+ };
/**
* Directions, to be used as bitmask values.
diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp
index 9ae7ed68..d7288796 100644
--- a/src/keyboardconfig.cpp
+++ b/src/keyboardconfig.cpp
@@ -19,8 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "keyboardconfig.h"
+#include <guichan/sdl/sdlinput.hpp>
+
#include "configuration.h"
+#include "keyboardconfig.h"
#include "log.h"
#include "gui/setup_keyboard.h"
@@ -40,13 +42,14 @@ static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = {
{"keyMoveRight", SDLK_RIGHT, "Move Right"},
{"keyAttack", SDLK_LCTRL, "Attack"},
{"keySmilie", SDLK_LALT, "Smilie"},
- {"keyTarget", SDLK_LSHIFT, "Target"},
+ {"keyTalk", SDLK_t, "Talk"},
+ {"keyTarget", SDLK_LSHIFT, "Stop Attack"},
{"keyTargetClosest", SDLK_a, "Target Closest"},
+ {"keyTargetNPC", SDLK_n, "Target NPC"},
{"keyTargetPlayer", SDLK_q, "Target Player"},
{"keyPickup", SDLK_z, "Pickup"},
{"keyHideWindows", SDLK_h, "Hide Windows"},
{"keyBeingSit", SDLK_s, "Sit"},
- {"keyShortcut0", SDLK_0, "Item Shortcut 0"},
{"keyShortcut1", SDLK_1, "Item Shortcut 1"},
{"keyShortcut2", SDLK_2, "Item Shortcut 2"},
{"keyShortcut3", SDLK_3, "Item Shortcut 3"},
@@ -56,6 +59,9 @@ static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = {
{"keyShortcut7", SDLK_7, "Item Shortcut 7"},
{"keyShortcut8", SDLK_8, "Item Shortcut 8"},
{"keyShortcut9", SDLK_9, "Item Shortcut 9"},
+ {"keyShortcut10", SDLK_0, "Item Shortcut 10"},
+ {"keyShortcut11", SDLK_MINUS, "Item Shortcut 11"},
+ {"keyShortcut12", SDLK_EQUALS, "Item Shortcut 12"},
{"keyWindowStatus", SDLK_F2, "Status Window"},
{"keyWindowInventory", SDLK_F3, "Inventory Window"},
{"keyWindowEquipment", SDLK_F4, "Equipment WIndow"},
@@ -64,7 +70,21 @@ static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = {
{"keyWindowChat", SDLK_F7, "Chat Window"},
{"keyWindowShortcut", SDLK_F8, "Item Shortcut Window"},
{"keyWindowSetup", SDLK_F9, "Setup Window"},
- {"keyWindowDebug", SDLK_F10, "Debug Window"}
+ {"keyWindowDebug", SDLK_F10, "Debug Window"},
+ {"keyWindowEmote", SDLK_F11, "Emote Window"},
+ {"keyWindowEmoteBar", SDLK_F12, "Emote Shortcut Window"},
+ {"keyEmoteShortcut1", SDLK_1, "Emote Shortcut 1"},
+ {"keyEmoteShortcut2", SDLK_2, "Emote Shortcut 2"},
+ {"keyEmoteShortcut3", SDLK_3, "Emote Shortcut 3"},
+ {"keyEmoteShortcut4", SDLK_4, "Emote Shortcut 4"},
+ {"keyEmoteShortcut5", SDLK_5, "Emote Shortcut 5"},
+ {"keyEmoteShortcut6", SDLK_6, "Emote Shortcut 6"},
+ {"keyEmoteShortcut7", SDLK_7, "Emote Shortcut 7"},
+ {"keyEmoteShortcut8", SDLK_8, "Emote Shortcut 8"},
+ {"keyEmoteShortcut9", SDLK_9, "Emote Shortcut 9"},
+ {"keyEmoteShortcut10", SDLK_0, "Emote Shortcut 10"},
+ {"keyEmoteShortcut11", SDLK_MINUS, "Emote Shortcut 11"},
+ {"keyEmoteShortcut12", SDLK_EQUALS, "Emote Shortcut 12"}
};
void KeyboardConfig::init()
@@ -110,11 +130,19 @@ void KeyboardConfig::makeDefault()
bool KeyboardConfig::hasConflicts()
{
int i, j;
+/**
+ * No need to parse the square matrix: only check one triangle
+ * that's enough to detect conflicts
+ */
for (i = 0; i < KEY_TOTAL; i++)
{
- for (j = 0; j < KEY_TOTAL; j++)
+ for (j = i, j++; j < KEY_TOTAL; j++)
{
- if (i != j && mKey[i].value == mKey[j].value)
+ // Allow for item shortcut and emote keys to overlap, but no other keys
+ if (!(((i >= KEY_SHORTCUT_1) && (i <= KEY_SHORTCUT_12)) &&
+ ((j >= KEY_EMOTE_1) && (j <= KEY_EMOTE_12)))
+ && mKey[i].value == mKey[j].value
+ )
{
return true;
}
@@ -140,6 +168,19 @@ int KeyboardConfig::getKeyIndex(int keyValue) const
return KEY_NO_VALUE;
}
+
+int KeyboardConfig::getKeyEmoteOffset(int keyValue) const
+{
+ for (int i = KEY_EMOTE_1; i <= KEY_EMOTE_12; i++)
+ {
+ if(keyValue == mKey[i].value)
+ {
+ return 1 + i - KEY_EMOTE_1;
+ }
+ }
+ return 0;
+}
+
bool KeyboardConfig::isKeyActive(int index)
{
return mActiveKeys[ mKey[index].value];
diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h
index 3317460f..2077126d 100644
--- a/src/keyboardconfig.h
+++ b/src/keyboardconfig.h
@@ -24,6 +24,8 @@
#include <string>
+#include <guichan/sdl/sdlinput.hpp>
+
#include "gui/sdlinput.h"
#include "gui/setup_keyboard.h"
@@ -101,6 +103,11 @@ class KeyboardConfig
int getKeyIndex(int keyValue) const;
/**
+ * Get the key function index for an emote by providing the offset value.
+ */
+ int getKeyEmoteOffset(int keyValue) const;
+
+ /**
* Set the enable flag, which will stop the user from doing actions.
*/
void setEnabled(bool flag)
@@ -148,14 +155,15 @@ class KeyboardConfig
KEY_MOVE_LEFT,
KEY_MOVE_RIGHT,
KEY_ATTACK,
- KEY_SMILIE,
+ KEY_EMOTE,
+ KEY_TALK,
KEY_TARGET,
KEY_TARGET_CLOSEST,
+ KEY_TARGET_NPC,
KEY_TARGET_PLAYER,
KEY_PICKUP,
KEY_HIDE_WINDOWS,
KEY_SIT,
- KEY_SHORTCUT_0,
KEY_SHORTCUT_1,
KEY_SHORTCUT_2,
KEY_SHORTCUT_3,
@@ -165,6 +173,9 @@ class KeyboardConfig
KEY_SHORTCUT_7,
KEY_SHORTCUT_8,
KEY_SHORTCUT_9,
+ KEY_SHORTCUT_10,
+ KEY_SHORTCUT_11,
+ KEY_SHORTCUT_12,
KEY_WINDOW_STATUS,
KEY_WINDOW_INVENTORY,
KEY_WINDOW_EQUIPMENT,
@@ -174,6 +185,20 @@ class KeyboardConfig
KEY_WINDOW_SHORTCUT,
KEY_WINDOW_SETUP,
KEY_WINDOW_DEBUG,
+ KEY_WINDOW_EMOTE,
+ KEY_WINDOW_EMOTE_SHORTCUT,
+ KEY_EMOTE_1,
+ KEY_EMOTE_2,
+ KEY_EMOTE_3,
+ KEY_EMOTE_4,
+ KEY_EMOTE_5,
+ KEY_EMOTE_6,
+ KEY_EMOTE_7,
+ KEY_EMOTE_8,
+ KEY_EMOTE_9,
+ KEY_EMOTE_10,
+ KEY_EMOTE_11,
+ KEY_EMOTE_12,
KEY_TOTAL
};
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 07044ce7..15f5b6b2 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -18,15 +18,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <cassert>
-#include "localplayer.h"
-
+#include "configuration.h"
#include "equipment.h"
#include "floor_item.h"
#include "game.h"
#include "inventory.h"
#include "item.h"
+#include "localplayer.h"
#include "main.h"
+#include "monster.h"
#include "particle.h"
#include "sound.h"
#include "monster.h"
@@ -38,10 +40,16 @@
#include "net/messageout.h"
#include "net/protocol.h"
+#include "resources/imageset.h"
+#include "resources/resourcemanager.h"
+
#include "utils/tostring.h"
LocalPlayer *player_node = NULL;
+static const int NAME_X_OFFSET = 15;
+static const int NAME_Y_OFFSET = 30;
+
LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map):
Player(id, job, map),
mCharId(0),
@@ -60,20 +68,52 @@ LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map):
mXp(0), mNetwork(0),
mTarget(NULL), mPickUpTarget(NULL),
mTrading(false), mGoingToTarget(false),
- mLastAction(-1),
- mWalkingDir(0), mDestX(0), mDestY(0),
- mInventory(new Inventory)
+ mTargetTime(-1), mLastAction(-1),
+ mLastTarget(-1), mWalkingDir(0),
+ mDestX(0), mDestY(0),
+ mInventory(new Inventory(INVENTORY_SIZE)),
+ mStorage(new Inventory(STORAGE_SIZE))
{
+ // Variable to keep the local player from doing certain actions before a map
+ // is initialized. e.g. drawing a player's name using the TextManager, since
+ // it appears to be dependant upon map coordinates for updating drawing.
+ mMapInitialized = false;
+
+ mUpdateName = true;
+
+ initTargetCursor();
}
LocalPlayer::~LocalPlayer()
{
delete mInventory;
+ delete mStorage;
+ delete mName;
+
+ for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++)
+ {
+ delete mTargetCursorInRange[i];
+ delete mTargetCursorOutRange[i];
+ mInRangeImages[i]->decRef();
+ mOutRangeImages[i]->decRef();
+ }
}
void LocalPlayer::logic()
{
switch (mAction) {
+ case STAND:
+ break;
+
+ case SIT:
+ break;
+
+ case DEAD:
+ break;
+
+ case HURT:
+ break;
+
case WALK:
mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed;
if (mFrame >= 6) {
@@ -91,7 +131,6 @@ void LocalPlayer::logic()
mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed;
if (mFrame >= frames) {
nextStep();
- attack();
}
break;
}
@@ -100,10 +139,65 @@ void LocalPlayer::logic()
if (get_elapsed_time(mLastAction) >= 1000) {
mLastAction = -1;
}
+ // Targeting allowed 4 times a second
+ if (get_elapsed_time(mLastTarget) >= 250) {
+ mLastTarget = -1;
+ }
+ // Remove target if its been on a being for more than a minute
+ if (get_elapsed_time(mTargetTime) >= 60000)
+ {
+ mTargetTime = -1;
+ setTarget(NULL);
+ mLastTarget = -1;
+ }
+
+ if (mTarget)
+ {
+ if (mTarget->mAction == DEAD)
+ {
+ stopAttack();
+ }
+ if (mKeepAttacking && mTarget)
+ {
+ attack(mTarget, true);
+ }
+
+ for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++)
+ {
+ player_node->mTargetCursorInRange[i]->update(10);
+ player_node->mTargetCursorOutRange[i]->update(10);
+ }
+ }
Being::logic();
}
+void LocalPlayer::setGM()
+{
+ mIsGM = !mIsGM;
+ mNameColor = mIsGM ? 0x009000: 0x202020;
+ setName(getName());
+ config.setValue(getName() + "GMassert", mIsGM);
+}
+
+void LocalPlayer::setName(const std::string &name)
+{
+ if (mName)
+ {
+ delete mName;
+ mName = 0;
+ }
+
+ if (config.getValue("showownname", false) && mMapInitialized)
+ {
+ Player::setName(name);
+ }
+ else
+ {
+ Being::setName(name);
+ }
+}
+
void LocalPlayer::nextStep()
{
if (mPath.empty())
@@ -240,9 +334,19 @@ void LocalPlayer::walk(unsigned char dir)
void LocalPlayer::setTarget(Being *target)
{
- if (target == mTarget)
- {
+ if (mLastTarget != -1 || target == this)
return;
+ mLastTarget = tick_time;
+
+ if ((target == NULL) || target == mTarget)
+ {
+ target = NULL;
+ mKeepAttacking = false;
+ mTargetTime = -1;
+ }
+ if (target)
+ {
+ mTargetTime = tick_time;
}
if (mTarget && mTarget->getType() == Being::MONSTER)
{
@@ -384,25 +488,25 @@ bool LocalPlayer::tradeRequestOk() const
void LocalPlayer::attack(Being *target, bool keep)
{
- // Can only attack when standing still
- if (mAction != STAND)
+ mKeepAttacking = keep;
+
+ if (!target)
return;
- if (keep && target)
+ if ((mTarget != target) || !mTarget)
{
+ mLastTarget = -1;
setTarget(target);
}
- else if (mTarget)
- {
- target = mTarget;
- }
-
- if (!target)
- return;
int dist_x = target->mX - mX;
int dist_y = target->mY - mY;
+ // Must be standing and be within attack range to continue
+ if ((mAction != STAND) || (mAttackRange < abs(dist_x)) ||
+ (mAttackRange < abs(dist_y)))
+ return;
+
if (abs(dist_y) >= abs(dist_x))
{
if (dist_y > 0)
@@ -418,8 +522,13 @@ void LocalPlayer::attack(Being *target, bool keep)
setDirection(LEFT);
}
- setAction(ATTACK);
+ // Implement charging attacks here
+ mLastAttackTime = 0;
+
mWalkTime = tick_time;
+ mTargetTime = tick_time;
+
+ setAction(ATTACK);
if (mEquippedWeapon)
{
@@ -434,11 +543,22 @@ void LocalPlayer::attack(Being *target, bool keep)
outMsg.writeInt16(0x0089);
outMsg.writeInt32(target->getId());
outMsg.writeInt8(0);
+
+ if (!keep)
+ {
+ stopAttack();
+ }
}
void LocalPlayer::stopAttack()
{
+ if (mTarget)
+ {
+ setAction(STAND);
+ mLastTarget = -1;
+ }
setTarget(NULL);
+ mLastTarget = -1;
}
Being* LocalPlayer::getTarget() const
@@ -481,6 +601,7 @@ bool LocalPlayer::withinAttackRange(Being *target)
void LocalPlayer::setGotoTarget(Being *target)
{
+ mLastTarget = -1;
setTarget(target);
mGoingToTarget = true;
setDestination(target->mX, target->mY);
@@ -527,3 +648,85 @@ void LocalPlayer::handleStatusEffect(StatusEffect *effect, int effectId)
}
}
}
+
+void LocalPlayer::initTargetCursor()
+{
+ // Load target cursors
+ loadTargetCursor("graphics/gui/target-cursor-blue-s.png", 44, 35,
+ false, TC_SMALL);
+ loadTargetCursor("graphics/gui/target-cursor-red-s.png", 44, 35,
+ true, TC_SMALL);
+ loadTargetCursor("graphics/gui/target-cursor-blue-m.png", 62, 44,
+ false, TC_MEDIUM);
+ loadTargetCursor("graphics/gui/target-cursor-red-m.png", 62, 44,
+ true, TC_MEDIUM);
+ loadTargetCursor("graphics/gui/target-cursor-blue-l.png", 82, 60,
+ false, TC_LARGE);
+ loadTargetCursor("graphics/gui/target-cursor-red-l.png", 82, 60,
+ true, TC_LARGE);
+}
+
+void LocalPlayer::loadTargetCursor(std::string filename, int width, int height,
+ bool outRange, TargetCursorSize size)
+{
+ assert(size > -1);
+ assert(size < 3);
+
+ ImageSet* currentImageSet;
+ SimpleAnimation* currentCursor;
+
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ currentImageSet = resman->getImageSet(filename, width, height);
+ Animation *anim = new Animation();
+ for (unsigned int i = 0; i < currentImageSet->size(); ++i)
+ {
+ anim->addFrame(currentImageSet->get(i), 75, 0, 0);
+ }
+ currentCursor = new SimpleAnimation(anim);
+
+ if (outRange)
+ {
+ mOutRangeImages[size] = currentImageSet;
+ mTargetCursorOutRange[size] = currentCursor;
+ }
+ else
+ {
+ mInRangeImages[size] = currentImageSet;
+ mTargetCursorInRange[size] = currentCursor;
+ }
+}
+
+void LocalPlayer::drawTargetCursor(Graphics *graphics, int scrollX, int scrollY)
+{
+
+ // Draw target marker if needed
+ if (mTarget)
+ {
+ // Calculate target circle position
+
+ // Find whether target is in range
+ int rangeX = abs(mTarget->mX - mX);
+ int rangeY = abs(mTarget->mY - mY);
+ int attackRange = getAttackRange();
+
+ // Get the correct target cursors graphic
+ TargetCursorSize cursorSize = mTarget->getTargetCursorSize();
+
+ if (rangeX > attackRange || rangeY > attackRange)
+ {
+ mTarget->mTargetCursor = mTargetCursorOutRange[cursorSize]->getCurrentImage();
+ }
+ else
+ {
+ mTarget->mTargetCursor = mTargetCursorInRange[cursorSize]->getCurrentImage();
+ }
+
+ // Draw the target cursor at the correct position
+ int posX = mTarget->getPixelX() + 16 - mTarget->mTargetCursor->getWidth() / 2 - scrollX;
+ int posY = mTarget->getPixelY() + 16 - mTarget->mTargetCursor->getHeight() / 2 - scrollY;
+
+ graphics->drawImage(mTarget->mTargetCursor, posX, posY);
+ }
+ return;
+}
diff --git a/src/localplayer.h b/src/localplayer.h
index 6b6486e5..55e12bf1 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -25,11 +25,16 @@
#include <vector>
#include "player.h"
+#include "simpleanimation.h"
// TODO move into some sane place...
#define MAX_SLOT 2
+#define INVENTORY_SIZE 102
+#define STORAGE_SIZE 301
+
class FloorItem;
+class ImageSet;
class Inventory;
class Item;
class Network;
@@ -54,7 +59,7 @@ class LocalPlayer : public Player
*/
~LocalPlayer();
- void setName(const std::string &name) {Being::setName(name); }
+ virtual void setName(const std::string &name);
void setNetwork(Network *network) { mNetwork = network; }
Network *getNetwork() {return mNetwork; }
virtual void logic();
@@ -71,6 +76,11 @@ class LocalPlayer : public Player
Inventory* getInventory() const { return mInventory; }
/**
+ * Returns the player's storage
+ */
+ Inventory* getStorage() const { return mStorage; }
+
+ /**
* Equips an item.
*/
void equipItem(Item *item);
@@ -118,6 +128,14 @@ class LocalPlayer : public Player
void attack(Being *target = NULL, bool keep = false);
+ /**
+ * Triggers whether or not to show the name as a GM name.
+ * NOTE: This doesn't mean that just anyone can use this.
+ * If the server doesn't acknowlege you, you won't be shown
+ * as a GM on other people's clients.
+ */
+ virtual void setGM();
+
void stopAttack();
Being* getTarget() const;
@@ -166,6 +184,12 @@ class LocalPlayer : public Player
void revive();
/**
+ * Accessors for mInStorage
+ */
+ bool getInStorage() { return mInStorage; }
+ void setInStorage(bool inStorage) { mInStorage = inStorage; }
+
+ /**
* Sets the amount of XP. Shows XP gaining effect if the player is on
* a map.
*/
@@ -198,6 +222,20 @@ class LocalPlayer : public Player
Uint16 mStatPoint, mSkillPoint;
Uint16 mStatsPointsToAttribute;
+ bool mUpdateName; /** Whether or not the name settings have changed */
+
+ bool mMapInitialized; /** Whether or not the map is available yet */
+
+ float mLastAttackTime; /**< Used to synchronize the charge dialog */
+
+ void drawTargetCursor(Graphics *graphics, int offsetX, int offsetY);
+
+ /** Animated in range target cursor. */
+ SimpleAnimation *mTargetCursorInRange[NUM_TC];
+
+ /** Animated out of range target cursor. */
+ SimpleAnimation *mTargetCursorOutRange[NUM_TC];
+
protected:
virtual void
handleStatusEffect(StatusEffect *effect, int effectId);
@@ -211,15 +249,35 @@ class LocalPlayer : public Player
FloorItem *mPickUpTarget;
bool mTrading;
+ bool mInStorage; /**< Whether storage is currently accessible */
bool mGoingToTarget;
- int mLastAction; /**< Time stamp of the last action, -1 if none. */
- int mWalkingDir; /**< The direction the player is walking in. */
- int mDestX; /**< X coordinate of destination. */
- int mDestY; /**< Y coordinate of destination. */
+ bool mKeepAttacking; /** Whether or not to continue to attack */
+ int mTargetTime; /** How long the being has been targeted **/
+ int mLastAction; /**< Time stamp of the last action, -1 if none. */
+ int mLastTarget; /** Time stamp of last targeting action, -1 if none. */
+ int mWalkingDir; /**< The direction the player is walking in. */
+ int mDestX; /**< X coordinate of destination. */
+ int mDestY; /**< Y coordinate of destination. */
std::vector<int> mStatusEffectIcons;
Inventory *mInventory;
+ Inventory *mStorage;
+
+ /**
+ * Helper function for loading target cursors
+ */
+ void loadTargetCursor(std::string filename, int width, int height,
+ bool outRange, Being::TargetCursorSize size);
+
+ /** Images of in range target cursor. */
+ ImageSet *mInRangeImages[NUM_TC];
+
+ /** Images of out of range target cursor. */
+ ImageSet *mOutRangeImages[NUM_TC];
+
+ // Load the target cursors into memory
+ void initTargetCursor();
};
extern LocalPlayer *player_node;
diff --git a/src/main.cpp b/src/main.cpp
index 0291fd86..6866093f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,48 +19,44 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "main.h"
-
#include <getopt.h>
#include <iostream>
#include <physfs.h>
+#include <SDL_image.h>
#include <unistd.h>
#include <vector>
-#include <SDL_image.h>
#include <guichan/actionlistener.hpp>
+
+#include <guichan/sdl/sdlinput.hpp>
+
#include <guichan/widgets/label.hpp>
#include <libxml/parser.h>
-#ifdef WIN32
-#include <SDL_syswm.h>
-#endif
-#ifndef WIN32
-#include <cerrno>
-#include <sys/stat.h>
-#endif
-#if defined __APPLE__
-#include <CoreFoundation/CFBundle.h>
-#endif
+#include <SDL/SDL_ttf.h>
#include "configuration.h"
-#include "keyboardconfig.h"
-#include "player_relations.h"
+#include "emoteshortcut.h"
#include "game.h"
#include "graphics.h"
#include "itemshortcut.h"
-#include "lockedarray.h"
+#include "keyboardconfig.h"
#include "localplayer.h"
+#include "lockedarray.h"
#include "log.h"
#include "logindata.h"
+#include "main.h"
#ifdef USE_OPENGL
#include "openglgraphics.h"
#endif
+#include "player_relations.h"
+#include "serverinfo.h"
#include "sound.h"
#include "gui/char_server.h"
#include "gui/char_select.h"
+#include "gui/colour.h"
#include "gui/gui.h"
#include "gui/login.h"
#include "gui/ok_dialog.h"
@@ -77,6 +73,8 @@
#include "net/messageout.h"
#include "net/network.h"
+#include "resources/colordb.h"
+#include "resources/emotedb.h"
#include "resources/image.h"
#include "resources/itemdb.h"
#include "resources/monsterdb.h"
@@ -87,7 +85,24 @@
#include "utils/gettext.h"
#include "utils/tostring.h"
-namespace {
+#ifdef __APPLE__
+#include <CoreFoundation/CFBundle.h>
+#endif
+
+#ifdef __MINGW32__
+#include <windows.h>
+#define usleep(usec) (Sleep ((usec) / 1000), 0)
+#endif
+
+#ifdef WIN32
+#include <SDL_syswm.h>
+#else
+#include <cerrno>
+#include <sys/stat.h>
+#endif
+
+namespace
+{
Window *setupWindow = 0;
struct SetupListener : public gcn::ActionListener
@@ -123,6 +138,7 @@ CharServerHandler charServerHandler;
LoginData loginData;
LockedArray<LocalPlayer*> charInfo(MAX_SLOT + 1);
+Colour *textColour;
// This anonymous namespace hides whatever is inside from other modules.
namespace {
@@ -168,10 +184,13 @@ struct Options
*/
void setUpdatesDir()
{
+ std::stringstream updates;
+
// If updatesHost is currently empty, fill it from config file
- if (updateHost.empty()) {
+ if (updateHost.empty())
+ {
updateHost =
- config.getValue("updatehost", "http://updates.themanaworld.org");
+ config.getValue("updatehost", "http://updates.themanaworld.org/");
}
// Remove any trailing slash at the end of the update host
@@ -181,29 +200,59 @@ void setUpdatesDir()
// Parse out any "http://" or "ftp://", and set the updates directory
size_t pos;
pos = updateHost.find("://");
- if (pos != updateHost.npos) {
- if (pos + 3 < updateHost.length()) {
- updatesDir =
- "updates/" + updateHost.substr(pos + 3);
- } else {
- logger->log("Error: Invalid update host: %s", updateHost.c_str());
- errorMessage = "Invalid update host: " + updateHost;
+ if (pos != updateHost.npos)
+ {
+ if (pos + 3 < updateHost.length())
+ {
+ updates << "updates/" << updateHost.substr(pos + 3)
+ << "/" << loginData.port;
+ updatesDir = updates.str();
+ }
+ else
+ {
+ logger->log(_("Error: Invalid update host: %s"), updateHost.c_str());
+ errorMessage = _("Invalid update host: ") + updateHost;
state = ERROR_STATE;
}
- } else {
- logger->log("Warning: no protocol was specified for the update host");
- updatesDir = "updates/" + updateHost;
+ }
+ else
+ {
+ logger->log(_("Warning: no protocol was specified for the update host"));
+ updates << "updates/" << updateHost << "/" << loginData.port;
+ updatesDir = updates.str();
}
ResourceManager *resman = ResourceManager::getInstance();
// Verify that the updates directory exists. Create if necessary.
- if (!resman->isDirectory("/" + updatesDir)) {
- if (!resman->mkdir("/" + updatesDir)) {
- logger->log("Error: %s/%s can't be made, but doesn't exist!",
+ if (!resman->isDirectory("/" + updatesDir))
+ {
+ if (!resman->mkdir("/" + updatesDir))
+ {
+#if defined WIN32
+ std::string newDir = homeDir + "\\" + updatesDir;
+ std::string::size_type loc = newDir.find("/", 0);
+
+ while (loc != std::string::npos)
+ {
+ newDir.replace(loc, 1, "\\");
+ loc = newDir.find("/", loc);
+ }
+
+ if (!CreateDirectory(newDir.c_str(), 0) &&
+ GetLastError() != ERROR_ALREADY_EXISTS)
+ {
+ logger->log(_("Error: %s can't be made, but doesn't exist!"),
+ newDir.c_str());
+ errorMessage = _("Error creating updates directory!");
+ state = ERROR_STATE;
+ }
+#else
+ logger->log(_("Error: %s/%s can't be made, but doesn't exist!"),
homeDir.c_str(), updatesDir.c_str());
- errorMessage = "Error creating updates directory!";
+ errorMessage = _("Error creating updates directory!");
state = ERROR_STATE;
+#endif
}
}
}
@@ -219,7 +268,7 @@ void init_engine(const Options &options)
GetLastError() != ERROR_ALREADY_EXISTS)
#elif defined __APPLE__
// Use Application Directory instead of .tmw
- homeDir = std::string(PHYSFS_getUserDir()) +
+ homeDir = std::string(PHYSFS_getUserDir()) +
"/Library/Application Support/The Mana World";
if ((mkdir(homeDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) &&
(errno != EEXIST))
@@ -230,7 +279,7 @@ void init_engine(const Options &options)
#endif
{
std::cout << homeDir
- << " can't be created, but it doesn't exist! Exiting."
+ << _(" can't be created, but it doesn't exist! Exiting.")
<< std::endl;
exit(1);
}
@@ -239,15 +288,15 @@ void init_engine(const Options &options)
logger->setLogFile(homeDir + std::string("/tmw.log"));
#ifdef PACKAGE_VERSION
- logger->log("Starting The Mana World Version %s", PACKAGE_VERSION);
+ logger->log(_("Starting The Mana World Version %s"), PACKAGE_VERSION);
#else
- logger->log("Starting The Mana World - Version not defined");
+ logger->log(_("Starting The Mana World - Version not defined"));
#endif
// Initialize SDL
- logger->log("Initializing SDL...");
+ logger->log(_("Initializing SDL..."));
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
- std::cerr << "Could not initialize SDL: " <<
+ std::cerr << _("Could not initialize SDL: ") <<
SDL_GetError() << std::endl;
exit(1);
}
@@ -260,7 +309,7 @@ void init_engine(const Options &options)
if (!resman->setWriteDir(homeDir)) {
std::cout << homeDir
- << " couldn't be set as home directory! Exiting."
+ << _(" couldn't be set as home directory! Exiting.")
<< std::endl;
exit(1);
}
@@ -280,7 +329,7 @@ void init_engine(const Options &options)
if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path,
PATH_MAX))
{
- fprintf(stderr, "Can't find Resources directory\n");
+ fprintf(stderr, _("Can't find Resources directory\n"));
}
CFRelease(resourcesURL);
strncat(path, "/data", PATH_MAX - 1);
@@ -290,9 +339,9 @@ void init_engine(const Options &options)
#endif
// Fill configuration with defaults
- logger->log("Initializing configuration...");
- config.setValue("host", "server.themanaworld.org");
- config.setValue("port", 6901);
+ logger->log(_("Initializing configuration..."));
+ config.setValue("host", "www.themanaworld.org");
+ config.setValue("port", 21001);
config.setValue("hwaccel", 0);
#if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL
config.setValue("opengl", 1);
@@ -312,24 +361,24 @@ void init_engine(const Options &options)
// Checking if the configuration file exists... otherwise creates it with
// default options !
- FILE *tmwFile = 0;
+ FILE *configFile = 0;
std::string configPath = options.configPath;
if (configPath.empty())
configPath = homeDir + "/config.xml";
- tmwFile = fopen(configPath.c_str(), "r");
+ configFile = fopen(configPath.c_str(), "r");
// If we can't read it, it doesn't exist !
- if (tmwFile == NULL) {
+ if (configFile == NULL) {
// We reopen the file in write mode and we create it
- tmwFile = fopen(configPath.c_str(), "wt");
+ configFile = fopen(configPath.c_str(), "wt");
}
- if (tmwFile == NULL) {
+ if (configFile == NULL) {
std::cout << "Can't create " << configPath << ". "
"Using Defaults." << std::endl;
} else {
- fclose(tmwFile);
+ fclose(configFile);
config.init(configPath);
}
@@ -364,17 +413,17 @@ void init_engine(const Options &options)
graphics = new Graphics();
#endif
- int width = (int) config.getValue("screenwidth", defaultScreenWidth);
- int height = (int) config.getValue("screenheight", defaultScreenHeight);
- int bpp = 0;
- bool fullscreen = ((int) config.getValue("screen", 0) == 1);
- bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1);
+ const int width = (int) config.getValue("screenwidth", defaultScreenWidth);
+ const int height = (int) config.getValue("screenheight", defaultScreenHeight);
+ const int bpp = 0;
+ const bool fullscreen = ((int) config.getValue("screen", 0) == 1);
+ const bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1);
// Try to set the desired video mode
if (!graphics->setVideoMode(width, height, bpp, fullscreen, hwaccel))
{
- std::cerr << "Couldn't set "
- << width << "x" << height << "x" << bpp << " video mode: "
+ std::cerr << _("Couldn't set ")
+ << width << "x" << height << "x" << bpp << _(" video mode: ")
<< SDL_GetError() << std::endl;
exit(1);
}
@@ -385,6 +434,9 @@ void init_engine(const Options &options)
// Initialize the item shortcuts.
itemShortcut = new ItemShortcut();
+ // Initialize the emote shortcuts.
+ emoteShortcut = new EmoteShortcut();
+
gui = new Gui(graphics);
state = LOGIN_STATE; /**< Initial game state */
@@ -401,7 +453,7 @@ void init_engine(const Options &options)
catch (const char *err) {
state = ERROR_STATE;
errorMessage = err;
- logger->log("Warning: %s", err);
+ logger->log(_("Warning: %s"), err);
}
// Initialize keyboard
@@ -416,6 +468,7 @@ void exit_engine()
{
// Before config.write() since it writes the shortcuts to the config
delete itemShortcut;
+ delete emoteShortcut;
config.write();
@@ -429,6 +482,8 @@ void exit_engine()
sound.close();
// Unload XML databases
+ ColorDB::unload();
+ EmoteDB::unload();
ItemDB::unload();
MonsterDB::unload();
NPCDB::unload();
@@ -440,27 +495,27 @@ void exit_engine()
void printHelp()
{
std::cout
- << "tmw" << std::endl << std::endl
- << "Options: " << std::endl
- << " -h --help : Display this help" << std::endl
- << " -v --version : Display the version" << std::endl
- << " -u --skipupdate : Skip the update process" << std::endl
- << " -d --data : Directory to load game data from" << std::endl
- << " -U --username : Login with this username" << std::endl
- << " -P --password : Login with this password" << std::endl
- << " -D --default : Bypass the login process with default settings" << std::endl
- << " -p --playername : Login with this player" << std::endl
- << " -C --configfile : Configuration file to use" << std::endl
- << " -H --updatehost : Use this update host" << std::endl;
+ << _("tmw") << std::endl << std::endl
+ << _("Options: ") << std::endl
+ << _(" -C --configfile : Configuration file to use") << std::endl
+ << _(" -d --data : Directory to load game data from") << std::endl
+ << _(" -D --default : Bypass the login process with default settings") << std::endl
+ << _(" -h --help : Display this help") << std::endl
+ << _(" -H --updatehost : Use this update host") << std::endl
+ << _(" -p --playername : Login with this player") << std::endl
+ << _(" -P --password : Login with this password") << std::endl
+ << _(" -u --skipupdate : Skip the update downloads") << std::endl
+ << _(" -U --username : Login with this username") << std::endl
+ << _(" -v --version : Display the version") << std::endl;
}
void printVersion()
{
#ifdef PACKAGE_VERSION
- std::cout << "The Mana World version " << PACKAGE_VERSION << std::endl;
+ std::cout << _("The Mana World version ") << PACKAGE_VERSION << std::endl;
#else
- std::cout << "The Mana World version " <<
- "(local build?, PACKAGE_VERSION is not defined)" << std::endl;
+ std::cout << _("The Mana World version ") <<
+ _"(local build?, PACKAGE_VERSION is not defined)") << std::endl;
#endif
}
@@ -469,16 +524,16 @@ void parseOptions(int argc, char *argv[], Options &options)
const char *optstring = "hvud:U:P:Dp:C:H:";
const struct option long_options[] = {
- { "help", no_argument, 0, 'h' },
- { "version", no_argument, 0, 'v' },
- { "skipupdate", no_argument, 0, 'u' },
+ { "configfile", required_argument, 0, 'C' },
{ "data", required_argument, 0, 'd' },
- { "username", required_argument, 0, 'U' },
- { "password", required_argument, 0, 'P' },
{ "default", no_argument, 0, 'D' },
{ "playername", required_argument, 0, 'p' },
- { "configfile", required_argument, 0, 'C' },
+ { "password", required_argument, 0, 'P' },
+ { "help", no_argument, 0, 'h' },
{ "updatehost", required_argument, 0, 'H' },
+ { "skipupdate", no_argument, 0, 'u' },
+ { "username", required_argument, 0, 'U' },
+ { "version", no_argument, 0, 'v' },
{ 0 }
};
@@ -490,36 +545,36 @@ void parseOptions(int argc, char *argv[], Options &options)
break;
switch (result) {
- default: // Unknown option
- case 'h':
- options.printHelp = true;
- break;
- case 'v':
- options.printVersion = true;
- break;
- case 'u':
- options.skipUpdate = true;
+ case 'C':
+ options.configPath = optarg;
break;
case 'd':
options.dataPath = optarg;
break;
- case 'U':
- options.username = optarg;
- break;
- case 'P':
- options.password = optarg;
- break;
case 'D':
options.chooseDefault = true;
break;
+ default: // Unknown option
+ case 'h':
+ options.printHelp = true;
+ break;
+ case 'H':
+ options.updateHost = optarg;
+ break;
case 'p':
options.playername = optarg;
break;
- case 'C':
- options.configPath = optarg;
+ case 'P':
+ options.password = optarg;
break;
- case 'H':
- options.updateHost = optarg;
+ case 'u':
+ options.skipUpdate = true;
+ break;
+ case 'U':
+ options.username = optarg;
+ break;
+ case 'v':
+ options.printVersion = true;
break;
}
}
@@ -556,8 +611,8 @@ struct ErrorListener : public gcn::ActionListener
// TODO Find some nice place for these functions
void accountLogin(Network *network, LoginData *loginData)
{
- logger->log("Trying to connect to account server...");
- logger->log("Username is %s", loginData->username.c_str());
+ logger->log(_("Trying to connect to account server..."));
+ logger->log(_("Username is %s"), loginData->username.c_str());
network->connect(loginData->hostname, loginData->port);
network->registerHandler(&loginHandler);
loginHandler.setLoginData(loginData);
@@ -597,9 +652,21 @@ void accountLogin(Network *network, LoginData *loginData)
config.setValue("remember", loginData->remember);
}
+inline int MIN(int x, int y)
+{
+ return x < y ? x : y;
+}
+
+void positionDialog(Window *dialog, int screenWidth, int screenHeight)
+{
+ dialog->setPosition(
+ MIN(screenWidth * 5 / 8, screenWidth - dialog->getWidth()),
+ MIN(screenHeight * 5 / 8, screenHeight - dialog->getHeight()));
+}
+
void charLogin(Network *network, LoginData *loginData)
{
- logger->log("Trying to connect to char server...");
+ logger->log(_("Trying to connect to char server..."));
network->connect(loginData->hostname, loginData->port);
network->registerHandler(&charServerHandler);
charServerHandler.setCharInfo(&charInfo);
@@ -621,14 +688,14 @@ void charLogin(Network *network, LoginData *loginData)
void mapLogin(Network *network, LoginData *loginData)
{
- logger->log("Memorizing selected character %s",
+ logger->log(_("Memorizing selected character %s"),
player_node->getName().c_str());
config.setValue("lastCharacter", player_node->getName());
MessageOut outMsg(network);
- logger->log("Trying to connect to map server...");
- logger->log("Map: %s", map_path.c_str());
+ logger->log(_("Trying to connect to map server..."));
+ logger->log(_("Map: %s"), map_path.c_str());
network->connect(loginData->hostname, loginData->port);
network->registerHandler(&mapLoginHandler);
@@ -697,6 +764,9 @@ int main(int argc, char *argv[])
unsigned int oldstate = !state; // We start with a status change.
+ // Needs to be created in main, as the updater uses it
+ textColour = new Colour();
+
Game *game = NULL;
Window *currentDialog = NULL;
Image *login_wallpaper = NULL;
@@ -707,7 +777,7 @@ int main(int argc, char *argv[])
gcn::Label *versionLabel = new gcn::Label(PACKAGE_VERSION);
top->add(versionLabel, 2, 2);
#endif
- ProgressBar *progressBar = new ProgressBar(0.0f, 100, 20);
+ ProgressBar *progressBar = new ProgressBar(0.0f, 100, 20, 168, 116, 31);
gcn::Label *progressLabel = new gcn::Label();
top->add(progressBar, 5, top->getHeight() - 5 - progressBar->getHeight());
top->add(progressLabel, 15 + progressBar->getWidth(),
@@ -729,12 +799,34 @@ int main(int argc, char *argv[])
loginData.password = options.password;
}
loginData.hostname = config.getValue("host", "server.themanaworld.org");
- loginData.port = (short)config.getValue("port", 0);
+ loginData.port = (short)config.getValue("port", 6901);
loginData.remember = config.getValue("remember", 0);
loginData.registerLogin = false;
SDLNet_Init();
Network *network = new Network();
+
+ // Set the most appropriate wallpaper, based on screen width
+ int screenWidth = (int) config.getValue("screenwidth", defaultScreenWidth);
+ int screenHeight = static_cast<int>(config.getValue("screenheight",
+ defaultScreenHeight));
+ std::string wallpaperName;
+
+ wallpaperName = "graphics/images/login_wallpaper.png";
+ if (screenWidth >= 1024 && screenWidth < 1280)
+ wallpaperName = "graphics/images/login_wallpaper_1024x768.png";
+ else if (screenWidth >= 1280 && screenWidth < 1440)
+ wallpaperName = "graphics/images/login_wallpaper_1280x960.png";
+ else if (screenWidth >= 1440 && screenWidth < 1600)
+ wallpaperName = "graphics/images/login_wallpaper_1440x1080.png";
+ else if (screenWidth >= 1600)
+ wallpaperName = "graphics/images/login_wallpaper_1600x1200.png";
+
+ login_wallpaper = ResourceManager::getInstance()-> getImage(wallpaperName);
+
+ if (!login_wallpaper)
+ logger->log(_("Couldn't load %s as wallpaper"), wallpaperName.c_str());
+
while (state != EXIT_STATE)
{
// Handle SDL events
@@ -770,16 +862,6 @@ int main(int argc, char *argv[])
}
}
- if (!login_wallpaper)
- {
- login_wallpaper = ResourceManager::getInstance()->
- getImage("graphics/images/login_wallpaper.png");
- if (!login_wallpaper)
- {
- logger->error("Couldn't load login_wallpaper.png");
- }
- }
-
if (progressBar->isVisible())
{
progressBar->setProgress(progressBar->getProgress() + 0.005f);
@@ -808,7 +890,7 @@ int main(int argc, char *argv[])
// Reload the wallpaper in case that it was updated
login_wallpaper->decRef();
login_wallpaper = ResourceManager::getInstance()->
- getImage("graphics/images/login_wallpaper.png");
+ getImage(wallpaperName);
break;
// Those states don't cause a network disconnect
@@ -847,9 +929,12 @@ int main(int argc, char *argv[])
false);
// Load XML databases
+ ColorDB::load();
ItemDB::load();
MonsterDB::load();
NPCDB::load();
+ EmoteDB::load();
+
state = CHAR_CONNECT_STATE;
break;
@@ -861,33 +946,49 @@ int main(int argc, char *argv[])
state = ACCOUNT_STATE;
} else {
currentDialog = new LoginDialog(&loginData);
+ positionDialog(currentDialog, screenWidth,
+ screenHeight);
}
break;
case REGISTER_STATE:
logger->log("State: REGISTER");
currentDialog = new RegisterDialog(&loginData);
+ positionDialog(currentDialog, screenWidth, screenHeight);
break;
case CHAR_SERVER_STATE:
logger->log("State: CHAR_SERVER");
+
+ if (n_server == 1)
+ {
+ SERVER_INFO *si = *server_info;
+ loginData.hostname = iptostring(si->address);
+ loginData.port = si->port;
+ loginData.updateHost = si->updateHost;
+ state = UPDATE_STATE;
+ }
+ else
{
int nextState = (options.skipUpdate) ?
LOADDATA_STATE : UPDATE_STATE;
currentDialog = new ServerSelectDialog(&loginData,
- nextState);
- }
- if (options.chooseDefault || options.playername != "") {
- ((ServerSelectDialog*) currentDialog)->action(
- gcn::ActionEvent(NULL, "ok"));
+ nextState);
+ positionDialog(currentDialog, screenWidth,
+ screenHeight);
+ if (options.chooseDefault || options.playername != "")
+ {
+ ((ServerSelectDialog*) currentDialog)->action(
+ gcn::ActionEvent(NULL, "ok"));
+ }
}
break;
-
case CHAR_SELECT_STATE:
logger->log("State: CHAR_SELECT");
currentDialog = new CharSelectDialog(network, &charInfo,
(loginData.sex == 0) ?
GENDER_FEMALE : GENDER_MALE);
+ positionDialog(currentDialog, screenWidth, screenHeight);
if (((CharSelectDialog*) currentDialog)->
selectByName(options.playername))
@@ -899,6 +1000,7 @@ int main(int argc, char *argv[])
if (options.chooseDefault)
((CharSelectDialog*) currentDialog)->action(
gcn::ActionEvent(NULL, "ok"));
+
break;
case GAME_STATE:
@@ -936,13 +1038,21 @@ int main(int argc, char *argv[])
setUpdatesDir();
logger->log("State: UPDATE");
- currentDialog = new UpdaterWindow(updateHost,
- homeDir + "/" + updatesDir);
+
+ if (options.skipUpdate) {
+ state = LOADDATA_STATE;
+ } else {
+ currentDialog = new UpdaterWindow(updateHost,
+ homeDir + "/" + updatesDir);
+ positionDialog(currentDialog, screenWidth,
+ screenHeight);
+ }
break;
case ERROR_STATE:
logger->log("State: ERROR");
currentDialog = new OkDialog(_("Error"), errorMessage);
+ positionDialog(currentDialog, screenWidth, screenHeight);
currentDialog->addActionListener(&errorListener);
currentDialog = NULL; // OkDialog deletes itself
network->disconnect();
@@ -979,8 +1089,15 @@ int main(int argc, char *argv[])
break;
}
}
+ /*
+ * This loop can really stress the CPU, for no reason since it's
+ * just constantly redrawing the wallpaper. Added the following
+ * usleep to limit it to 20 FPS during the login sequence
+ */
+ usleep(50000);
}
+ delete textColour;
#ifdef PACKAGE_VERSION
delete versionLabel;
#endif
diff --git a/src/main.h b/src/main.h
index 0e884fb2..df2c4397 100644
--- a/src/main.h
+++ b/src/main.h
@@ -30,8 +30,8 @@
#include "winver.h"
#endif
-#ifndef TMW_DATADIR
-#define TMW_DATADIR ""
+#ifndef AETHYRA_DATADIR
+#define AETHYRA_DATADIR ""
#endif
/*
diff --git a/src/map.cpp b/src/map.cpp
index f0c84159..17c28180 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -19,21 +19,21 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "map.h"
-
#include <queue>
#include "beingmanager.h"
#include "configuration.h"
#include "game.h"
#include "graphics.h"
+#include "localplayer.h"
+#include "map.h"
#include "particle.h"
#include "sprite.h"
#include "tileset.h"
-#include "resources/resourcemanager.h"
#include "resources/ambientoverlay.h"
#include "resources/image.h"
+#include "resources/resourcemanager.h"
#include "utils/dtor.h"
#include "utils/tostring.h"
@@ -136,6 +136,7 @@ void MapLayer::draw(Graphics *graphics,
// If drawing the fringe layer, make sure all sprites above this row of
// tiles have been drawn
if (mIsFringeLayer) {
+ player_node->drawTargetCursor(graphics, scrollX, scrollY);
while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) {
(*si)->draw(graphics, -scrollX, -scrollY);
si++;
@@ -256,7 +257,8 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY)
// draw the game world
Layers::const_iterator layeri = mLayers.begin();
- for (; layeri != mLayers.end(); ++layeri) {
+ for (; layeri != mLayers.end(); ++layeri)
+ {
(*layeri)->draw(graphics,
startX, startY, endX, endY,
scrollX, scrollY,
@@ -547,12 +549,15 @@ void Map::addParticleEffect(const std::string &effectFile, int x, int y)
void Map::initializeParticleEffects(Particle* particleEngine)
{
- for (std::list<ParticleEffectData>::iterator i = particleEffects.begin();
- i != particleEffects.end();
- i++
- )
+ if (config.getValue("particleeffects", 1))
{
- particleEngine->addEffect(i->file, i->x, i->y);
+ for (std::list<ParticleEffectData>::iterator i = particleEffects.begin();
+ i != particleEffects.end();
+ i++
+ )
+ {
+ particleEngine->addEffect(i->file, i->x, i->y);
+ }
}
}
diff --git a/src/map.h b/src/map.h
index 33133ac4..bd4cb122 100644
--- a/src/map.h
+++ b/src/map.h
@@ -186,8 +186,7 @@ class Map : public Properties
/**
* Finds the tile set that a tile with the given global id is part of.
*/
- Tileset*
- getTilesetWithGid(int gid) const;
+ Tileset* getTilesetWithGid(int gid) const;
/**
* Get tile reference.
@@ -207,26 +206,22 @@ class Map : public Properties
/**
* Returns the width of this map.
*/
- int
- getWidth() const { return mWidth; }
+ int getWidth() const { return mWidth; }
/**
* Returns the height of this map.
*/
- int
- getHeight() const { return mHeight; }
+ int getHeight() const { return mHeight; }
/**
* Returns the tile width of this map.
*/
- int
- getTileWidth() const { return mTileWidth; }
+ int getTileWidth() const { return mTileWidth; }
/**
* Returns the tile height used by this map.
*/
- int
- getTileHeight() const { return mTileHeight; }
+ int getTileHeight() const { return mTileHeight; }
/**
* Find a path from one location to the next.
@@ -236,14 +231,12 @@ class Map : public Properties
/**
* Adds a sprite to the map.
*/
- SpriteIterator
- addSprite(Sprite *sprite);
+ SpriteIterator addSprite(Sprite *sprite);
/**
* Removes a sprite from the map.
*/
- void
- removeSprite(SpriteIterator iterator);
+ void removeSprite(SpriteIterator iterator);
/**
* Adds a particle effect
@@ -270,9 +263,8 @@ class Map : public Properties
/**
* Draws the overlay graphic to the given graphics output.
*/
- void
- drawOverlay(Graphics *graphics, float scrollX, float scrollY,
- int detail);
+ void drawOverlay(Graphics *graphics, float scrollX, float scrollY,
+ int detail);
/**
* Tells whether a tile is occupied by a being.
diff --git a/src/monster.cpp b/src/monster.cpp
index f50855ca..68ed22f8 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -19,14 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "monster.h"
-
#include "animatedsprite.h"
#include "game.h"
-#include "sound.h"
+#include "localplayer.h"
+#include "monster.h"
#include "particle.h"
+#include "sound.h"
#include "text.h"
-#include "localplayer.h"
#include "resources/monsterdb.h"
@@ -44,6 +43,7 @@ Monster::Monster(Uint32 id, Uint16 job, Map *map):
// Setup Monster sprites
int c = BASE_SPRITE;
const std::list<std::string> &sprites = info.getSprites();
+
for (std::list<std::string>::const_iterator i = sprites.begin();
i != sprites.end();
i++)
@@ -61,21 +61,26 @@ Monster::Monster(Uint32 id, Uint16 job, Map *map):
mSprites[c] = AnimatedSprite::load("graphics/sprites/error.xml");
}
- const std::list<std::string> &particleEffects = info.getParticleEffects();
- for ( std::list<std::string>::const_iterator i = particleEffects.begin();
- i != particleEffects.end();
- i++
- )
+ if (mParticleEffects)
{
- controlParticle(particleEngine->addEffect((*i), 0, 0));
+ const std::list<std::string> &particleEffects = info.getParticleEffects();
+ for ( std::list<std::string>::const_iterator i = particleEffects.begin();
+ i != particleEffects.end(); i++
+ )
+ {
+ controlParticle(particleEngine->addEffect((*i), 0, 0));
+ }
}
+
+ mNameColor = 0xff2020;
}
-Monster::~Monster()
+Monster::~Monster()
{
if (mText)
{
- player_node->setTarget(0);
+ delete mText;
+ player_node->setTarget(NULL);
}
}
@@ -99,9 +104,11 @@ Being::Type Monster::getType() const
return MONSTER;
}
-void Monster::setAction(Uint8 action)
+void Monster::setAction(Action action)
{
SpriteAction currentAction = ACTION_INVALID;
+ int rotation = 0;
+ std::string particleEffect;
switch (action)
{
@@ -115,13 +122,34 @@ void Monster::setAction(Uint8 action)
case ATTACK:
currentAction = ACTION_ATTACK;
mSprites[BASE_SPRITE]->reset();
+
+ //attack particle effect
+ particleEffect = getInfo().getAttackParticleEffect();
+ if (particleEffect != "" && mParticleEffects)
+ {
+ switch (mDirection)
+ {
+ case DOWN: rotation = 0; break;
+ case LEFT: rotation = 90; break;
+ case UP: rotation = 180; break;
+ case RIGHT: rotation = 270; break;
+ default: break;
+ }
+ Particle *p;
+ p = particleEngine->addEffect(
+ particleEffect, 0, 0, rotation);
+ controlParticle(p);
+ }
break;
case STAND:
- currentAction = ACTION_STAND;
- break;
+ currentAction = ACTION_STAND;
+ break;
case HURT:
- // Not implemented yet
- break;
+ // Not implemented yet
+ break;
+ case SIT:
+ // Also not implemented yet
+ break;
}
if (currentAction != ACTION_INVALID)
@@ -164,13 +192,15 @@ const MonsterInfo &Monster::getInfo() const
void Monster::showName(bool show)
{
- delete mText;
+ if (mText)
+ {
+ delete mText;
+ }
if (show)
{
mText = new Text(getInfo().getName(), mPx + NAME_X_OFFSET,
mPy + NAME_Y_OFFSET - getHeight(),
- gcn::Graphics::CENTER,
- gcn::Color(255, 64, 64));
+ gcn::Graphics::CENTER, gcn::Color(255, 64, 64));
}
else
{
diff --git a/src/monster.h b/src/monster.h
index 36812f41..8d7f8ae7 100644
--- a/src/monster.h
+++ b/src/monster.h
@@ -36,7 +36,7 @@ class Monster : public Being
virtual void logic();
- virtual void setAction(Uint8 action);
+ virtual void setAction(Action action);
virtual Type getType() const;
@@ -62,8 +62,7 @@ class Monster : public Being
/**
* Returns the MonsterInfo, with static data about this monster.
*/
- const MonsterInfo&
- getInfo() const;
+ const MonsterInfo& getInfo() const;
/**
* Determine whether the mob should show it's name
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index e0ade2ae..8aaede44 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -19,24 +19,24 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "beinghandler.h"
-
+#include <iostream>
#include <SDL_types.h>
+#include "beinghandler.h"
#include "messagein.h"
#include "protocol.h"
#include "../being.h"
#include "../beingmanager.h"
+#include "../effectmanager.h"
#include "../game.h"
#include "../localplayer.h"
#include "../log.h"
#include "../main.h"
+#include "../npc.h"
#include "../particle.h"
-#include "../sound.h"
-#include <iostream>
#include "../player_relations.h"
-#include "../npc.h"
+#include "../sound.h"
const int EMOTION_TIME = 150; /**< Duration of emotion icon */
@@ -73,6 +73,7 @@ void BeingHandler::handleMessage(MessageIn *msg)
Uint16 headTop, headMid, headBottom;
Uint16 shoes, gloves;
Uint16 weapon, shield;
+ Uint16 gmstatus;
Sint16 param1;
int stunMode;
Uint32 statusEffects;
@@ -211,22 +212,17 @@ void BeingHandler::handleMessage(MessageIn *msg)
if (!dstBeing)
break;
+ // If this is player's current target, clear it.
if (dstBeing == player_node->getTarget())
- {
player_node->stopAttack();
- }
if (dstBeing == current_npc)
current_npc = NULL;
if (msg->readInt8() == 1)
- {
dstBeing->setAction(Being::DEAD);
- }
else
- {
beingManager->destroyBeing(dstBeing);
- }
break;
@@ -244,28 +240,26 @@ void BeingHandler::handleMessage(MessageIn *msg)
switch (type)
{
case 0x0a: // Critical Damage
- if (dstBeing) {
- dstBeing->controlParticle(particleEngine->addEffect(
- "graphics/particles/crit.particle.xml", 0, 0));
- }
+ if (dstBeing)
+ dstBeing->showCrit();
case 0x00: // Damage
- if (dstBeing) {
+ if (dstBeing)
dstBeing->takeDamage(param1);
- }
- if (srcBeing) {
+ if (srcBeing)
srcBeing->handleAttack(dstBeing, param1);
- }
break;
case 0x02: // Sit
- if (srcBeing) {
+ if (srcBeing)
+ {
srcBeing->mFrame = 0;
srcBeing->setAction(Being::SIT);
}
break;
case 0x03: // Stand up
- if (srcBeing) {
+ if (srcBeing)
+ {
srcBeing->mFrame = 0;
srcBeing->setAction(Being::STAND);
}
@@ -279,8 +273,9 @@ void BeingHandler::handleMessage(MessageIn *msg)
break;
int effectType = msg->readInt32();
+ Being* being = beingManager->findBeing(id);
- beingManager->findBeing(id)->triggerEffect(effectType);
+ effectManager->trigger(effectType, being);
break;
}
@@ -450,18 +445,22 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->setDirection(dir);
}
- msg->readInt16(); // GM status
+ gmstatus = msg->readInt16();
+ if (gmstatus & 0x80)
+ dstBeing->setGM();
if (msg->getId() == SMSG_PLAYER_UPDATE_1)
{
- switch (msg->readInt8()) {
-
- case 1: dstBeing->setAction(Being::DEAD);
- break;
-
- case 2: dstBeing->setAction(Being::SIT);
- break;
-
+ switch (msg->readInt8())
+ {
+ case 1:
+ if (dstBeing->getType() != Being::NPC)
+ dstBeing->setAction(Being::DEAD);
+ break;
+
+ case 2:
+ dstBeing->setAction(Being::SIT);
+ break;
}
}
else if (msg->getId() == SMSG_PLAYER_MOVE)
@@ -482,16 +481,16 @@ void BeingHandler::handleMessage(MessageIn *msg)
case SMSG_PLAYER_STOP:
/*
- * Instruction from server to stop walking at x, y.
- *
- * Some people like having this enabled. Others absolutely
- * despise it. So I'm setting to so that it only affects the
- * local player if the person has set a key "EnableSync" to "1"
- * in their config.xml file.
- *
- * This packet will be honored for all other beings, regardless
- * of the config setting.
- */
+ * Instruction from server to stop walking at x, y.
+ *
+ * Some people like having this enabled. Others absolutely
+ * despise it. So I'm setting to so that it only affects the
+ * local player if the person has set a key "EnableSync" to "1"
+ * in their config.xml file.
+ *
+ * This packet will be honored for all other beings, regardless
+ * of the config setting.
+ */
id = msg->readInt32();
if (mSync || id != player_node->getId()) {
@@ -509,11 +508,11 @@ void BeingHandler::handleMessage(MessageIn *msg)
case SMSG_PLAYER_MOVE_TO_ATTACK:
/*
- * This is an *advisory* message, telling the client that
- * it needs to move the character before attacking
- * a target (out of range, obstruction in line of fire).
- * We can safely ignore this...
- */
+ * This is an *advisory* message, telling the client that
+ * it needs to move the character before attacking
+ * a target (out of range, obstruction in line of fire).
+ * We can safely ignore this...
+ */
break;
case 0x0119:
diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h
index f72f0380..54b82075 100644
--- a/src/net/beinghandler.h
+++ b/src/net/beinghandler.h
@@ -27,7 +27,7 @@
class BeingHandler : public MessageHandler
{
public:
- BeingHandler(bool);
+ BeingHandler(bool enableSync);
void handleMessage(MessageIn *msg);
diff --git a/src/net/buysellhandler.cpp b/src/net/buysellhandler.cpp
index b7f3ecd4..5292b6f9 100644
--- a/src/net/buysellhandler.cpp
+++ b/src/net/buysellhandler.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "buysellhandler.h"
-
#include <SDL_types.h>
+#include "buysellhandler.h"
#include "messagein.h"
#include "protocol.h"
@@ -37,8 +36,8 @@
#include "../gui/sell.h"
extern BuyDialog *buyDialog;
-extern SellDialog *sellDialog;
extern Window *buySellDialog;
+extern SellDialog *sellDialog;
BuySellHandler::BuySellHandler()
{
diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp
index cfa52c38..909100e5 100644
--- a/src/net/charserverhandler.cpp
+++ b/src/net/charserverhandler.cpp
@@ -20,19 +20,24 @@
*/
#include "charserverhandler.h"
-
#include "messagein.h"
#include "network.h"
#include "protocol.h"
+#include "../extensions.h"
#include "../game.h"
#include "../localplayer.h"
#include "../log.h"
#include "../logindata.h"
#include "../main.h"
-#include "../gui/ok_dialog.h"
#include "../gui/char_select.h"
+#include "../gui/ok_dialog.h"
+
+/*
+ * Yeah, this is a global. Get over it.
+ */
+struct EXTENSIONS extensions;
CharServerHandler::CharServerHandler():
mCharCreateDialog(0)
@@ -54,6 +59,7 @@ CharServerHandler::CharServerHandler():
void CharServerHandler::handleMessage(MessageIn *msg)
{
int slot;
+ int flags;
LocalPlayer *tempPlayer;
logger->log("CharServerHandler: Packet ID: %x, Length: %d",
@@ -61,8 +67,13 @@ void CharServerHandler::handleMessage(MessageIn *msg)
switch (msg->getId())
{
case 0x006b:
- // Skip length word and an additional mysterious 20 bytes
- msg->skip(2 + 20);
+ msg->skip(2); // Length word
+ flags = msg->readInt32(); // Aethyra extensions flags
+ logger->log("Server flags are: %x", flags);
+ extensions.aethyra_inventory = (bool)(flags & 0x01);
+ extensions.aethyra_spells = (bool)(flags & 0x02);
+ extensions.aethyra_misc = (bool)(flags & 0x04);
+ msg->skip(16); // Unused
// Derive number of characters from message length
n_character = (msg->getLength() - 24) / 106;
diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp
index d25d4bcd..bf5a5a37 100644
--- a/src/net/chathandler.cpp
+++ b/src/net/chathandler.cpp
@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "chathandler.h"
-
#include <SDL_types.h>
#include <string>
+#include "chathandler.h"
#include "messagein.h"
#include "protocol.h"
diff --git a/src/net/equipmenthandler.cpp b/src/net/equipmenthandler.cpp
index e5bbf6fe..973de0f6 100644
--- a/src/net/equipmenthandler.cpp
+++ b/src/net/equipmenthandler.cpp
@@ -20,7 +20,6 @@
*/
#include "equipmenthandler.h"
-
#include "messagein.h"
#include "protocol.h"
@@ -107,7 +106,10 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
break;
}
- // Unequip any existing equipped item in this position
+ /*
+ * An item may occupy more than 1 slot. If so, it's
+ * only shown as equipped on the *first* slot.
+ */
mask = 1;
position = 0;
while (!(equipPoint & mask)) {
@@ -115,7 +117,10 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
position++;
}
logger->log("Position %i", position);
- item = player_node->getInventory()->getItem(player_node->mEquipment->getEquipment(position));
+
+ item = player_node->getInventory()->getItem(player_node->mEquipment->getEquipment(position));
+
+ // Unequip any existing equipped item in this position
if (item) {
item->setEquipped(false);
}
@@ -152,24 +157,11 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
item->setEquipped(false);
- switch (item->getId()) {
- case 529:
- case 1199:
- player_node->mEquipment->setArrows(0);
- break;
- case 521:
- case 522:
- case 530:
- case 536:
- case 1200:
- case 1201:
- player_node->setSprite(Being::WEAPON_SPRITE, 0);
- // TODO: Why this break? Shouldn't a weapon be
- // unequipped in inventory too?
- break;
- default:
- player_node->mEquipment->removeEquipment(position);
- break;
+ if (equipPoint & 0x8000) { // Arrows
+ player_node->mEquipment->setArrows(0);
+ }
+ else {
+ player_node->mEquipment->removeEquipment(position);
}
logger->log("Unequipping: %i %i(%i) %i",
index, equipPoint, type, position);
@@ -186,12 +178,12 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
break;
item = inventory->getItem(index);
- if (!item)
- break;
- item->setEquipped(true);
- player_node->mEquipment->setArrows(index);
- logger->log("Arrows equipped: %i", index);
+ if (item) {
+ item->setEquipped(true);
+ player_node->mEquipment->setArrows(index);
+ logger->log("Arrows equipped: %i", index);
+ }
break;
}
}
diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp
index cd9b5ce0..3ce0899a 100644
--- a/src/net/inventoryhandler.cpp
+++ b/src/net/inventoryhandler.cpp
@@ -19,22 +19,22 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "inventoryhandler.h"
-
#include <SDL_types.h>
+#include "inventoryhandler.h"
#include "messagein.h"
#include "protocol.h"
-#include "../resources/iteminfo.h"
+#include "../inventory.h"
#include "../item.h"
#include "../itemshortcut.h"
#include "../localplayer.h"
#include "../log.h"
-#include "../inventory.h"
#include "../gui/chat.h"
+#include "../resources/iteminfo.h"
+
#include "../utils/tostring.h"
InventoryHandler::InventoryHandler()
@@ -45,6 +45,12 @@ InventoryHandler::InventoryHandler()
SMSG_PLAYER_INVENTORY_REMOVE,
SMSG_PLAYER_INVENTORY_USE,
SMSG_ITEM_USE_RESPONSE,
+ SMSG_PLAYER_STORAGE_ITEMS,
+ SMSG_PLAYER_STORAGE_EQUIP,
+ SMSG_PLAYER_STORAGE_STATUS,
+ SMSG_PLAYER_STORAGE_ADD,
+ SMSG_PLAYER_STORAGE_REMOVE,
+ SMSG_PLAYER_STORAGE_CLOSE,
0
};
handledMessages = _messages;
@@ -53,35 +59,69 @@ InventoryHandler::InventoryHandler()
void InventoryHandler::handleMessage(MessageIn *msg)
{
Sint32 number;
- Sint16 index, amount, itemId, equipType;
+ Sint16 index, amount, itemId, equipType, arrow;
+ Sint16 identified, cards[4], itemType;
Inventory *inventory = player_node->getInventory();
+ Inventory *storage = player_node->getStorage();
switch (msg->getId())
{
case SMSG_PLAYER_INVENTORY:
- // Only called on map load / warp. First reset all items
- // to not load them twice on map change.
- inventory->clear();
+ case SMSG_PLAYER_STORAGE_ITEMS:
+ case SMSG_PLAYER_STORAGE_EQUIP:
+ switch (msg->getId()) {
+ case SMSG_PLAYER_INVENTORY:
+ // Clear inventory - this will be a complete refresh
+ inventory->clear();
+ break;
+ case SMSG_PLAYER_STORAGE_ITEMS:
+ /*
+ * This packet will always be followed by a
+ * SMSG_PLAYER_STORAGE_EQUIP packet. The two packets
+ * together comprise a complete refresh of storage, so
+ * clear storage here
+ */
+ storage->clear();
+ logger->log("Received SMSG_PLAYER_STORAGE_ITEMS");
+ break;
+ default:
+ logger->log("Received SMSG_PLAYER_STORAGE_EQUIP");
+ break;
+ }
msg->readInt16(); // length
number = (msg->getLength() - 4) / 18;
- for (int loop = 0; loop < number; loop++)
- {
+ for (int loop = 0; loop < number; loop++) {
index = msg->readInt16();
itemId = msg->readInt16();
- msg->readInt8(); // type
- msg->readInt8(); // identify flag
- amount = msg->readInt16();
- msg->skip(2); // unknown
- msg->skip(8); // card (4 shorts)
-
- inventory->setItem(index, itemId, amount, false);
-
- // Trick because arrows are not considered equipment
- if (itemId == 1199 || itemId == 529)
- {
- if (Item *item = inventory->getItem(index))
- item->setEquipment(true);
+ itemType = msg->readInt8();
+ identified = msg->readInt8();
+ if (msg->getId() == SMSG_PLAYER_STORAGE_EQUIP) {
+ amount = 1;
+ msg->readInt16(); // Equip Point?
+ } else {
+ amount = msg->readInt16();
+ }
+ arrow = msg->readInt16();
+ if (msg->getId() == SMSG_PLAYER_STORAGE_EQUIP) {
+ msg->readInt8(); // Attribute (broken)
+ msg->readInt8(); // Refine level
+ }
+ for (int i = 0; i < 4; i++)
+ cards[i] = msg->readInt16();
+
+ if (msg->getId() == SMSG_PLAYER_INVENTORY) {
+ inventory->setItem(index, itemId, amount, false);
+
+ // Trick because arrows are not considered equipment
+ if (arrow & 0x8000) {
+ if (Item *item = inventory->getItem(index))
+ item->setEquipment(true);
+ }
+ } else {
+ logger->log("Index:%d, ID:%d, Type:%d, Identified:%d, Qty:%d, Cards:%d, %d, %d, %d",
+ index, itemId, itemType, identified, amount, cards[0], cards[1], cards[2], cards[3]);
+ storage->setItem(index, itemId, amount, false);
}
}
break;
@@ -90,12 +130,13 @@ void InventoryHandler::handleMessage(MessageIn *msg)
index = msg->readInt16();
amount = msg->readInt16();
itemId = msg->readInt16();
- msg->readInt8(); // identify flag
+ identified = msg->readInt8();
msg->readInt8(); // attribute
msg->readInt8(); // refine
- msg->skip(8); // card
+ for (int i = 0; i < 4; i++)
+ cards[i] = msg->readInt16();
equipType = msg->readInt16();
- msg->readInt8(); // type
+ itemType = msg->readInt8();
if (msg->readInt8() > 0) {
chatWindow->chatLog("Unable to pick up item", BY_SERVER);
@@ -147,5 +188,38 @@ void InventoryHandler::handleMessage(MessageIn *msg)
item->setQuantity(amount);
}
break;
+
+ case SMSG_PLAYER_STORAGE_STATUS:
+ /*
+ * Basic slots used vs total slots info
+ * We don't really need this information, but this is
+ * the closest we get to an "Open Storage" packet
+ * from the server. It always comes after the two
+ * SMSG_PLAYER_STORAGE_... packets that update
+ * storage contents.
+ */
+ logger->log("Received SMSG_PLAYER_STORAGE_STATUS");
+ player_node->setInStorage(true);
+ break;
+
+ case SMSG_PLAYER_STORAGE_ADD:
+ /*
+ * Move an item into storage
+ */
+ break;
+
+ case SMSG_PLAYER_STORAGE_REMOVE:
+ /*
+ * Move an item out of storage
+ */
+ break;
+
+ case SMSG_PLAYER_STORAGE_CLOSE:
+ /*
+ * Storage access has been closed
+ */
+ player_node->setInStorage(false);
+ logger->log("Received SMSG_PLAYER_STORAGE_CLOSE");
+ break;
}
}
diff --git a/src/net/itemhandler.cpp b/src/net/itemhandler.cpp
index 03313a55..8c4af4e4 100644
--- a/src/net/itemhandler.cpp
+++ b/src/net/itemhandler.cpp
@@ -20,7 +20,6 @@
*/
#include "itemhandler.h"
-
#include "messagein.h"
#include "protocol.h"
diff --git a/src/net/loginhandler.cpp b/src/net/loginhandler.cpp
index 646c5f3c..f240618d 100644
--- a/src/net/loginhandler.cpp
+++ b/src/net/loginhandler.cpp
@@ -20,7 +20,6 @@
*/
#include "loginhandler.h"
-
#include "messagein.h"
#include "network.h"
#include "protocol.h"
@@ -35,7 +34,7 @@ extern SERVER_INFO **server_info;
LoginHandler::LoginHandler()
{
static const Uint16 _messages[] = {
- SMSG_UPDATE_HOST,
+ 0x0063,
0x0069,
0x006a,
0
@@ -87,7 +86,7 @@ void LoginHandler::handleMessage(MessageIn *msg)
iptostring(server_info[i]->address),
server_info[i]->port);
}
- state = CHAR_SERVER_STATE;
+ state = CHAR_SERVER_STATE;
break;
case 0x006a:
diff --git a/src/net/loginhandler.h b/src/net/loginhandler.h
index a380c767..c847b4c1 100644
--- a/src/net/loginhandler.h
+++ b/src/net/loginhandler.h
@@ -22,6 +22,8 @@
#ifndef NET_LOGINHANDLER_H
#define NET_LOGINHANDLER_H
+#include <string>
+
#include "messagehandler.h"
#include <string>
diff --git a/src/net/maploginhandler.cpp b/src/net/maploginhandler.cpp
index 0d349a6d..1b0919fa 100644
--- a/src/net/maploginhandler.cpp
+++ b/src/net/maploginhandler.cpp
@@ -20,7 +20,6 @@
*/
#include "maploginhandler.h"
-
#include "messagein.h"
#include "protocol.h"
diff --git a/src/net/messagehandler.cpp b/src/net/messagehandler.cpp
index 063532d4..f1561a31 100644
--- a/src/net/messagehandler.cpp
+++ b/src/net/messagehandler.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "messagehandler.h"
-
#include <cassert>
+#include "messagehandler.h"
#include "network.h"
MessageHandler::MessageHandler():
diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp
index cbcde3fe..a288d936 100644
--- a/src/net/messagein.cpp
+++ b/src/net/messagein.cpp
@@ -19,17 +19,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "messagein.h"
-
#include <cassert>
#include <SDL.h>
#include <SDL_endian.h>
+#include "messagein.h"
+
#define MAKEWORD(low,high) \
((unsigned short)(((unsigned char)(low)) | \
((unsigned short)((unsigned char)(high))) << 8))
-
MessageIn::MessageIn(const char *data, unsigned int length):
mData(data),
mLength(length),
@@ -39,15 +38,13 @@ MessageIn::MessageIn(const char *data, unsigned int length):
mId = readInt16();
}
-Sint8
-MessageIn::readInt8()
+Sint8 MessageIn::readInt8()
{
assert(mPos < mLength);
return mData[mPos++];
}
-Sint16
-MessageIn::readInt16()
+Sint16 MessageIn::readInt16()
{
assert(mPos + 2 <= mLength);
mPos += 2;
@@ -58,8 +55,7 @@ MessageIn::readInt16()
#endif
}
-Sint32
-MessageIn::readInt32()
+Sint32 MessageIn::readInt32()
{
assert(mPos + 4 <= mLength);
mPos += 4;
@@ -70,8 +66,7 @@ MessageIn::readInt32()
#endif
}
-void
-MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction)
+void MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction)
{
assert(mPos + 3 <= mLength);
@@ -120,8 +115,7 @@ MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction)
mPos += 3;
}
-void
-MessageIn::readCoordinatePair(Uint16 &srcX, Uint16 &srcY,
+void MessageIn::readCoordinatePair(Uint16 &srcX, Uint16 &srcY,
Uint16 &dstX, Uint16 &dstY)
{
assert(mPos + 5 <= mLength);
@@ -143,15 +137,13 @@ MessageIn::readCoordinatePair(Uint16 &srcX, Uint16 &srcY,
mPos += 5;
}
-void
-MessageIn::skip(unsigned int length)
+void MessageIn::skip(unsigned int length)
{
assert(mPos + length <= mLength);
mPos += length;
}
-std::string
-MessageIn::readString(int length)
+std::string MessageIn::readString(int length)
{
// Get string length
if (length < 0) {
diff --git a/src/net/messagein.h b/src/net/messagein.h
index 1788aa97..0ff6e78a 100644
--- a/src/net/messagein.h
+++ b/src/net/messagein.h
@@ -22,8 +22,8 @@
#ifndef MESSAGEIN_
#define MESSAGEIN_
-#include <string>
#include <SDL_types.h>
+#include <string>
/**
* Used for parsing an incoming message.
@@ -43,14 +43,12 @@ class MessageIn
/**
* Returns the message ID.
*/
- short
- getId() { return mId; }
+ short getId() { return mId; }
/**
* Returns the message length.
*/
- unsigned int
- getLength() { return mLength; }
+ unsigned int getLength() { return mLength; }
Sint8 readInt8(); /**< Reads a byte. */
Sint16 readInt16(); /**< Reads a short. */
@@ -60,30 +58,26 @@ class MessageIn
* Reads a special 3 byte block used by eAthena, containing x and y
* coordinates and direction.
*/
- void
- readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction);
+ void readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction);
/**
* Reads a special 5 byte block used by eAthena, containing a source
* and destination coordinate pair.
*/
- void
- readCoordinatePair(Uint16 &srcX, Uint16 &srcY,
- Uint16 &dstX, Uint16 &dstY);
+ void readCoordinatePair(Uint16 &srcX, Uint16 &srcY,
+ Uint16 &dstX, Uint16 &dstY);
/**
* Skips a given number of bytes.
*/
- void
- skip(unsigned int length);
+ void skip(unsigned int length);
/**
* Reads a string. If a length is not given (-1), it is assumed
* that the length of the string is stored in a short at the
* start of the string.
*/
- std::string
- readString(int length = -1);
+ std::string readString(int length = -1);
private:
const char* mData; /**< The message data. */
diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp
index 8f361e5e..bf4957be 100644
--- a/src/net/messageout.cpp
+++ b/src/net/messageout.cpp
@@ -20,13 +20,12 @@
*/
#include <cstring>
-#include <string>
#include <SDL.h>
#include <SDL_endian.h>
-
-#include "network.h"
+#include <string>
#include "messageout.h"
+#include "network.h"
MessageOut::MessageOut(Network *network):
mNetwork(network),
diff --git a/src/net/network.cpp b/src/net/network.cpp
index 1463c696..941995c9 100644
--- a/src/net/network.cpp
+++ b/src/net/network.cpp
@@ -19,15 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "network.h"
+#include <sstream>
#include "messagehandler.h"
#include "messagein.h"
+#include "network.h"
#include "../log.h"
-#include <sstream>
-
/** Warning: buffers and other variables are shared,
so there can be only one connection active at a time */
@@ -432,8 +431,7 @@ char *iptostring(int address)
return asciiIP;
}
-void
-Network::setError(const std::string& error)
+void Network::setError(const std::string& error)
{
logger->log("Network error: %s", error.c_str());
mError = error;
diff --git a/src/net/network.h b/src/net/network.h
index c942a819..c035f55c 100644
--- a/src/net/network.h
+++ b/src/net/network.h
@@ -48,47 +48,33 @@ class Network
~Network();
- bool
- connect(const std::string &address, short port);
+ bool connect(const std::string &address, short port);
- void
- disconnect();
+ void disconnect();
- void
- registerHandler(MessageHandler *handler);
+ void registerHandler(MessageHandler *handler);
- void
- unregisterHandler(MessageHandler *handler);
+ void unregisterHandler(MessageHandler *handler);
- void
- clearHandlers();
+ void clearHandlers();
- int
- getState() const { return mState; }
+ int getState() const { return mState; }
- const std::string&
- getError() const { return mError; }
+ const std::string& getError() const { return mError; }
- bool
- isConnected() const { return mState == CONNECTED; }
+ bool isConnected() const { return mState == CONNECTED; }
- int
- getInSize() const { return mInSize; }
+ int getInSize() const { return mInSize; }
- void
- skip(int len);
+ void skip(int len);
- bool
- messageReady();
+ bool messageReady();
- MessageIn
- getNextMessage();
+ MessageIn getNextMessage();
- void
- dispatchMessages();
+ void dispatchMessages();
- void
- flush();
+ void flush();
// ERROR replaced by NET_ERROR because already defined in Windows
enum {
@@ -100,17 +86,13 @@ class Network
};
protected:
- void
- setError(const std::string& error);
+ void setError(const std::string& error);
- Uint16
- readWord(int pos);
+ Uint16 readWord(int pos);
- bool
- realConnect();
+ bool realConnect();
- void
- receive();
+ void receive();
TCPsocket mSocket;
diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp
index b0314e47..82b07d41 100644
--- a/src/net/npchandler.cpp
+++ b/src/net/npchandler.cpp
@@ -19,18 +19,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npchandler.h"
-
#include "messagein.h"
+#include "npchandler.h"
#include "protocol.h"
#include "../beingmanager.h"
+#include "../localplayer.h"
#include "../npc.h"
+#include "../gui/npc_text.h"
#include "../gui/npcintegerdialog.h"
#include "../gui/npclistdialog.h"
#include "../gui/npcstringdialog.h"
-#include "../gui/npc_text.h"
extern NpcIntegerDialog *npcIntegerDialog;
extern NpcListDialog *npcListDialog;
@@ -60,6 +60,7 @@ void NPCHandler::handleMessage(MessageIn *msg)
case SMSG_NPC_CHOICE:
msg->readInt16(); // length
id = msg->readInt32();
+ player_node->setAction(LocalPlayer::STAND);
current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcListDialog->parseItems(msg->readString(msg->getLength() - 8));
npcListDialog->setVisible(true);
@@ -68,15 +69,15 @@ void NPCHandler::handleMessage(MessageIn *msg)
case SMSG_NPC_MESSAGE:
msg->readInt16(); // length
id = msg->readInt32();
+ player_node->setAction(LocalPlayer::STAND);
current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcTextDialog->addText(msg->readString(msg->getLength() - 8));
npcListDialog->setVisible(false);
npcTextDialog->setVisible(true);
break;
- case SMSG_NPC_CLOSE:
+ case SMSG_NPC_CLOSE:
id = msg->readInt32();
- dynamic_cast<NPC*>(beingManager->findBeing(id));
if (current_npc == dynamic_cast<NPC*>(beingManager->findBeing(id)))
current_npc = NULL;
break;
diff --git a/src/net/partyhandler.cpp b/src/net/partyhandler.cpp
new file mode 100644
index 00000000..d4b7455b
--- /dev/null
+++ b/src/net/partyhandler.cpp
@@ -0,0 +1,123 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/actionlistener.hpp>
+
+#include "partyhandler.h"
+#include "protocol.h"
+#include "messagein.h"
+
+#include "../gui/chat.h"
+#include "../gui/confirm_dialog.h"
+
+#include "../beingmanager.h"
+#include "../game.h"
+#include "../party.h"
+
+PartyHandler::PartyHandler(Party *party) : mParty(party)
+{
+ static const Uint16 _messages[] = {
+ SMSG_PARTY_CREATE,
+ SMSG_PARTY_INFO,
+ SMSG_PARTY_INVITE,
+ SMSG_PARTY_INVITED,
+ SMSG_PARTY_SETTINGS,
+ SMSG_PARTY_MEMBER_INFO,
+ SMSG_PARTY_LEAVE,
+ SMSG_PARTY_UPDATE_HP,
+ SMSG_PARTY_UPDATE_COORDS,
+ SMSG_PARTY_MESSAGE,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void PartyHandler::handleMessage(MessageIn *msg)
+{
+ switch (msg->getId())
+ {
+ case SMSG_PARTY_CREATE:
+ mParty->createResponse(msg->readInt8());
+ break;
+ case SMSG_PARTY_INFO:
+ break;
+ case SMSG_PARTY_INVITE:
+ {
+ std::string nick = msg->readString(24);
+ int status = msg->readInt8();
+ mParty->inviteResponse(nick, status);
+ break;
+ }
+ case SMSG_PARTY_INVITED:
+ {
+ int id = msg->readInt32();
+ Being *being = beingManager->findBeing(id);
+ if (being == NULL)
+ {
+ break;
+ }
+ std::string nick;
+ int gender = 0;
+ std::string partyName = "";
+ if (being->getType() != Being::PLAYER)
+ {
+ nick = "";
+ }
+ else
+ {
+ nick = being->getName();
+ gender = being->getGender();
+ partyName = msg->readString(24);
+ }
+ mParty->invitedAsk(nick, gender, partyName);
+ break;
+ }
+ case SMSG_PARTY_SETTINGS:
+ break;
+ case SMSG_PARTY_MEMBER_INFO:
+ break;
+ case SMSG_PARTY_LEAVE:
+ {
+ /*int id = */msg->readInt32();
+ std::string nick = msg->readString(24);
+ /*int fail = */msg->readInt8();
+ mParty->leftResponse(nick);
+ break;
+ }
+ case SMSG_PARTY_UPDATE_HP:
+ break;
+ case SMSG_PARTY_UPDATE_COORDS:
+ break;
+ case SMSG_PARTY_MESSAGE:
+ { // new block to enable local variables
+ int msgLength = msg->readInt16() - 8;
+ if (msgLength <= 0)
+ {
+ return;
+ }
+ int id = msg->readInt32();
+ Being *being = beingManager->findBeing(id);
+ std::string chatMsg = msg->readString(msgLength);
+ mParty->receiveChat(being, chatMsg);
+ }
+ break;
+ }
+}
diff --git a/src/net/partyhandler.h b/src/net/partyhandler.h
new file mode 100644
index 00000000..08d85ad0
--- /dev/null
+++ b/src/net/partyhandler.h
@@ -0,0 +1,39 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PARTYHANDLER_H
+#define PARTYHANDLER_H
+
+#include "messagehandler.h"
+
+class Party;
+
+class PartyHandler : public MessageHandler
+{
+ public:
+ PartyHandler(Party *party);
+
+ void handleMessage(MessageIn *msg);
+ private:
+ Party *mParty;
+};
+
+#endif
diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp
index 5d989a66..d06f1108 100644
--- a/src/net/playerhandler.cpp
+++ b/src/net/playerhandler.cpp
@@ -19,16 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "playerhandler.h"
-
#include "messagein.h"
+#include "playerhandler.h"
#include "protocol.h"
#include "../engine.h"
#include "../localplayer.h"
#include "../log.h"
#include "../npc.h"
-#include "../utils/tostring.h"
#include "../gui/buy.h"
#include "../gui/chat.h"
@@ -40,6 +38,9 @@
#include "../gui/skill.h"
#include "../gui/viewport.h"
+#include "../utils/tostring.h"
+#include "../utils/gettext.h"
+
// TODO Move somewhere else
OkDialog *weightNotice = NULL;
OkDialog *deathNotice = NULL;
@@ -51,7 +52,7 @@ extern SellDialog *sellDialog;
extern Window *buySellDialog;
static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; /* Max. distance we are willing to scroll after a teleport;
- ** everything beyond will reset the port hard. */
+ * everything beyond will reset the port hard. */
/**
* Listener used for handling the overweigth message.
@@ -110,10 +111,11 @@ void PlayerHandler::handleMessage(MessageIn *msg)
switch (msg->getId())
{
case SMSG_WALK_RESPONSE:
- // It is assumed by the client any request to walk actually
- // succeeds on the server. The plan is to have a correction
- // message when the server senses the client has the wrong
- // idea.
+ /*
+ * This client assumes that all walk messages succeed,
+ * and that the server will send a correction notice
+ * otherwise.
+ */
break;
case SMSG_PLAYER_WARP:
@@ -132,6 +134,7 @@ void PlayerHandler::handleMessage(MessageIn *msg)
player_node->stopAttack();
nearby = (engine->getCurrentMapName() == mapPath);
+
// Switch the actual map, deleting the previous one if necessary
engine->changeMap(mapPath);
@@ -143,7 +146,8 @@ void PlayerHandler::handleMessage(MessageIn *msg)
/* Scroll if neccessary */
if (!nearby
|| (abs(x - player_node->mX) > MAP_TELEPORT_SCROLL_DISTANCE)
- || (abs(y - player_node->mY) > MAP_TELEPORT_SCROLL_DISTANCE)) {
+ || (abs(y - player_node->mY) > MAP_TELEPORT_SCROLL_DISTANCE))
+ {
scrollOffsetX = (x - player_node->mX) * 32;
scrollOffsetY = (y - player_node->mY) * 32;
}
@@ -173,6 +177,9 @@ void PlayerHandler::handleMessage(MessageIn *msg)
case 0x0006: player_node->mMaxHp = value; break;
case 0x0007: player_node->mMp = value; break;
case 0x0008: player_node->mMaxMp = value; break;
+ case 0x0009:
+ player_node->mStatsPointsToAttribute = value;
+ break;
case 0x000b: player_node->mLevel = value; break;
case 0x000c:
player_node->mSkillPoint = value;
@@ -183,20 +190,16 @@ void PlayerHandler::handleMessage(MessageIn *msg)
player_node->mTotalWeight <
player_node->mMaxWeight / 2)
{
- weightNotice = new OkDialog("Message",
- "You are carrying more then half "
- "your weight. You are unable to "
- "regain health.");
+ weightNotice = new OkDialog(_("Message"),
+ _("You are carrying more then half "
+ "your weight. You are unable to "
+ "regain health."));
weightNotice->addActionListener(
&weightListener);
}
player_node->mTotalWeight = value;
break;
case 0x0019: player_node->mMaxWeight = value; break;
- case 0x0037: player_node->mJobLevel = value; break;
- case 0x0009:
- player_node->mStatsPointsToAttribute = value;
- break;
case 0x0029: player_node->ATK = value; break;
case 0x002b: player_node->MATK = value; break;
case 0x002d: player_node->DEF = value; break;
@@ -205,12 +208,44 @@ void PlayerHandler::handleMessage(MessageIn *msg)
case 0x0031: player_node->HIT = value; break;
case 0x0032: player_node->FLEE = value; break;
case 0x0035: player_node->mAttackSpeed = value; break;
+ case 0x0037: player_node->mJobLevel = value; break;
}
if (player_node->mHp == 0 && deathNotice == NULL)
{
- deathNotice = new OkDialog("Message",
- "You're now dead, press ok to restart");
+ static char const *const deadMsg[] =
+ {
+ _("You are dead."),
+ _("We regret to inform you that your character was killed in battle."),
+ _("You are not that alive anymore."),
+ _("The cold hands of the grim reaper are grabbing for your soul."),
+ _("Game Over!"),
+ _("Insert coin to continue"),
+ _("No, kids. Your character did not really die. It... err... went to a better place."),
+ _("Your plan of breaking your enemies weapon by bashing it with your throat failed."),
+ _("I guess this did not run too well."),
+ _("Do you want your possessions identified?"), // Nethack reference
+ _("Sadly, no trace of you was ever found..."), // Secret of Mana reference
+ _("Annihilated."), // Final Fantasy VI reference
+ _("Looks like you got your head handed to you."), //Earthbound reference
+ _("You screwed up again, dump your body down the tubes and get you another one."), // Leisure Suit Larry 1 Reference
+ _("You're not dead yet. You're just resting."), // Monty Python reference from a couple of skits
+ _("You are no more."), // Monty Python reference from the dead parrot sketch starting now
+ _("You have ceased to be."),
+ _("You've expired and gone to meet your maker."),
+ _("You're a stiff."),
+ _("Bereft of life, you rest in peace."),
+ _("If you weren't so animated, you'd be pushing up the daisies."),
+ _("Your metabolic processes are now history."),
+ _("You're off the twig."),
+ _("You've kicked the bucket."),
+ _("You've shuffled off your mortal coil, run down the curtain and joined the bleedin' choir invisibile."),
+ _("You are an ex-player."),
+ _("You're pining for the fjords.") // Monty Python reference from the dead parrot sketch
+ };
+ std::string message(deadMsg[rand()%27]);
+
+ deathNotice = new OkDialog(_("Message"), message);
deathNotice->addActionListener(&deathListener);
player_node->setAction(Being::DEAD);
}
@@ -229,7 +264,7 @@ void PlayerHandler::handleMessage(MessageIn *msg)
Uint32 curGp = player_node->mGp;
player_node->mGp = msg->readInt32();
if (player_node->mGp > curGp)
- chatWindow->chatLog("You picked up " +
+ chatWindow->chatLog(_("You picked up ") +
toString(player_node->mGp - curGp) + " GP",
BY_SERVER);
}
@@ -293,7 +328,7 @@ void PlayerHandler::handleMessage(MessageIn *msg)
}
break;
- // Updates stats and status points
+ // Updates stats and status points
case SMSG_PLAYER_STAT_UPDATE_5:
player_node->mStatsPointsToAttribute = msg->readInt16();
player_node->mAttr[LocalPlayer::STR] = msg->readInt8();
@@ -352,27 +387,14 @@ void PlayerHandler::handleMessage(MessageIn *msg)
switch (type) {
case 0:
- chatWindow->chatLog("Equip arrows first",
+ chatWindow->chatLog(_("Equip arrows first"),
BY_SERVER);
break;
default:
- logger->log("0x013b: Unhandled message %i", type);
+ logger->log(_("0x013b: Unhandled message %i"), type);
break;
}
}
break;
-
- //Stop walking
- //case 0x0088: // Disabled because giving some problems
- //if (being = beingManager->findBeing(readInt32(2))) {
- // if (being->getId() != player_node->getId()) {
- // being->action = STAND;
- // being->mFrame = 0;
- // set_coordinates(being->coordinates,
- // readWord(6), readWord(8),
- // get_direction(being->coordinates));
- // }
- //}
- //break;
}
}
diff --git a/src/net/protocol.h b/src/net/protocol.h
index b70834c6..fd08c45d 100644
--- a/src/net/protocol.h
+++ b/src/net/protocol.h
@@ -22,8 +22,11 @@
#ifndef PROTOCOL_
#define PROTOCOL_
-// Packets from server to client
+/*********************************
+ * Packets from server to client *
+ *********************************/
#define SMSG_LOGIN_SUCCESS 0x0073 /**< Contains starting location */
+#define SMSG_SERVER_PING 0x007f /**< Contains server tick */
#define SMSG_UPDATE_HOST 0x0063 /**< Custom update host packet */
#define SMSG_PLAYER_UPDATE_1 0x01d8
#define SMSG_PLAYER_UPDATE_2 0x01d9
@@ -66,6 +69,7 @@
#define SMSG_BEING_ACTION 0x008a /**< Attack, sit, stand up, ... */
#define SMSG_BEING_CHAT 0x008d /**< A being talks */
#define SMSG_BEING_NAME_RESPONSE 0x0095 /**< Has to be requested */
+
#define SMSG_NPC_MESSAGE 0x00b4
#define SMSG_NPC_NEXT 0x00b5
#define SMSG_NPC_CLOSE 0x00b6
@@ -82,6 +86,7 @@
#define SMSG_WHISPER_RESPONSE 0x0098
#define SMSG_GM_CHAT 0x009a /**< GM announce */
#define SMSG_WALK_RESPONSE 0x0087
+
#define SMSG_TRADE_REQUEST 0x00e5 /**< Receiving a request to trade */
#define SMSG_TRADE_RESPONSE 0x00e7
#define SMSG_TRADE_ITEM_ADD 0x00e9
@@ -90,7 +95,27 @@
#define SMSG_TRADE_CANCEL 0x00ee
#define SMSG_TRADE_COMPLETE 0x00f0
-// Packets from client to server
+#define SMSG_PARTY_CREATE 0x00fa
+#define SMSG_PARTY_INFO 0x00fb
+#define SMSG_PARTY_INVITE 0x00fd
+#define SMSG_PARTY_INVITED 0x00fe
+#define SMSG_PARTY_SETTINGS 0x0102
+#define SMSG_PARTY_MEMBER_INFO 0x0104
+#define SMSG_PARTY_LEAVE 0x0105
+#define SMSG_PARTY_UPDATE_HP 0x0106
+#define SMSG_PARTY_UPDATE_COORDS 0x0107
+#define SMSG_PARTY_MESSAGE 0x0109
+
+#define SMSG_PLAYER_STORAGE_ITEMS 0x01f0 /**< Item list for storage */
+#define SMSG_PLAYER_STORAGE_EQUIP 0x00a6 /**< Equipment list for storage */
+#define SMSG_PLAYER_STORAGE_STATUS 0x00f2 /**< Slots used and total slots */
+#define SMSG_PLAYER_STORAGE_ADD 0x00f4 /**< Add item/equip to storage */
+#define SMSG_PLAYER_STORAGE_REMOVE 0x00f6 /**< Remove item/equip from storage */
+#define SMSG_PLAYER_STORAGE_CLOSE 0x00f8 /**< Storage access closed */
+
+/**********************************
+ * Packets from client to server *
+ **********************************/
#define CMSG_CLIENT_PING 0x007e /**< Send to server with tick */
#define CMSG_TRADE_RESPONSE 0x00e6
#define CMSG_ITEM_PICKUP 0x009f
@@ -99,6 +124,8 @@
#define CMSG_NPC_BUY_SELL_REQUEST 0x00c5
#define CMSG_CHAT_MESSAGE 0x008c
#define CMSG_CHAT_WHISPER 0x0096
+#define CMSG_CHAT_ANNOUNCE 0x0099
+#define CMSG_CHAT_WHO 0x00c1
#define CMSG_NPC_LIST_CHOICE 0x00b8
#define CMSG_NPC_NEXT_REQUEST 0x00b9
#define CMSG_NPC_SELL_REQUEST 0x00c9
@@ -117,6 +144,17 @@
#define CMSG_PLAYER_EQUIP 0x00a9
#define CMSG_PLAYER_UNEQUIP 0x00ab
+#define CMSG_PARTY_CREATE 0x00f9
+#define CMSG_PARTY_INVITE 0x00fc
+#define CMSG_PARTY_INVITED 0x00ff
+#define CMSG_PARTY_LEAVE 0x0100 /** Undocumented */
+#define CMSG_PARTY_SETTINGS 0x0101
+#define CMSG_PARTY_MESSAGE 0x0108
+
+#define CMSG_MOVE_TO_STORAGE 0x00f3 /** Move item to storage */
+#define CSMG_MOVE_FROM_STORAGE 0x00f5 /** Remove item from storage */
+#define CMSG_CLOSE_STORAGE 0x00f7 /** Request storage close */
+
/** Encodes coords and direction in 3 bytes data */
void set_coordinates(char *data, unsigned short x, unsigned short y, unsigned char direction);
diff --git a/src/net/skillhandler.cpp b/src/net/skillhandler.cpp
index 17b1f117..e2185524 100644
--- a/src/net/skillhandler.cpp
+++ b/src/net/skillhandler.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "skillhandler.h"
-
#include "messagein.h"
#include "protocol.h"
+#include "skillhandler.h"
#include "../log.h"
diff --git a/src/net/tradehandler.cpp b/src/net/tradehandler.cpp
index da493302..0c7c9205 100644
--- a/src/net/tradehandler.cpp
+++ b/src/net/tradehandler.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "tradehandler.h"
-
#include "messagein.h"
#include "protocol.h"
+#include "tradehandler.h"
#include "../inventory.h"
#include "../item.h"
@@ -33,6 +32,8 @@
#include "../gui/confirm_dialog.h"
#include "../gui/trade.h"
+#include "../utils/gettext.h"
+
std::string tradePartnerName;
/**
@@ -87,9 +88,9 @@ void TradeHandler::handleMessage(MessageIn *msg)
player_node->setTrading(true);
ConfirmDialog *dlg;
- dlg = new ConfirmDialog("Request for trade",
+ dlg = new ConfirmDialog(_("Request for trade"),
tradePartnerName +
- " wants to trade with you, do you accept?");
+ _(" wants to trade with you, do you accept?"));
dlg->addActionListener(&listener);
}
else
@@ -103,37 +104,35 @@ void TradeHandler::handleMessage(MessageIn *msg)
switch (msg->readInt8())
{
case 0: // Too far away
- chatWindow->chatLog("Trading isn't possible. "
- "Trade partner is too far away.",
+ chatWindow->chatLog(_("Trading isn't possible. Trade partner is too far away."),
BY_SERVER);
break;
case 1: // Character doesn't exist
- chatWindow->chatLog("Trading isn't possible. "
- "Character doesn't exist.",
+ chatWindow->chatLog(_("Trading isn't possible. Character doesn't exist."),
BY_SERVER);
break;
case 2: // Invite request check failed...
- chatWindow->chatLog("Trade cancelled due to an "
- "unknown reason.", BY_SERVER);
+ chatWindow->chatLog(_("Trade cancelled due to an unknown reason."),
+ BY_SERVER);
break;
case 3: // Trade accepted
tradeWindow->reset();
tradeWindow->setCaption(
- "Trade: You and " + tradePartnerName);
+ _("Trade: You and ") + tradePartnerName);
tradeWindow->setVisible(true);
break;
case 4: // Trade cancelled
if (player_relations.hasPermission(tradePartnerName,
PlayerRelation::SPEECH_LOG))
- chatWindow->chatLog("Trade with " + tradePartnerName +
- " cancelled", BY_SERVER);
+ chatWindow->chatLog(_("Trade with ") + tradePartnerName +
+ _(" cancelled"), BY_SERVER);
// otherwise ignore silently
tradeWindow->setVisible(false);
player_node->setTrading(false);
break;
default: // Shouldn't happen as well, but to be sure
- chatWindow->chatLog("Unhandled trade cancel packet",
+ chatWindow->chatLog(_("Unhandled trade cancel packet"),
BY_SERVER);
break;
}
@@ -183,19 +182,17 @@ void TradeHandler::handleMessage(MessageIn *msg)
break;
case 1:
// Add item failed - player overweighted
- chatWindow->chatLog("Failed adding item. Trade "
- "partner is over weighted.",
+ chatWindow->chatLog(_("Failed adding item. Trade partner is over weighted."),
BY_SERVER);
break;
case 2:
- // Add item failed - player has no free slot
- chatWindow->chatLog("Failed adding item. Trade "
- "partner has no free slot.",
- BY_SERVER);
- break;
+ // Add item failed - player has no free slot
+ chatWindow->chatLog(_("Failed adding item. Trade partner has no free slot."),
+ BY_SERVER);
+ break;
default:
- chatWindow->chatLog("Failed adding item for "
- "unknown reason.", BY_SERVER);
+ chatWindow->chatLog(_("Failed adding item for unknown reason."),
+ BY_SERVER);
break;
}
}
@@ -207,14 +204,14 @@ void TradeHandler::handleMessage(MessageIn *msg)
break;
case SMSG_TRADE_CANCEL:
- chatWindow->chatLog("Trade canceled.", BY_SERVER);
+ chatWindow->chatLog(_("Trade canceled."), BY_SERVER);
tradeWindow->setVisible(false);
tradeWindow->reset();
player_node->setTrading(false);
break;
case SMSG_TRADE_COMPLETE:
- chatWindow->chatLog("Trade completed.", BY_SERVER);
+ chatWindow->chatLog(_("Trade completed."), BY_SERVER);
tradeWindow->setVisible(false);
tradeWindow->reset();
player_node->setTrading(false);
diff --git a/src/npc.cpp b/src/npc.cpp
index aed6d87b..19be4c4d 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -19,15 +19,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npc.h"
-
#include "animatedsprite.h"
#include "graphics.h"
+#include "localplayer.h"
+#include "npc.h"
#include "particle.h"
#include "text.h"
#include "net/messageout.h"
#include "net/protocol.h"
+
#include "resources/npcdb.h"
NPC *current_npc = 0;
@@ -36,7 +37,7 @@ static const int NAME_X_OFFSET = 15;
static const int NAME_Y_OFFSET = 30;
NPC::NPC(Uint32 id, Uint16 job, Map *map, Network *network):
- Being(id, job, map), mNetwork(network)
+ Player(id, job, map), mNetwork(network)
{
NPCInfo info = NPCDB::get(job);
@@ -54,28 +55,53 @@ NPC::NPC(Uint32 id, Uint16 job, Map *map, Network *network):
c++;
}
- // Setup particle effects
- for (std::list<std::string>::const_iterator i = info.particles.begin();
- i != info.particles.end();
- i++)
+ if (mParticleEffects)
{
- Particle *p = particleEngine->addEffect(*i, 0, 0);
- this->controlParticle(p);
+ //setup particle effects
+ for (std::list<std::string>::const_iterator i = info.particles.begin();
+ i != info.particles.end();
+ i++)
+ {
+ Particle *p = particleEngine->addEffect(*i, 0, 0);
+ this->controlParticle(p);
+ }
}
mName = 0;
+
+ mNameColor = 0x21bbbb;
}
NPC::~NPC()
{
- delete mName;
+ if (mName)
+ {
+ delete mName;
+ player_node->setTarget(NULL);
+ }
}
void NPC::setName(const std::string &name)
{
- delete mName;
- mName = new Text(name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
- gcn::Graphics::CENTER,
- gcn::Color(200, 200, 255));
+ if (mName)
+ {
+ delete mName;
+ }
+ std::string displayName = name.substr(0, name.find('#', 0));
+
+ mName = new Text(displayName, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
+ gcn::Graphics::CENTER, gcn::Color(200, 200, 255));
+ Being::setName(displayName + " (NPC)");
+}
+
+void NPC::setGender(Gender gender)
+{
+ Being::setGender(gender);
+}
+
+void NPC::setSprite(int slot, int id, std::string color)
+{
+ // Fix this later should it not be adequate enough.
+ Being::setSprite(slot, id, color);
}
Being::Type NPC::getType() const
diff --git a/src/npc.h b/src/npc.h
index 7c3baf6d..dd8d7f5d 100644
--- a/src/npc.h
+++ b/src/npc.h
@@ -22,13 +22,13 @@
#ifndef NPC_H
#define NPC_H
-#include "being.h"
+#include "player.h"
class Network;
class Graphics;
class Text;
-class NPC : public Being
+class NPC : public Player
{
public:
NPC(Uint32 id, Uint16 job, Map *map, Network *network);
@@ -36,9 +36,10 @@ class NPC : public Being
~NPC();
void setName(const std::string &name);
+ void setGender(Gender gender);
+ void setSprite(int slot, int id, std::string color);
- virtual Type
- getType() const;
+ virtual Type getType() const;
void talk();
void nextDialog();
diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp
index 01208c36..d3278c1a 100644
--- a/src/openglgraphics.cpp
+++ b/src/openglgraphics.cpp
@@ -19,30 +19,28 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "main.h"
-
-#ifdef USE_OPENGL
+#include <cstring>
+#include <SDL.h>
-#ifndef GL_TEXTURE_RECTANGLE_ARB
-#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
-#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
-#endif
+#include <guichan/exception.hpp>
+#include <guichan/image.hpp>
+#include "log.h"
+#include "main.h"
#include "openglgraphics.h"
-#include <cstring>
-#include <SDL.h>
+#include "resources/image.h"
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif
-#include <guichan/exception.hpp>
-#include <guichan/image.hpp>
-
-#include "log.h"
+#ifdef USE_OPENGL
-#include "resources/image.h"
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif
OpenGLGraphics::OpenGLGraphics():
mAlpha(false), mTexture(false), mColorAlpha(false),
diff --git a/src/particle.cpp b/src/particle.cpp
index 99a4dd36..a3026994 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -22,13 +22,12 @@
#include <algorithm>
#include <cmath>
-#include "particle.h"
-
#include "animationparticle.h"
#include "configuration.h"
#include "imageparticle.h"
#include "log.h"
#include "map.h"
+#include "particle.h"
#include "particleemitter.h"
#include "textparticle.h"
@@ -251,7 +250,7 @@ void Particle::moveTo(float x, float y)
}
Particle *Particle::addEffect(const std::string &particleEffectFile,
- int pixelX, int pixelY)
+ int pixelX, int pixelY, int rotation)
{
Particle *newParticle = NULL;
@@ -313,7 +312,7 @@ Particle *Particle::addEffect(const std::string &particleEffectFile,
continue;
ParticleEmitter *newEmitter;
- newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap);
+ newEmitter = new ParticleEmitter(emitterNode, newParticle, mMap, rotation);
newParticle->addEmitter(newEmitter);
}
diff --git a/src/particle.h b/src/particle.h
index 43fdda01..653e848f 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -102,7 +102,7 @@ class Particle : public Sprite
* particleEffectFile.
*/
Particle *addEffect(const std::string &particleEffectFile,
- int pixelX, int pixelY);
+ int pixelX, int pixelY, int rotation = 0);
/**
* Creates a standalone text particle.
diff --git a/src/particlecontainer.cpp b/src/particlecontainer.cpp
index c570d6d3..6300350d 100644
--- a/src/particlecontainer.cpp
+++ b/src/particlecontainer.cpp
@@ -44,7 +44,6 @@ void ParticleContainer::clear()
mNext->clear();
}
-
void ParticleContainer::moveTo(float x, float y)
{
if (mNext)
diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp
index 076bd740..ca9f7bf5 100644
--- a/src/particleemitter.cpp
+++ b/src/particleemitter.cpp
@@ -19,24 +19,23 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "particleemitter.h"
-
#include "animationparticle.h"
#include "imageparticle.h"
#include "log.h"
#include "particle.h"
+#include "particleemitter.h"
#include "resources/animation.h"
#include "resources/image.h"
-#include "resources/resourcemanager.h"
#include "resources/imageset.h"
+#include "resources/resourcemanager.h"
#include <cmath>
#define SIN45 0.707106781f
#define DEG_RAD_FACTOR 0.017453293f
-ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map):
+ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map, int rotation):
mOutputPauseLeft(0),
mParticleImage(0)
{
@@ -102,7 +101,9 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
else if (name == "horizontal-angle")
{
mParticleAngleHorizontal = readParticleEmitterProp(propertyNode, 0.0f);
+ mParticleAngleHorizontal.minVal += rotation;
mParticleAngleHorizontal.minVal *= DEG_RAD_FACTOR;
+ mParticleAngleHorizontal.maxVal += rotation;
mParticleAngleHorizontal.maxVal *= DEG_RAD_FACTOR;
mParticleAngleHorizontal.changeAmplitude *= DEG_RAD_FACTOR;
}
@@ -310,26 +311,25 @@ ParticleEmitter::readParticleEmitterProp(xmlNodePtr propertyNode, T def)
retval.set((T) XML::getFloatProperty(propertyNode, "min", (double) def),
(T) XML::getFloatProperty(propertyNode, "max", (double) def));
- std::string change = XML::getProperty(propertyNode, "change-func", "none");
- T amplitude = (T) XML::getFloatProperty(propertyNode, "change-amplitude", 0.0);
- int period = XML::getProperty(propertyNode, "change-period", 0);
- int phase = XML::getProperty(propertyNode, "change-phase", 0);
- if (change == "saw" || change == "sawtooth") {
- retval.setFunction(FUNC_SAW, amplitude, period, phase);
- } else if (change == "sine" || change == "sinewave") {
- retval.setFunction(FUNC_SINE, amplitude, period, phase);
- } else if (change == "triangle") {
- retval.setFunction(FUNC_TRIANGLE, amplitude, period, phase);
- } else if (change == "square"){
- retval.setFunction(FUNC_SQUARE, amplitude, period, phase);
- }
+ std::string change = XML::getProperty(propertyNode, "change-func", "none");
+ T amplitude = (T) XML::getFloatProperty(propertyNode, "change-amplitude", 0.0);
+ int period = XML::getProperty(propertyNode, "change-period", 0);
+ int phase = XML::getProperty(propertyNode, "change-phase", 0);
+ if (change == "saw" || change == "sawtooth") {
+ retval.setFunction(FUNC_SAW, amplitude, period, phase);
+ } else if (change == "sine" || change == "sinewave") {
+ retval.setFunction(FUNC_SINE, amplitude, period, phase);
+ } else if (change == "triangle") {
+ retval.setFunction(FUNC_TRIANGLE, amplitude, period, phase);
+ } else if (change == "square"){
+ retval.setFunction(FUNC_SQUARE, amplitude, period, phase);
+ }
return retval;
}
-std::list<Particle *>
-ParticleEmitter::createParticles(int tick)
+std::list<Particle *> ParticleEmitter::createParticles(int tick)
{
std::list<Particle *> newParticles;
diff --git a/src/particleemitter.h b/src/particleemitter.h
index 593ecb3a..cc77f215 100644
--- a/src/particleemitter.h
+++ b/src/particleemitter.h
@@ -44,7 +44,7 @@ class ParticleEmitter
/**
* Constructor.
*/
- ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map);
+ ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map, int rotation = 0);
/**
* Copy Constructor (necessary for reference counting of particle images)
@@ -70,8 +70,7 @@ class ParticleEmitter
/**
* Sets the target of the particles that are created
*/
- void
- setTarget(Particle *target)
+ void setTarget(Particle *target)
{ mParticleTarget = target; };
private:
diff --git a/src/particleemitterprop.h b/src/particleemitterprop.h
index d9b6350f..fde78f8f 100644
--- a/src/particleemitterprop.h
+++ b/src/particleemitterprop.h
@@ -19,8 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <cstdlib>
#include <cmath>
+#include <cstdlib>
/**
* Returns a random numeric value that is larger than or equal min and smaller
diff --git a/src/party.cpp b/src/party.cpp
new file mode 100644
index 00000000..ecb0ab2d
--- /dev/null
+++ b/src/party.cpp
@@ -0,0 +1,221 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "beingmanager.h"
+#include "game.h"
+#include "localplayer.h"
+#include "party.h"
+
+#include "gui/chat.h"
+#include "gui/confirm_dialog.h"
+
+#include "net/messageout.h"
+#include "net/protocol.h"
+
+#include "utils/gettext.h"
+#include "utils/strprintf.h"
+
+Party::Party(ChatWindow *chat, Network *network) :
+ mChat(chat), mNetwork(network), mInviteListener(network, &mInParty)
+{
+}
+
+void Party::respond(const std::string &command, const std::string &args)
+{
+ if (command == "new" || command == "create")
+ {
+ create(args);
+ return;
+ }
+ if (command == "leave")
+ {
+ leave(args);
+ return;
+ }
+ if (command == "settings")
+ {
+ mChat->chatLog(_("Not yet implemented!"), BY_SERVER);
+ return;
+ /*
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_PARTY_SETTINGS);
+ outMsg.writeInt16(0); // Experience
+ outMsg.writeInt16(0); // Item
+ */
+ }
+ mChat->chatLog(_("Party command not known."), BY_SERVER);
+}
+
+void Party::create(const std::string &party)
+{
+ if (party == "")
+ {
+ mChat->chatLog(_("Party name is missing."), BY_SERVER);
+ return;
+ }
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_PARTY_CREATE);
+ outMsg.writeString(party.substr(0, 23), 24);
+ mCreating = true;
+}
+
+void Party::leave(const std::string &args)
+{
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_PARTY_LEAVE);
+ mChat->chatLog(_("Left party."), BY_SERVER);
+ mInParty = false;
+}
+
+void Party::createResponse(bool ok)
+{
+ if (ok)
+ {
+ mChat->chatLog(_("Party successfully created."), BY_SERVER);
+ mInParty = true;
+ }
+ else
+ {
+ mChat->chatLog(_("Could not create party."), BY_SERVER);
+ }
+}
+
+void Party::inviteResponse(const std::string &nick, int status)
+{
+ switch (status)
+ {
+ case 0:
+ mChat->chatLog(strprintf(_("%s is already a member of a party."),
+ nick.c_str()), BY_SERVER);
+ break;
+ case 1:
+ mChat->chatLog(strprintf(_("%s refused your invitation."),
+ nick.c_str()), BY_SERVER);
+ break;
+ case 2:
+ mChat->chatLog(strprintf(_("%s is now a member of your party."),
+ nick.c_str()), BY_SERVER);
+ break;
+ }
+}
+
+void Party::invitedAsk(const std::string &nick, int gender,
+ const std::string &partyName)
+{
+ mPartyName = partyName; /* Quick and nasty - needs redoing */
+ if (nick == "")
+ {
+ mChat->chatLog(_("You can\'t have a blank party name!"), BY_SERVER);
+ return;
+ }
+ mCreating = false;
+ ConfirmDialog *dlg = new ConfirmDialog(_("Invite to party"),
+ strprintf(_("%s invites you to join"
+ " the %s party, do you accept?"),
+ nick.c_str(), partyName.c_str()));
+ dlg->addActionListener(&mInviteListener);
+}
+
+void Party::InviteListener::action(const gcn::ActionEvent &event)
+{
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_PARTY_INVITED);
+ outMsg.writeInt32(player_node->getId());
+ bool accept = event.getId() == "yes";
+ outMsg.writeInt32(accept ? 1 : 0);
+ *mInParty = *mInParty || accept;
+}
+
+void Party::leftResponse(const std::string &nick)
+{
+ mChat->chatLog(strprintf(_("%s has left your party."), nick.c_str()),
+ BY_SERVER);
+}
+
+void Party::receiveChat(Being *being, const std::string &msg)
+{
+ if (being == NULL)
+ {
+ return;
+ }
+ if (being->getType() != Being::PLAYER)
+ {
+ mChat->chatLog(_("Party chat received, but being is not a player"),
+ BY_SERVER);
+ return;
+ }
+ being->setSpeech(msg, SPEECH_TIME);
+ mChat->chatLog(being->getName() + " : " + msg, BY_PARTY);
+}
+
+void Party::help()
+{
+ mChat->chatLog(_("/party <command> <params>: Party commands."), BY_SERVER);
+}
+
+void Party::help(const std::string &msg)
+{
+ if (msg == "")
+ {
+ mChat->chatLog(_("Command: /party <command> <args>"), BY_SERVER);
+ mChat->chatLog(_("where <command> can be one of:"), BY_SERVER);
+ mChat->chatLog(_(" /new"), BY_SERVER);
+ mChat->chatLog(_(" /create"), BY_SERVER);
+ mChat->chatLog(_(" /prefix"), BY_SERVER);
+ mChat->chatLog(_(" /leave"), BY_SERVER);
+ mChat->chatLog(_("This command implements the partying function."),
+ BY_SERVER);
+ mChat->chatLog(_("Type /help party <command> for further help."),
+ BY_SERVER);
+ return;
+ }
+ if (msg == "new" || msg == "create")
+ {
+ mChat->chatLog(_("Command: /party new <party-name>"), BY_SERVER);
+ mChat->chatLog(_("Command: /party create <party-name>"), BY_SERVER);
+ mChat->chatLog(_("These commands create a new party <party-name."),
+ BY_SERVER);
+ return;
+ }
+ if (msg == "prefix")
+ {
+ mChat->chatLog(_("Command: /party prefix <prefix-char>"), BY_SERVER);
+ mChat->chatLog(_("This command sets the party prefix character."),
+ BY_SERVER);
+ mChat->chatLog(_("Any message preceded by <prefix-char> is sent to "
+ "the party instead of everyone."), BY_SERVER);
+ mChat->chatLog(_("Command: /party prefix"), BY_SERVER);
+ mChat->chatLog(_("This command reports the current party prefix "
+ "character."), BY_SERVER);
+ return;
+ }
+ //if (msg == "settings")
+ //if (msg == "info")
+ if (msg == "leave")
+ {
+ mChat->chatLog(_("Command: /party leave"), BY_SERVER);
+ mChat->chatLog(_("This command causes the player to leave the party."),
+ BY_SERVER);
+ return;
+ }
+ mChat->chatLog(_("Unknown /party command."), BY_SERVER);
+ mChat->chatLog(_("Type /help party for a list of options."), BY_SERVER);
+}
diff --git a/src/party.h b/src/party.h
new file mode 100644
index 00000000..8d6dce47
--- /dev/null
+++ b/src/party.h
@@ -0,0 +1,73 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PARTY_H
+#define PARTY_H
+
+#include <string>
+
+#include <guichan/actionlistener.hpp>
+
+class PartyHandler;
+class Being;
+class ChatWindow;
+class Network;
+
+class Party
+{
+ public:
+ Party(ChatWindow *chat, Network *network);
+ void respond(const std::string &command, const std::string &args);
+
+ void create(const std::string &party);
+ void leave(const std::string &args);
+
+ void createResponse(bool ok);
+ void inviteResponse(const std::string &nick, int status);
+ void invitedAsk(const std::string &nick, int gender,
+ const std::string &partyName);
+ void leftResponse(const std::string &nick);
+ void receiveChat(Being *being, const std::string &msg);
+
+ void help();
+ void help(const std::string &msg);
+ private:
+ ChatWindow *mChat;
+ std::string mPartyName;
+ Network *mNetwork;
+ bool mInParty;
+ bool mCreating; /**< Used to give an appropriate response to
+ failure */
+ PartyHandler *handler;
+
+ class InviteListener : public gcn::ActionListener
+ {
+ public:
+ InviteListener(Network *network, bool *inParty) :
+ mNetwork(network), mInParty(inParty) {};
+ void action(const gcn::ActionEvent &event);
+ Network *mNetwork;
+ private:
+ bool *mInParty;
+ };
+ InviteListener mInviteListener;
+};
+#endif
diff --git a/src/player.cpp b/src/player.cpp
index 5ab94595..ca8c9f14 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -19,20 +19,19 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "player.h"
+#include <iostream>
#include "animatedsprite.h"
#include "game.h"
#include "graphics.h"
#include "log.h"
+#include "player.h"
#include "resources/itemdb.h"
#include "resources/iteminfo.h"
#include "utils/strprintf.h"
-#include <iostream>
-
static const int NAME_X_OFFSET = 15;
static const int NAME_Y_OFFSET = 30;
@@ -44,19 +43,25 @@ Player::Player(int id, int job, Map *map):
Player::~Player()
{
- if (mName)
- {
- delete mName;
- }
+ delete mName;
}
void Player::setName(const std::string &name)
{
if (mName == 0)
{
- mName = new FlashText(name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
- gcn::Graphics::CENTER,
- gcn::Color(255, 255, 255));
+ if (mIsGM)
+ {
+ mNameColor = 0x009000;
+ mName = new FlashText("(GM) " + name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
+ gcn::Graphics::CENTER, gcn::Color(0, 255, 0));
+ }
+ else
+ {
+ mNameColor = 0x202020;
+ mName = new FlashText(name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
+ gcn::Graphics::CENTER, gcn::Color(255, 255, 255));
+ }
Being::setName(name);
}
}
@@ -64,6 +69,18 @@ void Player::setName(const std::string &name)
void Player::logic()
{
switch (mAction) {
+ case STAND:
+ break;
+
+ case SIT:
+ break;
+
+ case DEAD:
+ break;
+
+ case HURT:
+ break;
+
case WALK:
mFrame = (get_elapsed_time(mWalkTime) * 6) / mWalkSpeed;
if (mFrame >= 6) {
@@ -126,13 +143,13 @@ void Player::setGender(Gender gender)
void Player::setHairStyle(int style, int color)
{
- style = style < 0 ? mHairStyle : style % getHairStylesNr();
- color = color < 0 ? mHairColor : color % getHairColorsNr();
+ style = style < 0 ? mHairStyle : style % mNumberOfHairstyles;
+ color = color < 0 ? mHairColor : color % ColorDB::size();
if (style == mHairStyle && color == mHairColor) return;
Being::setHairStyle(style, color);
- setSprite(HAIR_SPRITE, style * -1, getHairColor(color));
+ setSprite(HAIR_SPRITE, style * -1, ColorDB::get(color));
setAction(mAction);
}
@@ -187,4 +204,3 @@ void Player::updateCoords()
}
}
-
diff --git a/src/player.h b/src/player.h
index 7fe2a09c..5fe9963a 100644
--- a/src/player.h
+++ b/src/player.h
@@ -43,17 +43,13 @@ class Player : public Being
/**
* Set up mName to be the character's name
*/
- virtual void
- setName(const std::string &name);
+ virtual void setName(const std::string &name);
- virtual void
- logic();
+ virtual void logic();
- virtual Type
- getType() const;
+ virtual Type getType() const;
- virtual void
- setGender(Gender gender);
+ virtual void setGender(Gender gender);
/**
* Sets the hair style and color for this player.
@@ -70,8 +66,7 @@ class Player : public Being
/**
* Sets visible equipments for this player.
*/
- virtual void
- setSprite(int slot, int id, std::string color = "");
+ virtual void setSprite(int slot, int id, std::string color = "");
/**
* Flash the player's name
@@ -79,9 +74,8 @@ class Player : public Being
void flash(int time);
protected:
- void updateCoords();
+ virtual void updateCoords();
- private:
FlashText *mName;
};
diff --git a/src/player_relations.cpp b/src/player_relations.cpp
index 09859c59..057eea94 100644
--- a/src/player_relations.cpp
+++ b/src/player_relations.cpp
@@ -19,12 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <algorithm>
+
#include "beingmanager.h"
-#include "player_relations.h"
#include "graphics.h"
-#include "gui/gui.h"
+#include "player_relations.h"
-#include <algorithm>
+#include "gui/gui.h"
#define PLAYER_IGNORE_STRATEGY_NOP "nop"
#define PLAYER_IGNORE_STRATEGY_EMOTE0 "emote0"
@@ -90,8 +91,7 @@ PlayerRelationsManager::PlayerRelationsManager() :
{
}
-void
-PlayerRelationsManager::clear()
+void PlayerRelationsManager::clear()
{
std::vector<std::string> *names = getPlayers();
for (std::vector<std::string>::const_iterator
@@ -104,8 +104,7 @@ PlayerRelationsManager::clear()
#define PLAYER_IGNORE_STRATEGY "player-ignore-strategy"
#define DEFAULT_PERMISSIONS "default-player-permissions"
-int
-PlayerRelationsManager::getPlayerIgnoreStrategyIndex(const std::string &name)
+int PlayerRelationsManager::getPlayerIgnoreStrategyIndex(const std::string &name)
{
std::vector<PlayerIgnoreStrategy *> *strategies = getPlayerIgnoreStrategies();
for (unsigned int i = 0; i < strategies->size(); i++)
@@ -115,8 +114,7 @@ PlayerRelationsManager::getPlayerIgnoreStrategyIndex(const std::string &name)
return -1;
}
-void
-PlayerRelationsManager::load()
+void PlayerRelationsManager::load()
{
clear();
@@ -133,8 +131,7 @@ PlayerRelationsManager::load()
}
-void
-PlayerRelationsManager::init()
+void PlayerRelationsManager::init()
{
load();
@@ -142,8 +139,7 @@ PlayerRelationsManager::init()
clear(); // Yes, we still keep them around in the config file until the next update.
}
-void
-PlayerRelationsManager::store()
+void PlayerRelationsManager::store()
{
config.setList<std::map<std::string, PlayerRelation *>::const_iterator,
std::pair<std::string, PlayerRelation *>,
@@ -160,8 +156,7 @@ PlayerRelationsManager::store()
config.write();
}
-void
-PlayerRelationsManager::signalUpdate(const std::string &name)
+void PlayerRelationsManager::signalUpdate(const std::string &name)
{
store();
@@ -169,8 +164,7 @@ PlayerRelationsManager::signalUpdate(const std::string &name)
(*it)->updatedPlayer(name);
}
-unsigned int
-PlayerRelationsManager::checkPermissionSilently(const std::string &player_name, unsigned int flags)
+unsigned int PlayerRelationsManager::checkPermissionSilently(const std::string &player_name, unsigned int flags)
{
PlayerRelation *r = mRelations[player_name];
if (!r)
@@ -195,16 +189,14 @@ PlayerRelationsManager::checkPermissionSilently(const std::string &player_name,
}
}
-bool
-PlayerRelationsManager::hasPermission(Being *being, unsigned int flags)
+bool PlayerRelationsManager::hasPermission(Being *being, unsigned int flags)
{
if (being->getType() == Being::PLAYER)
return hasPermission(being->getName(), flags) == flags;
return true;
}
-bool
-PlayerRelationsManager::hasPermission(const std::string &name, unsigned int flags)
+bool PlayerRelationsManager::hasPermission(const std::string &name, unsigned int flags)
{
unsigned int rejections = flags & ~checkPermissionSilently(name, flags);
bool permitted = rejections == 0;
@@ -223,8 +215,7 @@ PlayerRelationsManager::hasPermission(const std::string &name, unsigned int flag
return permitted;
}
-void
-PlayerRelationsManager::setRelation(const std::string &player_name, PlayerRelation::relation relation)
+void PlayerRelationsManager::setRelation(const std::string &player_name, PlayerRelation::relation relation)
{
PlayerRelation *r = mRelations[player_name];
if (r == NULL)
@@ -235,8 +226,7 @@ PlayerRelationsManager::setRelation(const std::string &player_name, PlayerRelati
signalUpdate(player_name);
}
-std::vector<std::string> *
-PlayerRelationsManager::getPlayers()
+std::vector<std::string> * PlayerRelationsManager::getPlayers()
{
std::vector<std::string> *retval = new std::vector<std::string>();
@@ -249,8 +239,7 @@ PlayerRelationsManager::getPlayers()
return retval;
}
-void
-PlayerRelationsManager::removePlayer(const std::string &name)
+void PlayerRelationsManager::removePlayer(const std::string &name)
{
if (mRelations[name])
delete mRelations[name];
@@ -261,8 +250,7 @@ PlayerRelationsManager::removePlayer(const std::string &name)
}
-PlayerRelation::relation
-PlayerRelationsManager::getRelation(const std::string &name)
+PlayerRelation::relation PlayerRelationsManager::getRelation(const std::string &name)
{
if (mRelations[name])
return mRelations[name]->mRelation;
@@ -273,14 +261,12 @@ PlayerRelationsManager::getRelation(const std::string &name)
////////////////////////////////////////
// defaults
-unsigned int
-PlayerRelationsManager::getDefault() const
+unsigned int PlayerRelationsManager::getDefault() const
{
return mDefaultPermissions;
}
-void
-PlayerRelationsManager::setDefault(unsigned int permissions)
+void PlayerRelationsManager::setDefault(unsigned int permissions)
{
mDefaultPermissions = permissions;
@@ -302,8 +288,7 @@ public:
mShortName = PLAYER_IGNORE_STRATEGY_NOP;
}
- virtual void
- ignore(Player *player, unsigned int flags)
+ virtual void ignore(Player *player, unsigned int flags)
{
}
};
@@ -317,8 +302,7 @@ public:
mShortName = "dotdotdot";
}
- virtual void
- ignore(Player *player, unsigned int flags)
+ virtual void ignore(Player *player, unsigned int flags)
{
player->setSpeech("...", 5);
}
@@ -334,8 +318,7 @@ public:
mShortName = "blinkname";
}
- virtual void
- ignore(Player *player, unsigned int flags)
+ virtual void ignore(Player *player, unsigned int flags)
{
player->flash(200);
}
@@ -351,8 +334,7 @@ public:
mShortName = shortname;
}
- virtual void
- ignore(Player *player, unsigned int flags)
+ virtual void ignore(Player *player, unsigned int flags)
{
player->setEmote(mEmotion, IGNORE_EMOTE_TIME);
}
diff --git a/src/player_relations.h b/src/player_relations.h
index 6cbaf6b3..0f8bb4e3 100644
--- a/src/player_relations.h
+++ b/src/player_relations.h
@@ -22,13 +22,14 @@
#ifndef PLAYER_RELATIONS_H
#define PLAYER_RELATIONS_H
-#include "being.h"
-#include "player.h"
-#include "configuration.h"
-#include <string>
+#include <list>
#include <map>
+#include <string>
#include <vector>
-#include <list>
+
+#include "being.h"
+#include "configuration.h"
+#include "player.h"
struct PlayerRelation
{
diff --git a/src/properties.h b/src/properties.h
index 016d607a..a2ce5b88 100644
--- a/src/properties.h
+++ b/src/properties.h
@@ -23,8 +23,8 @@
#define PROPERTIES_H
#include <map>
-#include <string>
#include <sstream>
+#include <string>
/**
* A class holding a set of properties.
diff --git a/src/recorder.cpp b/src/recorder.cpp
new file mode 100644
index 00000000..07d9a771
--- /dev/null
+++ b/src/recorder.cpp
@@ -0,0 +1,114 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <physfs.h>
+
+#include "recorder.h"
+
+#include "gui/buttonbox.h"
+#include "gui/chat.h"
+
+#include "utils/trim.h"
+
+Recorder::Recorder(ChatWindow *chat) : mChat(chat)
+{
+ mButtonBox = new ButtonBox("Recording...", "Stop recording", this);
+ mButtonBox->setY(20);
+}
+
+void Recorder::record(const std::string &msg)
+{
+ if (mStream.is_open())
+ {
+ mStream << msg << std::endl;
+ }
+}
+
+void Recorder::respond(const std::string &msg)
+{
+ std::string msgCopy = msg;
+ trim(msgCopy);
+ if (msgCopy == "")
+ {
+ if (mStream.is_open())
+ {
+ mStream.close();
+ mButtonBox->setVisible(false);
+ /*
+ * Message should go after mStream is closed so that it isn't
+ * recorded.
+ */
+ mChat->chatLog("Finishing recording.", BY_SERVER);
+ }
+ else
+ {
+ mChat->chatLog("Not currently recording.", BY_SERVER);
+ }
+ return;
+ }
+ if (mStream.is_open())
+ {
+ mChat->chatLog("Already recording.", BY_SERVER);
+ }
+ else
+ {
+ /*
+ * Message should go before mStream is opened so that it isn't
+ * recorded.
+ */
+ mChat->chatLog("Starting to record...", BY_SERVER);
+ std::string file = std::string(PHYSFS_getUserDir()) + "/.tmw/" + msgCopy;
+
+ mStream.open(file.c_str(), std::ios_base::trunc);
+ if (mStream.is_open())
+ {
+ mButtonBox->setVisible(true);
+ }
+ else
+ {
+ mChat->chatLog("Failed to start recording.", BY_SERVER);
+ }
+ }
+}
+
+void Recorder::help() const
+{
+ mChat->chatLog("/record <filename>: Start recording the chat.", BY_SERVER);
+}
+
+void Recorder::help(const std::string &args) const
+{
+ mChat->chatLog("Command: /record <filename>", BY_SERVER);
+ mChat->chatLog("This command starts recording the chat log to the file "
+ "<filename>.", BY_SERVER);
+ mChat->chatLog("Command: /record", BY_SERVER);
+ mChat->chatLog("This command finishes a recording session.", BY_SERVER);
+}
+
+void Recorder::buttonBoxRespond()
+{
+ respond("");
+}
+
+Recorder::~Recorder()
+{
+ delete mButtonBox;
+}
diff --git a/src/recorder.h b/src/recorder.h
new file mode 100644
index 00000000..4a220166
--- /dev/null
+++ b/src/recorder.h
@@ -0,0 +1,48 @@
+/*
+ * Aethyra
+ * Copyright (C) 2008 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef RECORD_H
+#define RECORD_H
+
+#include <fstream>
+#include <string>
+
+#include "gui/buttonbox.h"
+
+class ChatWindow;
+
+class Recorder : public ButtonBoxListener
+{
+ private:
+ ChatWindow *mChat;
+ std::ofstream mStream;
+ ButtonBox *mButtonBox;
+ public:
+ Recorder(ChatWindow *chat);
+ void record(const std::string &msg);
+ void respond(const std::string &msg);
+ void help() const;
+ void help(const std::string &args) const;
+ void buttonBoxRespond();
+ bool isRecording() {return (bool) mStream.is_open();}
+ virtual ~Recorder();
+};
+#endif
diff --git a/src/resources/action.cpp b/src/resources/action.cpp
index 3fd3237e..e2cb11f2 100644
--- a/src/resources/action.cpp
+++ b/src/resources/action.cpp
@@ -20,12 +20,10 @@
*/
#include "action.h"
-
#include "animation.h"
#include "../utils/dtor.h"
-
Action::Action()
{
}
diff --git a/src/resources/action.h b/src/resources/action.h
index c557e6da..649d3828 100644
--- a/src/resources/action.h
+++ b/src/resources/action.h
@@ -44,11 +44,9 @@ class Action
*/
~Action();
- void
- setAnimation(int direction, Animation *animation);
+ void setAnimation(int direction, Animation *animation);
- Animation*
- getAnimation(int direction) const;
+ Animation* getAnimation(int direction) const;
protected:
typedef std::map<int, Animation*> Animations;
diff --git a/src/resources/ambientoverlay.cpp b/src/resources/ambientoverlay.cpp
index ef034acf..32ed47d1 100644
--- a/src/resources/ambientoverlay.cpp
+++ b/src/resources/ambientoverlay.cpp
@@ -20,7 +20,6 @@
*/
#include "ambientoverlay.h"
-
#include "image.h"
#include "../graphics.h"
diff --git a/src/resources/animation.cpp b/src/resources/animation.cpp
index 62e5ac16..8d7156a9 100644
--- a/src/resources/animation.cpp
+++ b/src/resources/animation.cpp
@@ -19,10 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "animation.h"
-
#include <algorithm>
+#include "animation.h"
+
#include "../utils/dtor.h"
Animation::Animation():
@@ -30,22 +30,19 @@ Animation::Animation():
{
}
-void
-Animation::addFrame(Image *image, unsigned int delay, int offsetX, int offsetY)
+void Animation::addFrame(Image *image, unsigned int delay, int offsetX, int offsetY)
{
Frame frame = { image, delay, offsetX, offsetY };
mFrames.push_back(frame);
mDuration += delay;
}
-void
-Animation::addTerminator()
+void Animation::addTerminator()
{
addFrame(NULL, 0, 0, 0);
}
-bool
-Animation::isTerminator(const Frame &candidate)
+bool Animation::isTerminator(const Frame &candidate)
{
return (candidate.image == NULL);
}
diff --git a/src/resources/animation.h b/src/resources/animation.h
index 29c99209..0c461ebe 100644
--- a/src/resources/animation.h
+++ b/src/resources/animation.h
@@ -54,39 +54,33 @@ class Animation
/**
* Appends a new animation at the end of the sequence.
*/
- void
- addFrame(Image *image, unsigned int delay, int offsetX, int offsetY);
+ void addFrame(Image *image, unsigned int delay, int offsetX, int offsetY);
/**
* Appends an animation terminator that states that the animation
* should not loop.
*/
- void
- addTerminator();
+ void addTerminator();
/**
* Returns the frame at the specified index.
*/
- Frame*
- getFrame(int index) { return &(mFrames[index]); }
+ Frame* getFrame(int index) { return &(mFrames[index]); }
/**
* Returns the length of this animation in frames.
*/
- unsigned int
- getLength() const { return mFrames.size(); }
+ unsigned int getLength() const { return mFrames.size(); }
/**
* Returns the duration of this animation.
*/
- int
- getDuration() const { return mDuration; }
+ int getDuration() const { return mDuration; }
/**
* Determines whether the given animation frame is a terminator.
*/
- static bool
- isTerminator(const Frame &phase);
+ static bool isTerminator(const Frame &phase);
protected:
std::vector<Frame> mFrames;
diff --git a/src/resources/buddylist.cpp b/src/resources/buddylist.cpp
index 24198f59..541acabe 100644
--- a/src/resources/buddylist.cpp
+++ b/src/resources/buddylist.cpp
@@ -21,13 +21,13 @@
#include <algorithm>
#include <cstring>
-#include <iostream>
#include <fstream>
+#include <iostream>
#include "buddylist.h"
-#include "../main.h"
#include "../configuration.h"
+#include "../main.h"
BuddyList::BuddyList()
{
@@ -111,7 +111,7 @@ bool BuddyList::removeBuddy(const std::string buddy)
return false;
}
-int BuddyList::getNumberOfElements()
+int BuddyList::getNumberOfElements()
{
return mBuddylist.size();
}
diff --git a/src/resources/buddylist.h b/src/resources/buddylist.h
index 33fcde4d..d769b2b8 100644
--- a/src/resources/buddylist.h
+++ b/src/resources/buddylist.h
@@ -52,7 +52,7 @@ class BuddyList : public gcn::ListModel {
/**
* Returns the number of buddy on the list
*/
- int getNumberOfElements();
+ int getNumberOfElements();
/**
* Returns the buddy of the number or null
diff --git a/src/resources/colordb.cpp b/src/resources/colordb.cpp
new file mode 100644
index 00000000..f80ca6b3
--- /dev/null
+++ b/src/resources/colordb.cpp
@@ -0,0 +1,125 @@
+/*
+ * Aethyra
+ * Copyright 2008 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <cassert>
+#include <libxml/tree.h>
+
+#include "colordb.h"
+
+#include "../log.h"
+
+#include "../utils/dtor.h"
+#include "../utils/gettext.h"
+#include "../utils/xml.h"
+
+#define HAIR_COLOR_FILE "colors.xml"
+#define TMW_COLOR_FILE "hair.xml"
+
+namespace
+{
+ ColorDB::Colors mColors;
+ bool mLoaded = false;
+ std::string mFail = "#ffffff";
+}
+
+void ColorDB::load()
+{
+ if (mLoaded)
+ {
+ return;
+ }
+
+ XML::Document *doc = new XML::Document(HAIR_COLOR_FILE);
+ xmlNodePtr root = doc->rootNode();
+ bool TMWHair = false;
+
+ if (!root || !xmlStrEqual(root->name, BAD_CAST "colors"))
+ {
+ logger->log(_("Trying TMW's color file, %s."), TMW_COLOR_FILE);
+
+ TMWHair = true;
+
+ delete doc;
+
+ doc = new XML::Document(TMW_COLOR_FILE);
+ root = doc->rootNode();
+ if (!root || !xmlStrEqual(root->name, BAD_CAST "colors"))
+ {
+ logger->log(_("ColorDB: Failed"));
+ mColors[0] = mFail;
+ mLoaded = true;
+
+ delete doc;
+
+ return;
+ }
+ }
+ for_each_xml_child_node(node, root)
+ {
+ if (xmlStrEqual(node->name, BAD_CAST "color"))
+ {
+ int id = XML::getProperty(node, "id", 0);
+
+ if (mColors.find(id) != mColors.end())
+ {
+ logger->log(_("ColorDB: Redefinition of dye ID %d"), id);
+ }
+
+ TMWHair ? mColors[id] = XML::getProperty(node, "value", "#FFFFFF") :
+ mColors[id] = XML::getProperty(node, "dye", "#FFFFFF");
+ }
+ }
+
+ delete doc;
+
+ mLoaded = true;
+}
+
+void ColorDB::unload()
+{
+ logger->log(_("Unloading color database..."));
+
+ mColors.clear();
+ mLoaded = false;
+}
+
+std::string& ColorDB::get(int id)
+{
+ if(!mLoaded)
+ load();
+
+ ColorIterator i = mColors.find(id);
+
+ if (i == mColors.end())
+ {
+ logger->log(_("ColorDB: Error, unknown dye ID# %d"), id);
+ return mFail;
+ }
+ else
+ {
+ return i->second;
+ }
+}
+
+int ColorDB::size()
+{
+ return mColors.size();
+}
diff --git a/src/resources/colordb.h b/src/resources/colordb.h
new file mode 100644
index 00000000..65b7f759
--- /dev/null
+++ b/src/resources/colordb.h
@@ -0,0 +1,52 @@
+/*
+ * Aethyra
+ * Copyright 2008 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef COLOR_MANAGER_H
+#define COLOR_MANAGER_H
+
+#include <map>
+#include <string>
+
+/**
+ * The class that holds the color information.
+ */
+namespace ColorDB
+{
+ /**
+ * Loads the color data from <code>colors.xml</code>.
+ */
+ void load();
+
+ /**
+ * Clear the color data
+ */
+ void unload();
+
+ std::string& get(int id);
+
+ int size();
+
+ // Color DB
+ typedef std::map<int, std::string> Colors;
+ typedef Colors::iterator ColorIterator;
+}
+
+#endif
diff --git a/src/resources/dye.h b/src/resources/dye.h
index d32c3f22..3cef334a 100644
--- a/src/resources/dye.h
+++ b/src/resources/dye.h
@@ -22,6 +22,7 @@
#ifndef DYE_H
#define DYE_H
+#include <string>
#include <vector>
/**
@@ -36,7 +37,7 @@ class Palette
* The string is either a file name or a sequence of hexadecimal RGB
* values separated by ',' and starting with '#'.
*/
- Palette(const std::string &);
+ Palette(const std::string &pallete);
/**
* Gets a pixel color depending on its intensity.
@@ -63,7 +64,7 @@ class Dye
* The parts of string are separated by semi-colons. Each part starts
* by an uppercase letter, followed by a colon and then a palette name.
*/
- Dye(const std::string &);
+ Dye(const std::string &dye);
/**
* Destroys the associated palettes.
diff --git a/src/resources/emotedb.cpp b/src/resources/emotedb.cpp
new file mode 100644
index 00000000..2f43822d
--- /dev/null
+++ b/src/resources/emotedb.cpp
@@ -0,0 +1,143 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "emotedb.h"
+#include "resourcemanager.h"
+
+#include "../log.h"
+
+#include "../utils/dtor.h"
+#include "../utils/gettext.h"
+#include "../utils/xml.h"
+
+namespace
+{
+ EmoteInfos mEmoteInfos;
+ EmoteInfo mUnknown;
+ bool mLoaded = false;
+ int mLastEmote = 0;
+}
+
+void EmoteDB::load()
+{
+ if (mLoaded)
+ return;
+
+ mLastEmote = 0;
+
+ EmoteSprite *unknownSprite = new EmoteSprite;
+ unknownSprite->sprite = "error.xml";
+ unknownSprite->name = "unknown";
+ unknownSprite->variant = 0;
+ mUnknown.sprites.push_back(unknownSprite);
+
+ logger->log(_("Initializing emote database..."));
+
+ XML::Document doc("emotes.xml");
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "emotes"))
+ {
+ logger->log(_("Emote Database: Error while loading emotes.xml!"));
+ return;
+ }
+
+ //iterate <emote>s
+ for_each_xml_child_node(emoteNode, rootNode)
+ {
+ if (!xmlStrEqual(emoteNode->name, BAD_CAST "emote"))
+ continue;
+
+ int id = XML::getProperty(emoteNode, "id", -1);
+ if (id == -1)
+ {
+ logger->log(_("Emote Database: Emote with missing ID in emotes.xml!"));
+ continue;
+ }
+
+ EmoteInfo *currentInfo = new EmoteInfo;
+
+ for_each_xml_child_node(spriteNode, emoteNode)
+ {
+ if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
+ {
+ EmoteSprite *currentSprite = new EmoteSprite;
+ currentSprite->sprite = (const char*) spriteNode->xmlChildrenNode->content;
+ currentSprite->variant = XML::getProperty(spriteNode, "variant", 0);
+ currentInfo->sprites.push_back(currentSprite);
+ }
+ else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
+ {
+ std::string particlefx = (const char*) spriteNode->xmlChildrenNode->content;
+ currentInfo->particles.push_back(particlefx);
+ }
+ }
+ mEmoteInfos[id] = currentInfo;
+ if (id > mLastEmote) mLastEmote = id;
+ }
+
+ mLoaded = true;
+}
+
+void EmoteDB::unload()
+{
+ for ( EmoteInfosIterator i = mEmoteInfos.begin();
+ i != mEmoteInfos.end();
+ i++)
+ {
+ while (!i->second->sprites.empty())
+ {
+ delete i->second->sprites.front();
+ i->second->sprites.pop_front();
+ }
+ delete i->second;
+ }
+
+ mEmoteInfos.clear();
+
+ while (!mUnknown.sprites.empty())
+ {
+ delete mUnknown.sprites.front();
+ mUnknown.sprites.pop_front();
+ }
+
+ mLoaded = false;
+}
+
+const EmoteInfo& EmoteDB::get(int id)
+{
+ EmoteInfosIterator i = mEmoteInfos.find(id);
+
+ if (i == mEmoteInfos.end())
+ {
+ logger->log(_("EmoteDB: Warning, unknown emote ID %d requested"), id);
+ return mUnknown;
+ }
+ else
+ {
+ return *(i->second);
+ }
+}
+
+const int& EmoteDB::getLast()
+{
+ return mLastEmote;
+}
diff --git a/src/resources/emotedb.h b/src/resources/emotedb.h
new file mode 100644
index 00000000..0962edad
--- /dev/null
+++ b/src/resources/emotedb.h
@@ -0,0 +1,60 @@
+/*
+ * Aethyra
+ * Copyright 2009 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EMOTE_DB_H
+#define EMOTE_DB_H
+
+#include <list>
+#include <map>
+#include <string>
+
+struct EmoteSprite
+{
+ std::string sprite;
+ std::string name;
+ int variant;
+};
+
+struct EmoteInfo
+{
+ std::list<EmoteSprite*> sprites;
+ std::list<std::string> particles;
+};
+
+typedef std::map<int, EmoteInfo*> EmoteInfos;
+
+/**
+ * Emote information database.
+ */
+namespace EmoteDB
+{
+ void load();
+
+ void unload();
+
+ const EmoteInfo& get(int id);
+
+ const int& getLast();
+
+ typedef EmoteInfos::iterator EmoteInfosIterator;
+}
+
+#endif
diff --git a/src/resources/image.cpp b/src/resources/image.cpp
index cc986c81..c3310849 100644
--- a/src/resources/image.cpp
+++ b/src/resources/image.cpp
@@ -21,9 +21,8 @@
#include <SDL_image.h>
-#include "image.h"
-
#include "dye.h"
+#include "image.h"
#include "../log.h"
diff --git a/src/resources/image.h b/src/resources/image.h
index 963fbb24..a4048803 100644
--- a/src/resources/image.h
+++ b/src/resources/image.h
@@ -22,9 +22,10 @@
#ifndef IMAGE_H
#define IMAGE_H
+#include <SDL.h>
+
#include "../main.h"
-#include <SDL.h>
#ifdef USE_OPENGL
/* The definition of OpenGL extensions by SDL is giving problems with recent
@@ -96,7 +97,6 @@ class Image : public Resource
virtual int getWidth() const
{ return mBounds.w; }
-
/**
* Returns the height of the image.
*/
@@ -129,7 +129,6 @@ class Image : public Resource
static void setLoadAsOpenGL(bool useOpenGL);
#endif
-
protected:
/**
* Constructor.
diff --git a/src/resources/imageloader.cpp b/src/resources/imageloader.cpp
index 5aad7c52..7895d33d 100644
--- a/src/resources/imageloader.cpp
+++ b/src/resources/imageloader.cpp
@@ -21,12 +21,12 @@
#include <cassert>
#include <string>
+
#include <guichan/color.hpp>
#include <guichan/sdl/sdlpixel.hpp>
-#include "imageloader.h"
-
#include "image.h"
+#include "imageloader.h"
#include "resourcemanager.h"
ProxyImage::ProxyImage(SDL_Surface *s):
diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp
index 458b0405..92bb3242 100644
--- a/src/resources/imageset.cpp
+++ b/src/resources/imageset.cpp
@@ -19,12 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "image.h"
#include "imageset.h"
#include "../log.h"
-#include "image.h"
-
#include "../utils/dtor.h"
ImageSet::ImageSet(Image *img, int width, int height)
@@ -45,8 +44,7 @@ ImageSet::~ImageSet()
delete_all(mImages);
}
-Image*
-ImageSet::get(size_type i) const
+Image* ImageSet::get(size_type i) const
{
if (i >= mImages.size())
{
diff --git a/src/resources/imageset.h b/src/resources/imageset.h
index 00a36754..f59c76bb 100644
--- a/src/resources/imageset.h
+++ b/src/resources/imageset.h
@@ -28,7 +28,6 @@
class Image;
-
/**
* Stores a set of subimages originating from a single image.
*/
diff --git a/src/resources/imagewriter.cpp b/src/resources/imagewriter.cpp
index d6bb4659..c350ac07 100644
--- a/src/resources/imagewriter.cpp
+++ b/src/resources/imagewriter.cpp
@@ -19,11 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "imagewriter.h"
-
#include <png.h>
-#include <string>
#include <SDL.h>
+#include <string>
+
+#include "imagewriter.h"
#include "../log.h"
diff --git a/src/resources/imagewriter.h b/src/resources/imagewriter.h
index 8eb6cead..a9133846 100644
--- a/src/resources/imagewriter.h
+++ b/src/resources/imagewriter.h
@@ -27,5 +27,5 @@ class ImageWriter
{
public:
static bool writePNG(SDL_Surface *surface,
- const std::string &filename);
+ const std::string &filename);
};
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 1678eda8..773febd7 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -20,10 +20,10 @@
*/
#include <cassert>
+
#include <libxml/tree.h>
#include "itemdb.h"
-
#include "iteminfo.h"
#include "resourcemanager.h"
@@ -36,6 +36,7 @@
namespace
{
ItemDB::ItemInfos mItemInfos;
+ ItemDB::NamedItemInfos mNamedItemInfos;
ItemInfo *mUnknown;
bool mLoaded = false;
}
@@ -49,20 +50,20 @@ void ItemDB::load()
if (mLoaded)
return;
- logger->log("Initializing item database...");
+ logger->log(_("Initializing item database..."));
mUnknown = new ItemInfo();
- mUnknown->setName("Unknown item");
+ mUnknown->setName(_("Unknown item"));
mUnknown->setImageName("");
mUnknown->setSprite("error.xml", GENDER_MALE);
mUnknown->setSprite("error.xml", GENDER_FEMALE);
- XML::Document doc("items.xml");
+ XML::Document doc(_("items.xml"));
xmlNodePtr rootNode = doc.rootNode();
if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "items"))
{
- logger->error("ItemDB: Error while loading items.xml!");
+ logger->error(_("ItemDB: Error while loading items.xml!"));
}
for_each_xml_child_node(node, rootNode)
@@ -74,12 +75,12 @@ void ItemDB::load()
if (id == 0)
{
- logger->log("ItemDB: Invalid or missing item ID in items.xml!");
+ logger->log(_("ItemDB: Invalid or missing item ID in items.xml!"));
continue;
}
else if (mItemInfos.find(id) != mItemInfos.end())
{
- logger->log("ItemDB: Redefinition of item ID %d", id);
+ logger->log(_("ItemDB: Redefinition of item ID %d"), id);
}
int type = XML::getProperty(node, "type", 0);
@@ -95,6 +96,7 @@ void ItemDB::load()
if (id)
{
ItemInfo *itemInfo = new ItemInfo;
+ itemInfo->setId(id);
itemInfo->setImageName(image);
itemInfo->setName(name.empty() ? _("Unnamed") : name);
itemInfo->setDescription(description);
@@ -117,6 +119,34 @@ void ItemDB::load()
}
mItemInfos[id] = itemInfo;
+ if (!name.empty())
+ {
+ NamedItemInfoIterator itr = mNamedItemInfos.find(name);
+ if (itr == mNamedItemInfos.end())
+ {
+ std::string temp = name;
+ while (temp[0] == ' ')
+ {
+ temp = temp.substr(1, temp.size());
+ }
+ while (temp[temp.size()] == ' ')
+ {
+ temp = temp.substr(0, temp.size() - 1);
+ }
+
+ for (unsigned int i = 0; i < temp.size(); i++)
+ {
+ temp[i] = (char) tolower(temp[i]);
+ }
+
+ mNamedItemInfos[temp] = itemInfo;
+ }
+ else
+ {
+ logger->log(_("ItemDB: Duplicate name of item found item %d"),
+ id);
+ }
+ }
}
#define CHECK_PARAM(param, error_value) \
@@ -126,9 +156,9 @@ void ItemDB::load()
CHECK_PARAM(name, "");
CHECK_PARAM(image, "");
CHECK_PARAM(description, "");
- CHECK_PARAM(effect, "");
+ // CHECK_PARAM(effect, "");
// CHECK_PARAM(type, 0);
- // CHECK_PARAM(weight, 0);
+ CHECK_PARAM(weight, 0);
// CHECK_PARAM(slot, 0);
#undef CHECK_PARAM
@@ -139,7 +169,7 @@ void ItemDB::load()
void ItemDB::unload()
{
- logger->log("Unloading item database...");
+ logger->log(_("Unloading item database..."));
delete mUnknown;
mUnknown = NULL;
@@ -157,7 +187,24 @@ const ItemInfo& ItemDB::get(int id)
if (i == mItemInfos.end())
{
- logger->log("ItemDB: Error, unknown item ID# %d", id);
+ logger->log(_("ItemDB: Error, unknown item ID# %d"), id);
+ return *mUnknown;
+ }
+ else
+ {
+ return *(i->second);
+ }
+}
+
+const ItemInfo& ItemDB::get(const std::string &name)
+{
+ assert(mLoaded && !name.empty());
+
+ NamedItemInfoIterator i = mNamedItemInfos.find(name);
+
+ if (i == mNamedItemInfos.end())
+ {
+ logger->log("ItemDB: Error, unknown item name %s", name.c_str());
return *mUnknown;
}
else
@@ -175,7 +222,6 @@ void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node)
{
itemInfo->setSprite(filename, GENDER_MALE);
}
-
if (gender == "female" || gender == "unisex")
{
itemInfo->setSprite(filename, GENDER_FEMALE);
@@ -197,7 +243,7 @@ void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node)
}
else
{
- logger->log("ItemDB: Ignoring unknown sound event '%s'",
+ logger->log(_("ItemDB: Ignoring unknown sound event '%s'"),
event.c_str());
}
}
diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h
index 03fb1eed..e7c23ca2 100644
--- a/src/resources/itemdb.h
+++ b/src/resources/itemdb.h
@@ -22,10 +22,10 @@
#ifndef ITEM_MANAGER_H
#define ITEM_MANAGER_H
-#include "iteminfo.h"
-
#include <map>
+#include "iteminfo.h"
+
/**
* The namespace that holds the item information.
*/
@@ -42,10 +42,13 @@ namespace ItemDB
void unload();
const ItemInfo& get(int id);
+ const ItemInfo& get(const std::string &name);
// Items database
typedef std::map<int, ItemInfo*> ItemInfos;
+ typedef std::map<std::string, ItemInfo*> NamedItemInfos;
typedef ItemInfos::iterator ItemInfoIterator;
+ typedef NamedItemInfos::iterator NamedItemInfoIterator;
}
#endif
diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp
index b924c591..2f118284 100644
--- a/src/resources/iteminfo.cpp
+++ b/src/resources/iteminfo.cpp
@@ -19,12 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "iteminfo.h"
-
#include "itemdb.h"
+#include "iteminfo.h"
-const std::string&
-ItemInfo::getSprite(Gender gender) const
+const std::string& ItemInfo::getSprite(Gender gender) const
{
if (mView)
{
@@ -67,15 +65,12 @@ void ItemInfo::setWeaponType(int type)
}
}
-void
-ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename)
+void ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename)
{
mSounds[event].push_back("sfx/" + filename);
}
-
-const std::string&
-ItemInfo::getSound(EquipmentSoundEvent event) const
+const std::string& ItemInfo::getSound(EquipmentSoundEvent event) const
{
static const std::string empty;
std::map< EquipmentSoundEvent, std::vector<std::string> >::const_iterator i;
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index a04213ff..86725ca2 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -54,6 +54,12 @@ class ItemInfo
{
}
+ void setId(int id)
+ { mId = id; }
+
+ int getId() const
+ { return mId; }
+
void setName(const std::string &name)
{ mName = name; }
@@ -115,6 +121,7 @@ class ItemInfo
char mType; /**< Item type. */
short mWeight; /**< Weight in grams. */
int mView; /**< Item ID of how this item looks. */
+ int mId; /**< Item ID */
// Equipment related members
SpriteAction mAttackType; /**< Attack type, in case of weapon. */
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index 21125c2a..ddf48df0 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -19,14 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "mapreader.h"
-
#include <cassert>
#include <iostream>
#include <zlib.h>
-#include "resourcemanager.h"
#include "image.h"
+#include "mapreader.h"
+#include "resourcemanager.h"
#include "../log.h"
#include "../map.h"
@@ -205,14 +204,11 @@ Map *MapReader::readMap(xmlNodePtr node, const std::string &path)
// Take the filename off the path
const std::string pathDir = path.substr(0, path.rfind("/") + 1);
- //xmlChar *prop = xmlGetProp(node, BAD_CAST "version");
- //xmlFree(prop);
-
const int w = XML::getProperty(node, "width", 0);
const int h = XML::getProperty(node, "height", 0);
- const int tw = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
- const int th = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
- Map *map = new Map(w, h, tw, th);
+ const int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH);
+ const int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT);
+ Map *map = new Map(w, h, tilew, tileh);
for_each_xml_child_node(childNode, node)
{
@@ -236,8 +232,8 @@ Map *MapReader::readMap(xmlNodePtr node, const std::string &path)
// The object group offset is applied to each object individually
const int tileOffsetX = XML::getProperty(childNode, "x", 0);
const int tileOffsetY = XML::getProperty(childNode, "y", 0);
- const int offsetX = tileOffsetX * tw;
- const int offsetY = tileOffsetY * th;
+ const int offsetX = tileOffsetX * tilew;
+ const int offsetY = tileOffsetY * tileh;
for_each_xml_child_node(objectNode, childNode)
{
@@ -326,8 +322,8 @@ void MapReader::readLayer(xmlNodePtr node, Map *map)
const int offsetY = XML::getProperty(node, "y", 0);
const std::string name = XML::getProperty(node, "name", "");
- const bool isFringeLayer = (name == "Fringe");
- const bool isCollisionLayer = (name == "Collision");
+ const bool isFringeLayer = (name.substr(0,6) == "Fringe");
+ const bool isCollisionLayer = (name.substr(0,9) == "Collision");
MapLayer *layer = 0;
@@ -370,7 +366,7 @@ void MapReader::readLayer(xmlNodePtr node, Map *map)
while (*charStart) {
if (*charStart != ' ' && *charStart != '\t' &&
- *charStart != '\n')
+ *charStart != '\n')
{
*charIndex = *charStart;
charIndex++;
@@ -461,15 +457,20 @@ Tileset *MapReader::readTileset(xmlNodePtr node,
const std::string &path,
Map *map)
{
+ int firstGid = XML::getProperty(node, "firstgid", 0);
+ XML::Document* doc = NULL;
Tileset *set = NULL;
if (xmlHasProp(node, BAD_CAST "source"))
{
- logger->log("Warning: External tilesets not supported yet.");
- return set;
+ std::string filename = XML::getProperty(node, "source", "");
+ while (filename.substr(0, 3) == "../")
+ filename.erase(0, 3); // Remove "../"
+ doc = new XML::Document(filename);
+ node = doc->rootNode();
+ firstGid += XML::getProperty(node, "firstgid", 0);
}
- const int firstGid = XML::getProperty(node, "firstgid", 0);
const int tw = XML::getProperty(node, "tilewidth", map->getTileWidth());
const int th = XML::getProperty(node, "tileheight", map->getTileHeight());
@@ -545,5 +546,7 @@ Tileset *MapReader::readTileset(xmlNodePtr node,
}
}
+ delete doc;
+
return set;
}
diff --git a/src/resources/mapreader.h b/src/resources/mapreader.h
index 8cb2749d..ef945c3f 100644
--- a/src/resources/mapreader.h
+++ b/src/resources/mapreader.h
@@ -26,8 +26,8 @@
#include <libxml/tree.h>
-class Properties;
class Map;
+class Properties;
class Tileset;
/**
diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp
index 5d452db2..c7926260 100644
--- a/src/resources/monsterdb.cpp
+++ b/src/resources/monsterdb.cpp
@@ -20,12 +20,12 @@
*/
#include "monsterdb.h"
-
#include "resourcemanager.h"
#include "../log.h"
#include "../utils/dtor.h"
+#include "../utils/gettext.h"
#include "../utils/xml.h"
namespace
@@ -35,23 +35,22 @@ namespace
bool mLoaded = false;
}
-void
-MonsterDB::load()
+void MonsterDB::load()
{
if (mLoaded)
return;
mUnknown.addSprite("error.xml");
- mUnknown.setName("unnamed");
+ mUnknown.setName(_("unnamed"));
- logger->log("Initializing monster database...");
+ logger->log(_("Initializing monster database..."));
- XML::Document doc("monsters.xml");
+ XML::Document doc(_("monsters.xml"));
xmlNodePtr rootNode = doc.rootNode();
if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "monsters"))
{
- logger->error("Monster Database: Error while loading monster.xml!");
+ logger->error(_("Monster Database: Error while loading monster.xml!"));
}
//iterate <monster>s
@@ -82,7 +81,7 @@ MonsterDB::load()
}
else
{
- logger->log("MonsterDB: Unknown target cursor type \"%s\" for %s - using medium sized one",
+ logger->log(_("MonsterDB: Unknown target cursor type \"%s\" for %s - using medium sized one"),
targetCursor.c_str(), currentInfo->getName().c_str());
currentInfo->setTargetCursorSize(Being::TC_MEDIUM);
}
@@ -119,11 +118,17 @@ MonsterDB::load()
}
else
{
- logger->log("MonsterDB: Warning, sound effect %s for unknown event %s of monster %s",
+ logger->log(_("MonsterDB: Warning, sound effect %s for unknown event %s of monster %s"),
filename, event.c_str(), currentInfo->getName().c_str());
}
}
+ if (xmlStrEqual(spriteNode->name, BAD_CAST "attack"))
+ {
+ std::string event = XML::getProperty(spriteNode, "particle-effect", "");
+ currentInfo->addAttackParticleEffect(event);
+ }
+
if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx"))
{
currentInfo->addParticleEffect(
@@ -151,7 +156,7 @@ const MonsterInfo &MonsterDB::get(int id)
if (i == mMonsterInfos.end())
{
- logger->log("MonsterDB: Warning, unknown monster ID %d requested", id);
+ logger->log(_("MonsterDB: Warning, unknown monster ID %d requested"), id);
return mUnknown;
}
else
diff --git a/src/resources/monsterdb.h b/src/resources/monsterdb.h
index 8555670b..6fbde55f 100644
--- a/src/resources/monsterdb.h
+++ b/src/resources/monsterdb.h
@@ -31,11 +31,9 @@
*/
namespace MonsterDB
{
- void
- load();
+ void load();
- void
- unload();
+ void unload();
const MonsterInfo& get(int id);
diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp
index d8ff8be3..503990e7 100644
--- a/src/resources/monsterinfo.cpp
+++ b/src/resources/monsterinfo.cpp
@@ -36,8 +36,7 @@ MonsterInfo::~MonsterInfo()
}
-void
-MonsterInfo::addSound(MonsterSoundEvent event, std::string filename)
+void MonsterInfo::addSound(MonsterSoundEvent event, std::string filename)
{
if (mSounds.find(event) == mSounds.end())
{
@@ -48,8 +47,7 @@ MonsterInfo::addSound(MonsterSoundEvent event, std::string filename)
}
-std::string
-MonsterInfo::getSound(MonsterSoundEvent event) const
+std::string MonsterInfo::getSound(MonsterSoundEvent event) const
{
std::map<MonsterSoundEvent, std::vector<std::string>* >::const_iterator i;
diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h
index b37ac1a9..75464035 100644
--- a/src/resources/monsterinfo.h
+++ b/src/resources/monsterinfo.h
@@ -22,14 +22,13 @@
#ifndef MONSTERINFO_H
#define MONSTERINFO_H
+#include <list>
#include <map>
#include <string>
#include <vector>
-#include <list>
#include "../being.h"
-
enum MonsterSoundEvent
{
MONSTER_EVENT_HIT,
@@ -57,39 +56,39 @@ class MonsterInfo
*/
~MonsterInfo();
- void
- setName(std::string name) { mName = name; }
+ void setName(std::string name) { mName = name; }
- void
- addSprite(std::string filename) { mSprites.push_back(filename); }
+ void addSprite(std::string filename) { mSprites.push_back(filename); }
- void
- setTargetCursorSize(Being::TargetCursorSize targetCursorSize)
+ void setTargetCursorSize(Being::TargetCursorSize targetCursorSize)
{ mTargetCursorSize = targetCursorSize; }
- void
- addSound(MonsterSoundEvent event, std::string filename);
+ void addSound(MonsterSoundEvent event, std::string filename);
+
+ void addParticleEffect(std::string filename);
+
+ const std::string& getName() const
+ { return mName; }
- void
- addParticleEffect(std::string filename);
+ const std::list<std::string>& getSprites() const
+ { return mSprites; }
- const std::string&
- getName() const { return mName; }
+ Being::TargetCursorSize getTargetCursorSize() const
+ { return mTargetCursorSize; }
- const std::list<std::string>&
- getSprites() const { return mSprites; }
+ std::string getSound(MonsterSoundEvent event) const;
- Being::TargetCursorSize
- getTargetCursorSize() const { return mTargetCursorSize; }
+ std::string getAttackParticleEffect() const { return mAttackParticle; }
- std::string
- getSound(MonsterSoundEvent event) const;
+ void addAttackParticleEffect(const std::string &particleEffect)
+ { mAttackParticle = particleEffect; }
- const std::list<std::string>&
- getParticleEffects() const { return mParticleEffects; }
+ const std::list<std::string>& getParticleEffects() const
+ { return mParticleEffects; }
private:
std::string mName;
+ std::string mAttackParticle;
std::list<std::string> mSprites;
Being::TargetCursorSize mTargetCursorSize;
std::map<MonsterSoundEvent, std::vector<std::string>* > mSounds;
diff --git a/src/resources/music.cpp b/src/resources/music.cpp
index 3b81d05b..ed78a541 100644
--- a/src/resources/music.cpp
+++ b/src/resources/music.cpp
@@ -55,8 +55,7 @@ Resource *Music::load(void *buffer, unsigned bufferSize)
}
}
-bool
-Music::play(int loops)
+bool Music::play(int loops)
{
/*
* Warning: loops should be always set to -1 (infinite) with current
@@ -71,8 +70,7 @@ Music::play(int loops)
return mChannel != -1;
}
-void
-Music::stop()
+void Music::stop()
{
/*
* Warning: very dungerous trick, it could try to stop channels occupied
diff --git a/src/resources/music.h b/src/resources/music.h
index cff18338..65f1ee88 100644
--- a/src/resources/music.h
+++ b/src/resources/music.h
@@ -56,14 +56,12 @@ class Music : public Resource
* @return <code>true</code> if the playback started properly
* <code>false</code> otherwise.
*/
- virtual bool
- play(int loops);
+ virtual bool play(int loops);
/**
* Stops the music.
*/
- virtual void
- stop();
+ virtual void stop();
protected:
/**
diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp
index 9faef60d..88572481 100644
--- a/src/resources/npcdb.cpp
+++ b/src/resources/npcdb.cpp
@@ -20,12 +20,12 @@
*/
#include "npcdb.h"
-
#include "resourcemanager.h"
#include "../log.h"
#include "../utils/dtor.h"
+#include "../utils/gettext.h"
#include "../utils/xml.h"
namespace
@@ -45,17 +45,17 @@ void NPCDB::load()
unknownSprite->variant = 0;
mUnknown.sprites.push_back(unknownSprite);
- logger->log("Initializing NPC database...");
+ logger->log(_("Initializing NPC database..."));
XML::Document doc("npcs.xml");
xmlNodePtr rootNode = doc.rootNode();
if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "npcs"))
{
- logger->error("NPC Database: Error while loading items.xml!");
+ logger->error(_("NPC Database: Error while loading npcs.xml!"));
}
- //iterate <monster>s
+ //iterate <npc>s
for_each_xml_child_node(npcNode, rootNode)
{
if (!xmlStrEqual(npcNode->name, BAD_CAST "npc"))
@@ -64,7 +64,7 @@ void NPCDB::load()
int id = XML::getProperty(npcNode, "id", 0);
if (id == 0)
{
- logger->log("NPC Database: NPC with missing ID in npcs.xml!");
+ logger->log(_("NPC Database: NPC with missing ID in npcs.xml!"));
continue;
}
@@ -91,8 +91,7 @@ void NPCDB::load()
mLoaded = true;
}
-void
-NPCDB::unload()
+void NPCDB::unload()
{
for ( NPCInfosIterator i = mNPCInfos.begin();
i != mNPCInfos.end();
@@ -117,14 +116,13 @@ NPCDB::unload()
mLoaded = false;
}
-const NPCInfo&
-NPCDB::get(int id)
+const NPCInfo& NPCDB::get(int id)
{
NPCInfosIterator i = mNPCInfos.find(id);
if (i == mNPCInfos.end())
{
- logger->log("NPCDB: Warning, unknown NPC ID %d requested", id);
+ logger->log(_("NPCDB: Warning, unknown NPC ID %d requested"), id);
return mUnknown;
}
else
diff --git a/src/resources/npcdb.h b/src/resources/npcdb.h
index a7f28c50..af6764bf 100644
--- a/src/resources/npcdb.h
+++ b/src/resources/npcdb.h
@@ -22,8 +22,8 @@
#ifndef NPC_DB_H
#define NPC_DB_H
-#include <map>
#include <list>
+#include <map>
#include <string>
struct NPCsprite
@@ -45,11 +45,9 @@ typedef std::map<int, NPCInfo*> NPCInfos;
*/
namespace NPCDB
{
- void
- load();
+ void load();
- void
- unload();
+ void unload();
const NPCInfo& get(int id);
diff --git a/src/resources/resource.cpp b/src/resources/resource.cpp
index 4c173962..d1c3ada4 100644
--- a/src/resources/resource.cpp
+++ b/src/resources/resource.cpp
@@ -22,21 +22,18 @@
#include <cassert>
#include "resource.h"
-
#include "resourcemanager.h"
Resource::~Resource()
{
}
-void
-Resource::incRef()
+void Resource::incRef()
{
mRefCount++;
}
-void
-Resource::decRef()
+void Resource::decRef()
{
// Reference may not already have reached zero
assert(mRefCount != 0);
diff --git a/src/resources/resource.h b/src/resources/resource.h
index 0dc50c03..303b82c8 100644
--- a/src/resources/resource.h
+++ b/src/resources/resource.h
@@ -41,8 +41,7 @@ class Resource
/**
* Increments the internal reference count.
*/
- void
- incRef();
+ void incRef();
/**
* Decrements the reference count and deletes the object
@@ -51,8 +50,7 @@ class Resource
* @return <code>true</code> if the object was deleted
* <code>false</code> otherwise.
*/
- void
- decRef();
+ void decRef();
/**
* Return the path identifying this resource.
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index febcf0d0..3f58076e 100644
--- a/src/resources/resourcemanager.cpp
+++ b/src/resources/resourcemanager.cpp
@@ -20,24 +20,22 @@
*/
#include <cassert>
-#include <sstream>
-#include <sys/time.h>
-
#include <physfs.h>
#include <SDL_image.h>
+#include <sstream>
-#include "resourcemanager.h"
+#include <sys/time.h>
#include "dye.h"
#include "image.h"
+#include "imageset.h"
#include "music.h"
+#include "resourcemanager.h"
#include "soundeffect.h"
-#include "imageset.h"
#include "spritedef.h"
#include "../log.h"
-
ResourceManager *ResourceManager::instance = NULL;
ResourceManager::ResourceManager()
@@ -155,8 +153,8 @@ bool ResourceManager::addToSearchPath(const std::string &path, bool append)
}
void ResourceManager::searchAndAddArchives(const std::string &path,
- const std::string &ext,
- bool append)
+ const std::string &ext,
+ bool append)
{
const char *dirSep = PHYSFS_getDirSeparator();
char **list = PHYSFS_enumerateFiles(path.c_str());
@@ -420,8 +418,7 @@ void *ResourceManager::loadFile(const std::string &fileName, int &fileSize)
return buffer;
}
-std::vector<std::string>
-ResourceManager::loadTextFile(const std::string &fileName)
+std::vector<std::string> ResourceManager::loadTextFile(const std::string &fileName)
{
int contentsLength;
char *fileContents = (char*)loadFile(fileName, contentsLength);
diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h
index 6a7a2ed6..73f55fd3 100644
--- a/src/resources/resourcemanager.h
+++ b/src/resources/resourcemanager.h
@@ -27,11 +27,11 @@
#include <string>
#include <vector>
-class Resource;
class Image;
+class ImageSet;
class Music;
+class Resource;
class SoundEffect;
-class ImageSet;
class SpriteDef;
struct SDL_Surface;
diff --git a/src/resources/soundeffect.cpp b/src/resources/soundeffect.cpp
index 21488511..3a285730 100644
--- a/src/resources/soundeffect.cpp
+++ b/src/resources/soundeffect.cpp
@@ -47,8 +47,7 @@ Resource *SoundEffect::load(void *buffer, unsigned bufferSize)
}
}
-bool
-SoundEffect::play(int loops, int volume)
+bool SoundEffect::play(int loops, int volume)
{
Mix_VolumeChunk(mChunk, volume);
diff --git a/src/resources/soundeffect.h b/src/resources/soundeffect.h
index 5f511b29..05ec9e54 100644
--- a/src/resources/soundeffect.h
+++ b/src/resources/soundeffect.h
@@ -58,8 +58,7 @@ class SoundEffect : public Resource
* @return <code>true</code> if the playback started properly
* <code>false</code> otherwise.
*/
- virtual bool
- play(int loops, int volume);
+ virtual bool play(int loops, int volume);
protected:
/**
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
index 64ce8b0a..af3281be 100644
--- a/src/resources/spritedef.cpp
+++ b/src/resources/spritedef.cpp
@@ -21,14 +21,13 @@
#include <set>
-#include "spritedef.h"
-
#include "action.h"
#include "animation.h"
#include "dye.h"
#include "image.h"
#include "imageset.h"
#include "resourcemanager.h"
+#include "spritedef.h"
#include "../log.h"
#include "../utils/xml.h"
diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h
index b86a4c4d..b9d7b85d 100644
--- a/src/resources/spritedef.h
+++ b/src/resources/spritedef.h
@@ -25,10 +25,10 @@
#include <map>
#include <string>
-#include "resource.h"
-
#include <libxml/tree.h>
+#include "resource.h"
+
class Action;
class ImageSet;
@@ -89,7 +89,6 @@ class SpriteDef : public Resource
static SpriteDirection
makeSpriteDirection(const std::string &direction);
-
private:
/**
* Constructor.
@@ -140,7 +139,6 @@ class SpriteDef : public Resource
*/
void substituteAction(SpriteAction complete, SpriteAction with);
-
typedef std::map<std::string, ImageSet*> ImageSets;
typedef ImageSets::iterator ImageSetIterator;
diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp
index 8abb4a67..17d9ce60 100644
--- a/src/simpleanimation.cpp
+++ b/src/simpleanimation.cpp
@@ -19,15 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "simpleanimation.h"
-
#include "graphics.h"
#include "log.h"
+#include "simpleanimation.h"
#include "resources/image.h"
-#include "resources/resourcemanager.h"
#include "resources/imageset.h"
-
+#include "resources/resourcemanager.h"
SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode):
mAnimationTime(0),
diff --git a/src/sound.cpp b/src/sound.cpp
index c69dc023..78538c09 100644
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -19,11 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "sound.h"
-
#include <SDL.h>
#include "log.h"
+#include "sound.h"
+
#include "resources/resourcemanager.h"
#include "resources/soundeffect.h"
diff --git a/src/sound.h b/src/sound.h
index 88336572..05b2def3 100644
--- a/src/sound.h
+++ b/src/sound.h
@@ -23,7 +23,6 @@
#define SOUND_H
#include <SDL_mixer.h>
-
#include <string>
/** Sound engine
diff --git a/src/sprite.h b/src/sprite.h
index 624e4e8b..a6384e94 100644
--- a/src/sprite.h
+++ b/src/sprite.h
@@ -44,30 +44,26 @@ class Sprite
* would support setting a translation offset. It already does this
* partly with the clipping rectangle support.
*/
- virtual void
- draw(Graphics *graphics, int offsetX, int offsetY) const = 0;
+ virtual void draw(Graphics *graphics, int offsetX, int offsetY) const = 0;
/**
* Returns the horizontal size of the sprites graphical representation
* in pixels or 0 when it is undefined.
*/
- virtual int
- getWidth() const
+ virtual int getWidth() const
{ return 0; }
/**
* Returns the vertical size of the sprites graphical representation
* in pixels or 0 when it is undefined.
*/
- virtual int
- getHeight() const
+ virtual int getHeight() const
{ return 0; }
/**
* Returns the pixel Y coordinate of the sprite.
*/
- virtual int
- getPixelY() const = 0;
+ virtual int getPixelY() const = 0;
};
#endif
diff --git a/src/text.cpp b/src/text.cpp
index 0e458c9f..e148c117 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -1,5 +1,6 @@
/*
* The Mana World
+ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net>
* Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
@@ -68,8 +69,8 @@ Text::Text(const std::string &text, int x, int y,
sbImage->decRef();
}
++mInstances;
- mHeight = gui->getFont()->getHeight();
- mWidth = gui->getFont()->getWidth(text);
+ mHeight = boldFont->getHeight();
+ mWidth = boldFont->getWidth(text);
switch (alignment)
{
@@ -115,7 +116,7 @@ void Text::adviseXY(int x, int y)
void Text::draw(Graphics *graphics, int xOff, int yOff)
{
- graphics->setFont(gui->getFont());
+ graphics->setFont(boldFont);
if (mIsSpeech) {
static_cast<Graphics*>(graphics)->drawImageRect(
diff --git a/src/text.h b/src/text.h
index a7eae152..8d463223 100644
--- a/src/text.h
+++ b/src/text.h
@@ -1,5 +1,6 @@
/*
* The Mana World
+ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net>
* Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
@@ -23,6 +24,7 @@
#define TEXT_H
#include "graphics.h"
+#include "guichanfwd.h"
#include <list>
@@ -79,6 +81,11 @@ class FlashText : public Text
gcn::Color colour);
/**
+ * Remove the text from the screen
+ */
+ virtual ~FlashText() {}
+
+ /**
* Flash the text for so many refreshes.
*/
void flash(int time) {mTime = time; }
@@ -89,7 +96,7 @@ class FlashText : public Text
virtual void draw(Graphics *graphics, int xOff, int yOff);
private:
- int mTime; /**< Time left for flashing. */
+ int mTime; /**< Time left for flashing */
};
#endif // TEXT_H
diff --git a/src/textmanager.cpp b/src/textmanager.cpp
index bbcc271a..e22f6f4f 100644
--- a/src/textmanager.cpp
+++ b/src/textmanager.cpp
@@ -1,5 +1,6 @@
/*
* The Mana World
+ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net>
* Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
diff --git a/src/textmanager.h b/src/textmanager.h
index fd0006c9..15c65195 100644
--- a/src/textmanager.h
+++ b/src/textmanager.h
@@ -1,5 +1,6 @@
/*
* The Mana World
+ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net>
* Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
diff --git a/src/textparticle.cpp b/src/textparticle.cpp
index 0367f109..7e329b4e 100644
--- a/src/textparticle.cpp
+++ b/src/textparticle.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "textparticle.h"
-
#include "graphics.h"
+#include "textparticle.h"
TextParticle::TextParticle(Map *map, const std::string &text,
int colorR, int colorG, int colorB,
diff --git a/src/textparticle.h b/src/textparticle.h
index acf1e6a5..bc7cd88c 100644
--- a/src/textparticle.h
+++ b/src/textparticle.h
@@ -22,11 +22,10 @@
#ifndef _TEXTPARTICLE_H
#define _TEXTPARTICLE_H
-#include "particle.h"
-
#include <guichan/color.hpp>
#include "guichanfwd.h"
+#include "particle.h"
class TextParticle : public Particle
{
diff --git a/src/utils/base64.cpp b/src/utils/base64.cpp
index 8cea60f9..9d8ba836 100644
--- a/src/utils/base64.cpp
+++ b/src/utils/base64.cpp
@@ -27,8 +27,8 @@
+----------------------------------------------------------------------+
*/
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include "base64.h"
diff --git a/src/utils/strprintf.cpp b/src/utils/strprintf.cpp
index bed4a7c4..07fb3508 100644
--- a/src/utils/strprintf.cpp
+++ b/src/utils/strprintf.cpp
@@ -45,3 +45,4 @@ std::string strprintf(char const *format, ...)
delete [] buf2;
return res;
}
+
diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp
index f6498c9f..d5dd54be 100644
--- a/src/utils/xml.cpp
+++ b/src/utils/xml.cpp
@@ -20,7 +20,9 @@
*/
#include "xml.h"
+
#include "../log.h"
+
#include "../resources/resourcemanager.h"
namespace XML