summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt52
-rw-r--r--src/Makefile.am68
-rw-r--r--src/animatedsprite.cpp1
-rw-r--r--src/animationparticle.cpp1
-rw-r--r--src/being.cpp255
-rw-r--r--src/being.h117
-rw-r--r--src/beingmanager.cpp21
-rw-r--r--src/beingmanager.h39
-rw-r--r--src/configlistener.h3
-rw-r--r--src/configuration.cpp8
-rw-r--r--src/configuration.h7
-rw-r--r--src/effectmanager.cpp104
-rw-r--r--src/effectmanager.h62
-rw-r--r--src/emoteshortcut.cpp77
-rw-r--r--src/emoteshortcut.h125
-rw-r--r--src/engine.cpp51
-rw-r--r--src/engine.h2
-rw-r--r--src/equipment.cpp7
-rw-r--r--src/floor_item.cpp17
-rw-r--r--src/floor_item.h36
-rw-r--r--src/flooritemmanager.cpp3
-rw-r--r--src/game.cpp440
-rw-r--r--src/game.h8
-rw-r--r--src/graphics.cpp22
-rw-r--r--src/graphics.h28
-rw-r--r--src/gui/browserbox.cpp116
-rw-r--r--src/gui/browserbox.h8
-rw-r--r--src/gui/buddywindow.cpp83
-rw-r--r--src/gui/button.cpp46
-rw-r--r--src/gui/button.h3
-rw-r--r--src/gui/buy.cpp5
-rw-r--r--src/gui/buy.h12
-rw-r--r--src/gui/buysell.cpp3
-rw-r--r--src/gui/char_select.cpp198
-rw-r--r--src/gui/char_select.h18
-rw-r--r--src/gui/char_server.cpp30
-rw-r--r--src/gui/char_server.h2
-rw-r--r--src/gui/chat.cpp565
-rw-r--r--src/gui/chat.h62
-rw-r--r--src/gui/chatinput.h4
-rw-r--r--src/gui/checkbox.cpp31
-rw-r--r--src/gui/checkbox.h6
-rw-r--r--src/gui/color.cpp146
-rw-r--r--src/gui/color.h136
-rw-r--r--src/gui/confirm_dialog.cpp59
-rw-r--r--src/gui/confirm_dialog.h12
-rw-r--r--src/gui/connection.cpp10
-rw-r--r--src/gui/debugwindow.cpp5
-rw-r--r--src/gui/debugwindow.h4
-rw-r--r--src/gui/emotecontainer.cpp172
-rw-r--r--src/gui/emotecontainer.h136
-rw-r--r--src/gui/emoteshortcutcontainer.cpp204
-rw-r--r--src/gui/emoteshortcutcontainer.h77
-rw-r--r--src/gui/emotewindow.cpp77
-rw-r--r--src/gui/emotewindow.h (renamed from src/gui/buddywindow.h)38
-rw-r--r--src/gui/equipmentwindow.cpp214
-rw-r--r--src/gui/equipmentwindow.h54
-rw-r--r--src/gui/focushandler.cpp3
-rw-r--r--src/gui/focushandler.h2
-rw-r--r--src/gui/gui.cpp54
-rw-r--r--src/gui/gui.h8
-rw-r--r--src/gui/help.cpp17
-rw-r--r--src/gui/help.h4
-rw-r--r--src/gui/inttextfield.cpp1
-rw-r--r--src/gui/inttextfield.h3
-rw-r--r--src/gui/inventorywindow.cpp222
-rw-r--r--src/gui/inventorywindow.h41
-rw-r--r--src/gui/item_amount.cpp6
-rw-r--r--src/gui/item_amount.h4
-rw-r--r--src/gui/itemcontainer.cpp79
-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.cpp216
-rw-r--r--src/gui/itempopup.h54
-rw-r--r--src/gui/itemshortcutcontainer.cpp157
-rw-r--r--src/gui/itemshortcutcontainer.h43
-rw-r--r--src/gui/listbox.cpp34
-rw-r--r--src/gui/listbox.h3
-rw-r--r--src/gui/login.cpp218
-rw-r--r--src/gui/login.h59
-rw-r--r--src/gui/menuwindow.cpp45
-rw-r--r--src/gui/menuwindow.h2
-rw-r--r--src/gui/minimap.cpp75
-rw-r--r--src/gui/minimap.h12
-rw-r--r--src/gui/ministatus.cpp26
-rw-r--r--src/gui/ministatus.h7
-rw-r--r--src/gui/npc_text.cpp68
-rw-r--r--src/gui/npc_text.h23
-rw-r--r--src/gui/npcintegerdialog.cpp28
-rw-r--r--src/gui/npcintegerdialog.h19
-rw-r--r--src/gui/npclistdialog.cpp48
-rw-r--r--src/gui/npclistdialog.h10
-rw-r--r--src/gui/npcstringdialog.cpp18
-rw-r--r--src/gui/npcstringdialog.h11
-rw-r--r--src/gui/ok_dialog.cpp58
-rw-r--r--src/gui/ok_dialog.h10
-rw-r--r--src/gui/passwordfield.cpp2
-rw-r--r--src/gui/passwordfield.h5
-rw-r--r--src/gui/playerbox.cpp24
-rw-r--r--src/gui/playerbox.h4
-rw-r--r--src/gui/popupmenu.cpp91
-rw-r--r--src/gui/popupmenu.h3
-rw-r--r--src/gui/progressbar.cpp38
-rw-r--r--src/gui/progressbar.h9
-rw-r--r--src/gui/radiobutton.cpp39
-rw-r--r--src/gui/radiobutton.h5
-rw-r--r--src/gui/recorder.cpp116
-rw-r--r--src/gui/recorder.h76
-rw-r--r--src/gui/register.cpp56
-rw-r--r--src/gui/register.h23
-rw-r--r--src/gui/scrollarea.cpp51
-rw-r--r--src/gui/scrollarea.h5
-rw-r--r--src/gui/sdlinput.cpp2
-rw-r--r--src/gui/sell.cpp10
-rw-r--r--src/gui/sell.h4
-rw-r--r--src/gui/setup.cpp26
-rw-r--r--src/gui/setup.h5
-rw-r--r--src/gui/setup_audio.cpp7
-rw-r--r--src/gui/setup_audio.h4
-rw-r--r--src/gui/setup_colors.cpp249
-rw-r--r--src/gui/setup_colors.h75
-rw-r--r--src/gui/setup_joystick.cpp15
-rw-r--r--src/gui/setup_joystick.h4
-rw-r--r--src/gui/setup_keyboard.cpp20
-rw-r--r--src/gui/setup_keyboard.h11
-rw-r--r--src/gui/setup_players.cpp35
-rw-r--r--src/gui/setup_players.h17
-rw-r--r--src/gui/setup_video.cpp149
-rw-r--r--src/gui/setup_video.h10
-rw-r--r--src/gui/shop.h4
-rw-r--r--src/gui/shoplistbox.cpp28
-rw-r--r--src/gui/shoplistbox.h5
-rw-r--r--src/gui/shortcutcontainer.cpp71
-rw-r--r--src/gui/shortcutcontainer.h107
-rw-r--r--src/gui/shortcutwindow.cpp (renamed from src/gui/itemshortcutwindow.cpp)31
-rw-r--r--src/gui/shortcutwindow.h (renamed from src/gui/itemshortcutwindow.h)20
-rw-r--r--src/gui/skill.cpp122
-rw-r--r--src/gui/skill.h8
-rw-r--r--src/gui/slider.cpp16
-rw-r--r--src/gui/slider.h2
-rw-r--r--src/gui/speechbubble.cpp95
-rw-r--r--src/gui/speechbubble.h48
-rw-r--r--src/gui/status.cpp231
-rw-r--r--src/gui/status.h11
-rw-r--r--src/gui/table.cpp264
-rw-r--r--src/gui/table.h57
-rw-r--r--src/gui/table_model.cpp24
-rw-r--r--src/gui/table_model.h6
-rw-r--r--src/gui/textbox.cpp60
-rw-r--r--src/gui/textbox.h13
-rw-r--r--src/gui/textfield.cpp60
-rw-r--r--src/gui/textfield.h42
-rw-r--r--src/gui/trade.cpp182
-rw-r--r--src/gui/trade.h2
-rw-r--r--src/gui/truetypefont.cpp7
-rw-r--r--src/gui/truetypefont.h1
-rw-r--r--src/gui/updatewindow.cpp64
-rw-r--r--src/gui/updatewindow.h3
-rw-r--r--src/gui/viewport.cpp234
-rw-r--r--src/gui/viewport.h81
-rw-r--r--src/gui/widgets/dropdown.cpp203
-rw-r--r--src/gui/widgets/dropdown.h99
-rw-r--r--src/gui/widgets/resizegrip.cpp20
-rw-r--r--src/gui/widgets/resizegrip.h3
-rw-r--r--src/gui/widgets/tab.cpp47
-rw-r--r--src/gui/widgets/tab.h8
-rw-r--r--src/gui/widgets/tabbedarea.cpp2
-rw-r--r--src/gui/window.cpp255
-rw-r--r--src/gui/window.h38
-rw-r--r--src/gui/windowcontainer.h3
-rw-r--r--src/guichanfwd.h3
-rw-r--r--src/imageparticle.cpp3
-rw-r--r--src/inventory.cpp70
-rw-r--r--src/inventory.h8
-rw-r--r--src/item.h36
-rw-r--r--src/itemshortcut.cpp20
-rw-r--r--src/itemshortcut.h2
-rw-r--r--src/joystick.cpp5
-rw-r--r--src/joystick.h8
-rw-r--r--src/keyboardconfig.cpp129
-rw-r--r--src/keyboardconfig.h49
-rw-r--r--src/localplayer.cpp253
-rw-r--r--src/localplayer.h76
-rw-r--r--src/log.cpp2
-rw-r--r--src/log.h1
-rw-r--r--src/main.cpp345
-rw-r--r--src/main.h4
-rw-r--r--src/map.cpp24
-rw-r--r--src/map.h28
-rw-r--r--src/monster.cpp71
-rw-r--r--src/monster.h5
-rw-r--r--src/net/beinghandler.cpp94
-rw-r--r--src/net/beinghandler.h2
-rw-r--r--src/net/buysellhandler.cpp17
-rw-r--r--src/net/charserverhandler.cpp43
-rw-r--r--src/net/chathandler.cpp8
-rw-r--r--src/net/equipmenthandler.cpp51
-rw-r--r--src/net/inventoryhandler.cpp136
-rw-r--r--src/net/itemhandler.cpp1
-rw-r--r--src/net/loginhandler.cpp38
-rw-r--r--src/net/loginhandler.h3
-rw-r--r--src/net/maploginhandler.cpp9
-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.cpp22
-rw-r--r--src/net/network.h57
-rw-r--r--src/net/npchandler.cpp15
-rw-r--r--src/net/partyhandler.cpp122
-rw-r--r--src/net/partyhandler.h39
-rw-r--r--src/net/playerhandler.cpp114
-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.cpp55
-rw-r--r--src/npc.h9
-rw-r--r--src/openglgraphics.cpp23
-rw-r--r--src/particle.cpp7
-rw-r--r--src/particle.h4
-rw-r--r--src/particlecontainer.cpp5
-rw-r--r--src/particlecontainer.h6
-rw-r--r--src/particleemitter.cpp45
-rw-r--r--src/particleemitter.h9
-rw-r--r--src/particleemitterprop.h1
-rw-r--r--src/party.cpp217
-rw-r--r--src/party.h76
-rw-r--r--src/player.cpp56
-rw-r--r--src/player.h20
-rw-r--r--src/player_relations.cpp71
-rw-r--r--src/player_relations.h10
-rw-r--r--src/properties.h2
-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.cpp11
-rw-r--r--src/resources/animation.h18
-rw-r--r--src/resources/buddylist.cpp10
-rw-r--r--src/resources/buddylist.h5
-rw-r--r--src/resources/colordb.cpp122
-rw-r--r--src/resources/colordb.h52
-rw-r--r--src/resources/dye.cpp1
-rw-r--r--src/resources/dye.h5
-rw-r--r--src/resources/emotedb.cpp140
-rw-r--r--src/resources/emotedb.h60
-rw-r--r--src/resources/image.cpp46
-rw-r--r--src/resources/image.h9
-rw-r--r--src/resources/imageloader.cpp5
-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.h4
-rw-r--r--src/resources/itemdb.cpp56
-rw-r--r--src/resources/itemdb.h7
-rw-r--r--src/resources/iteminfo.cpp13
-rw-r--r--src/resources/iteminfo.h19
-rw-r--r--src/resources/mapreader.cpp38
-rw-r--r--src/resources/mapreader.h4
-rw-r--r--src/resources/monsterdb.cpp32
-rw-r--r--src/resources/monsterdb.h8
-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.cpp14
-rw-r--r--src/resources/npcdb.h8
-rw-r--r--src/resources/resource.cpp7
-rw-r--r--src/resources/resource.h9
-rw-r--r--src/resources/resourcemanager.cpp21
-rw-r--r--src/resources/resourcemanager.h6
-rw-r--r--src/resources/soundeffect.cpp3
-rw-r--r--src/resources/soundeffect.h6
-rw-r--r--src/resources/spritedef.cpp7
-rw-r--r--src/resources/spritedef.h6
-rw-r--r--src/simpleanimation.cpp16
-rw-r--r--src/simpleanimation.h11
-rw-r--r--src/sound.cpp12
-rw-r--r--src/sound.h1
-rw-r--r--src/sprite.h12
-rw-r--r--src/statuseffect.cpp10
-rw-r--r--src/text.cpp27
-rw-r--r--src/text.h25
-rw-r--r--src/textmanager.cpp18
-rw-r--r--src/textmanager.h9
-rw-r--r--src/textparticle.cpp3
-rw-r--r--src/textparticle.h5
-rw-r--r--src/utils/base64.cpp2
-rw-r--r--src/utils/strprintf.cpp1
-rw-r--r--src/utils/tostring.h15
-rw-r--r--src/utils/xml.cpp2
291 files changed, 9710 insertions, 3651 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 70a58272..c7e3d936 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
@@ -79,12 +81,20 @@ SET(SRCS
gui/chatinput.h
gui/checkbox.cpp
gui/checkbox.h
+ gui/color.cpp
+ gui/color.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
@@ -101,10 +111,12 @@ 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
- gui/itemshortcutwindow.h
+ gui/itemshortcutcontainer.h\
gui/item_amount.cpp
gui/item_amount.h
gui/linkhandler.h
@@ -138,6 +150,8 @@ SET(SRCS
gui/progressbar.h
gui/radiobutton.cpp
gui/radiobutton.h
+ gui/recorder.cpp
+ gui/recorder.h
gui/register.cpp
gui/register.h
gui/scrollarea.cpp
@@ -146,10 +160,12 @@ SET(SRCS
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_colors.cpp
+ gui/setup_colors.h
gui/setup_joystick.cpp
gui/setup_joystick.h
gui/setup_keyboard.cpp
@@ -163,10 +179,16 @@ SET(SRCS
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.cpp
@@ -179,6 +201,8 @@ SET(SRCS
gui/textfield.h
gui/trade.cpp
gui/trade.h
+ gui/truetypefont.cpp
+ gui/truetypefont.h
gui/updatewindow.h
gui/updatewindow.cpp
gui/viewport.cpp
@@ -215,6 +239,8 @@ SET(SRCS
net/network.h
net/npchandler.cpp
net/npchandler.h
+ net/partyhandler.cpp
+ net/partyhandler.h
net/playerhandler.cpp
net/playerhandler.h
net/protocol.cpp
@@ -231,8 +257,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,6 +315,10 @@ SET(SRCS
configlistener.h
configuration.cpp
configuration.h
+ effectmanager.cpp
+ effectmanager.h
+ emoteshortcut.cpp
+ emoteshortcut.h
engine.cpp
engine.h
equipment.cpp
@@ -328,9 +362,13 @@ SET(SRCS
openglgraphics.h
particle.cpp
particle.h
+ particlecontainer.cpp
+ particlecontainer.h
particleemitter.cpp
particleemitter.h
particleemitterprop.h
+ party.cpp
+ party.h
player.cpp
player.h
player_relations.cpp
@@ -346,6 +384,10 @@ SET(SRCS
sound.cpp
sound.h
sprite.h
+ text.cpp
+ text.h
+ textmanager.cpp
+ textmanager.h
textparticle.cpp
textparticle.h
tileset.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 358b0b61..8de13464 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,36 @@ 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/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/color.cpp \
+ gui/color.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 +61,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 \
@@ -80,8 +90,6 @@ tmw_SOURCES = gui/widgets/layout.cpp \
gui/npc_text.h \
gui/ok_dialog.cpp \
gui/ok_dialog.h \
- gui/truetypefont.cpp \
- gui/truetypefont.h \
gui/passwordfield.cpp \
gui/passwordfield.h \
gui/playerbox.cpp \
@@ -92,6 +100,8 @@ tmw_SOURCES = gui/widgets/layout.cpp \
gui/progressbar.h \
gui/radiobutton.cpp \
gui/radiobutton.h \
+ gui/recorder.cpp \
+ gui/recorder.h \
gui/register.cpp \
gui/register.h \
gui/scrollarea.cpp \
@@ -100,10 +110,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_colors.cpp \
+ gui/setup_colors.h \
gui/setup_joystick.cpp \
gui/setup_joystick.h \
gui/setup_keyboard.cpp \
@@ -117,22 +129,30 @@ 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 \
gui/textfield.h \
gui/trade.cpp \
gui/trade.h \
+ gui/truetypefont.cpp \
+ gui/truetypefont.h \
gui/updatewindow.h \
gui/updatewindow.cpp \
gui/viewport.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,6 +266,10 @@ 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 \
@@ -283,11 +313,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 \
@@ -318,5 +350,5 @@ tmw_SOURCES = gui/widgets/layout.cpp \
# set the include path found by configure
INCLUDES = \
$(all_includes) \
- -DTMW_DATADIR=\""$(pkgdatadir)/"\" \
+ -DPKG_DATADIR=\""$(pkgdatadir)/"\" \
-DLOCALEDIR=\""$(localedir)"\"
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..dcb45a9d 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -22,52 +22,68 @@
#include "being.h"
#include "animatedsprite.h"
-#include "equipment.h"
+#include "configuration.h"
+#include "effectmanager.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 "gui/speechbubble.h"
+
+#include "resources/colordb.h"
+
+#include "resources/emotedb.h"
+#include "resources/image.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/trim.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),
- mEquipment(new Equipment()),
mId(id),
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 +99,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 +139,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 +172,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 +185,44 @@ 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
+ trim(mSpeech);
+
+ // check for links
+ std::string::size_type start = mSpeech.find('[');
+ std::string::size_type end = mSpeech.find(']', start);
- mSpeech = new Text(text, mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET,
- gcn::Graphics::CENTER,
- gcn::Color(255, 255, 255), true);
- mSpeechTime = 500;
+ 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);
+ }
+
+ std::string::size_type position = mSpeech.find('|');
+ if (mSpeech[start + 1] == '@' && mSpeech[start + 2] == '@')
+ {
+ 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.empty())
+ mSpeechTime = time <= SPEECH_MAX_TIME ? time : SPEECH_MAX_TIME;
}
void Being::takeDamage(int amount)
@@ -173,10 +237,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;
@@ -190,6 +250,13 @@ void Being::takeDamage(int amount)
// Show damage number
particleEngine->addTextSplashEffect(damage, 255, 255, 255, font,
mPx + 16, mPy + 16);
+ effectManager->trigger(26, this);
+}
+
+void Being::showCrit()
+{
+ effectManager->trigger(28, this);
+
}
void Being::handleAttack(Being *victim, int damage)
@@ -225,9 +292,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 +309,8 @@ void Being::setAction(Uint8 action)
{
currentAction = mEquippedWeapon->getAttackType();
}
- else {
+ else
+ {
currentAction = ACTION_ATTACK;
}
for (int i = 0; i < VECTOREND_SPRITE; i++)
@@ -278,16 +347,18 @@ void Being::setAction(Uint8 action)
}
}
-
void Being::setDirection(Uint8 direction)
{
+ if (mDirection == direction)
+ return;
+
mDirection = direction;
SpriteDirection dir = getSpriteDirection();
for (int i = 0; i < VECTOREND_SPRITE; i++)
{
- if (mSprites[i] != NULL)
- mSprites[i]->setDirection(dir);
+ if (mSprites[i])
+ mSprites[i]->setDirection(dir);
}
}
@@ -307,8 +378,9 @@ SpriteDirection Being::getSpriteDirection() const
{
dir = DIRECTION_RIGHT;
}
- else {
- dir = DIRECTION_LEFT;
+ else
+ {
+ dir = DIRECTION_LEFT;
}
return dir;
@@ -352,28 +424,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--;
@@ -385,7 +457,7 @@ void Being::logic()
// Update sprite animations
for (int i = 0; i < VECTOREND_SPRITE; i++)
{
- if (mSprites[i] != NULL)
+ if (mSprites[i])
{
mSprites[i]->update(tick_time * 10);
}
@@ -415,7 +487,7 @@ void Being::draw(Graphics *graphics, int offsetX, int offsetY) const
for (int i = 0; i < VECTOREND_SPRITE; i++)
{
- if (mSprites[i] != NULL)
+ if (mSprites[i])
{
mSprites[i]->draw(graphics, px, py);
}
@@ -431,8 +503,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(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 +566,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 +610,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 +619,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 +653,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;
}
}
@@ -620,14 +743,14 @@ void Being::internalTriggerEffect(int effectId, bool sfx, bool gfx)
return;
}
- if (gfx && ed->mGFXEffect != "") {
+ if (gfx && !ed->mGFXEffect.empty()) {
Particle *selfFX;
selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0);
controlParticle(selfFX);
}
- if (sfx && ed->mSFXEffect != "") {
+ if (sfx && !ed->mSFXEffect.empty()) {
sound.playSfx(ed->mSFXEffect);
}
}
@@ -695,7 +818,7 @@ static void initializeHair()
int index = atoi(XML::getProperty(node, "id", "-1").c_str());
std::string value = XML::getProperty(node, "value", "");
- if (index >= 0 && value != "") {
+ if (index >= 0 && !value.empty()) {
if (index >= hairColorsNr) {
hairColorsNr = index + 1;
hairColors.resize(hairColorsNr, "#000000");
@@ -706,7 +829,7 @@ static void initializeHair()
}
} // done initializing
- if (hairColorsNr == 0) { // No colours -> black only
+ if (hairColorsNr == 0) { // No colors -> black only
hairColorsNr = 1;
hairColors.resize(hairColorsNr, "#000000");
}
diff --git a/src/being.h b/src/being.h
index 7d5ed989..3c3a9b73 100644
--- a/src/being.h
+++ b/src/being.h
@@ -22,34 +22,44 @@
#ifndef BEING_H
#define BEING_H
-#include <list>
-#include <memory>
-#include <string>
+#include <guichan/color.hpp>
+
#include <SDL_types.h>
+
#include <set>
+#include <string>
+#include <vector>
+#include "particlecontainer.h"
#include "position.h"
#include "sprite.h"
-#include "map.h"
-#include "animatedsprite.h"
-#include "particlecontainer.h"
+
+#include "resources/spritedef.h"
#define FIRST_IGNORE_EMOTE 14
#define STATUS_EFFECTS 32
+#define SPEECH_TIME 500
+#define SPEECH_MAX_TIME 1000
+
class AnimatedSprite;
-class Equipment;
+class Image;
class ItemInfo;
class Item;
class Map;
class Graphics;
-class ImageSet;
class Particle;
+class Position;
+class SpeechBubble;
class Text;
class StatusEffect;
-enum Gender {
+typedef std::list<Sprite*> Sprites;
+typedef Sprites::iterator SpriteIterator;
+
+enum Gender
+{
GENDER_MALE = 0,
GENDER_FEMALE = 1,
GENDER_UNSPECIFIED = 2
@@ -58,7 +68,8 @@ enum Gender {
class Being : public Sprite
{
public:
- enum Type {
+ enum Type
+ {
UNKNOWN,
PLAYER,
NPC,
@@ -68,7 +79,8 @@ class Being : public Sprite
/**
* Action the being is currently performing.
*/
- enum Action {
+ enum Action
+ {
STAND,
WALK,
ATTACK,
@@ -77,7 +89,8 @@ class Being : public Sprite
HURT
};
- enum Sprite {
+ enum Sprite
+ {
BASE_SPRITE = 0,
SHOE_SPRITE,
BOTTOMCLOTHES_SPRITE,
@@ -93,7 +106,8 @@ class Being : public Sprite
VECTOREND_SPRITE
};
- enum TargetCursorSize {
+ enum TargetCursorSize
+ {
TC_SMALL = 0,
TC_MEDIUM,
TC_LARGE,
@@ -107,13 +121,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.
@@ -142,7 +156,7 @@ class Being : public Sprite
* @param text The text that should appear.
* @param time The amount of time the text should stay in milliseconds.
*/
- void setSpeech(const std::string &text, Uint32 time);
+ void setSpeech(const std::string &text, Uint32 time = 500);
/**
* Puts a damage bubble above this being.
@@ -152,6 +166,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 +205,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 +235,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(int offsetX, int offsetY);
+
+ /**
* Draws the emotion picture above the being.
*/
void drawEmotion(Graphics *graphics, int offsetX, int offsetY);
@@ -253,7 +290,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 +303,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 +364,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 +405,8 @@ class Being : public Sprite
internalTriggerEffect(effectId, false, true);
}
- const std::auto_ptr<Equipment> mEquipment;
-
+ // Target cursor being used by the being
+ Image *mTargetCursor;
static int getHairColorsNr();
@@ -365,6 +414,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 +429,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 +463,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 +481,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 +497,14 @@ 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? */
+ /** Reset particle status effects on next redraw? */
+ bool mMustResetParticles;
+
+ // 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..ec7d6a2c 100644
--- a/src/configlistener.h
+++ b/src/configlistener.h
@@ -22,8 +22,7 @@
#ifndef CONFIGLISTENER_H
#define CONFIGLISTENER_H
-#include <iosfwd>
-
+#include <string>
/**
* The listener interface for receiving notifications about changes to
diff --git a/src/configuration.cpp b/src/configuration.cpp
index 04839777..6815ea03 100644
--- a/src/configuration.cpp
+++ b/src/configuration.cpp
@@ -19,12 +19,8 @@
* 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 +86,6 @@ void ConfigurationObject::clear()
mOptions.clear();
}
-
ConfigurationObject::~ConfigurationObject()
{
clear();
@@ -193,7 +188,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..4d28008d 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -22,11 +22,12 @@
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
-#include <map>
+#include <libxml/xmlwriter.h>
+
+#include <cassert>
#include <list>
+#include <map>
#include <string>
-#include <cassert>
-#include <libxml/xmlwriter.h>
class ConfigListener;
class ConfigurationObject;
diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp
new file mode 100644
index 00000000..f004a450
--- /dev/null
+++ b/src/effectmanager.cpp
@@ -0,0 +1,104 @@
+/*
+ * An effects manager
+ * Copyright (C) 2008 Fate <fate.tmw@googlemail.com>
+ * Copyright (C) 2008 Chuck Miller <shadowmil@gmail.com>
+ *
+ * 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 "being.h"
+#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)
+ {
+ rValue = true;
+ if (!(*i).GFX.empty())
+ {
+ Particle *selfFX;
+ selfFX = particleEngine->addEffect((*i).GFX, 0, 0);
+ being->controlParticle(selfFX);
+ }
+ if (!(*i).SFX.empty())
+ 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)
+ {
+ rValue = true;
+ if (!(*i).GFX.empty())
+ particleEngine->addEffect((*i).GFX, x, y);
+ if (!(*i).SFX.empty())
+ sound.playSfx((*i).SFX);
+ break;
+ }
+ }
+ return rValue;
+}
diff --git a/src/effectmanager.h b/src/effectmanager.h
new file mode 100644
index 00000000..01c5a6b8
--- /dev/null
+++ b/src/effectmanager.h
@@ -0,0 +1,62 @@
+/*
+ * An effects manager
+ * Copyright (C) 2008 Fate <fate.tmw@googlemail.com>
+ * Copyright (C) 2008 Chuck Miller <shadowmil@gmail.com>
+ *
+ * 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
+ */
+
+#ifndef EFFECT_MANAGER_H
+#define EFFECT_MANAGER_H
+
+#include <list>
+#include <string>
+
+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..807fa3a2
--- /dev/null
+++ b/src/emoteshortcut.cpp
@@ -0,0 +1,77 @@
+/*
+ * Extended support for activating emotes
+ * Copyright (C) 2009 Aethyra 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 "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..ceb51a9b
--- /dev/null
+++ b/src/emoteshortcut.h
@@ -0,0 +1,125 @@
+/*
+ * Extended support for activating emotes
+ * Copyright (C) 2009 Aethyra 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
+ */
+
+#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..39b9b3ec 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -19,19 +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"
#include "localplayer.h"
#include "log.h"
-#include "main.h"
#include "map.h"
#include "particle.h"
#include "sound.h"
@@ -44,14 +37,10 @@
#include "net/protocol.h"
#include "resources/mapreader.h"
-#include "resources/monsterdb.h"
#include "resources/resourcemanager.h"
-#include "utils/dtor.h"
#include "utils/tostring.h"
-extern Minimap *minimap;
-
char itemCurrenyQ[10] = "0";
Engine::Engine(Network *network):
@@ -82,28 +71,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 +117,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/engine.h b/src/engine.h
index f2852351..7ad6d894 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -22,7 +22,6 @@
#ifndef _ENGINE_H
#define _ENGINE_H
-#include <iosfwd>
#include <string>
class Map;
@@ -52,7 +51,6 @@ class Engine
const std::string &getCurrentMapName() { return mMapName; }
-
/**
* Sets the currently active map.
*/
diff --git a/src/equipment.cpp b/src/equipment.cpp
index b93beed4..cb7acd44 100644
--- a/src/equipment.cpp
+++ b/src/equipment.cpp
@@ -24,19 +24,16 @@
#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);
+ item->setEquipped(true);
}
diff --git a/src/floor_item.cpp b/src/floor_item.cpp
index e96b3652..fbe606b4 100644
--- a/src/floor_item.cpp
+++ b/src/floor_item.cpp
@@ -20,9 +20,12 @@
*/
#include "floor_item.h"
-
+#include "graphics.h"
+#include "item.h"
#include "map.h"
+#include "resources/image.h"
+
FloorItem::FloorItem(unsigned int id,
unsigned int itemId,
unsigned short x,
@@ -47,3 +50,15 @@ FloorItem::~FloorItem()
delete mItem;
}
+
+unsigned int FloorItem::getItemId() const
+{
+ return mItem->getId();
+}
+
+void FloorItem::draw(Graphics *graphics, int offsetX, int offsetY) const
+{
+ graphics->drawImage(mItem->getImage(),
+ mX * 32 + offsetX,
+ mY * 32 + offsetY);
+}
diff --git a/src/floor_item.h b/src/floor_item.h
index e0a67eca..444c756a 100644
--- a/src/floor_item.h
+++ b/src/floor_item.h
@@ -22,11 +22,16 @@
#ifndef FLOORITEM_H
#define FLOORITEM_H
-#include "graphics.h"
-#include "item.h"
-#include "map.h"
+#include <list>
+
#include "sprite.h"
-#include "resources/image.h"
+
+class Graphics;
+class Image;
+class Item;
+class Map;
+
+typedef std::list<Sprite*> Sprites;
/**
* An item lying on the floor.
@@ -51,47 +56,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;
/**
* 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
- {
- graphics->drawImage(mItem->getImage(),
- mX * 32 + offsetX,
- mY * 32 + offsetY);
- }
+ void draw(Graphics *graphics, int offsetX, int offsetY) const;
private:
unsigned int mId;
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 2ba8f7d7..5b701fc1 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "game.h"
-
#include <fstream>
#include <physfs.h>
#include <sstream>
@@ -30,8 +28,11 @@
#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,14 @@
#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/itemshortcutcontainer.h"
#include "gui/menuwindow.h"
#include "gui/minimap.h"
#include "gui/ministatus.h"
@@ -68,23 +72,23 @@
#include "gui/trade.h"
#include "gui/viewport.h"
-#include "net/protocol.h"
#include "net/beinghandler.h"
#include "net/buysellhandler.h"
#include "net/chathandler.h"
#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"
-extern Graphics *graphics;
+#include "utils/gettext.h"
class Map;
@@ -93,6 +97,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 +114,7 @@ BuyDialog *buyDialog;
SellDialog *sellDialog;
BuySellDialog *buySellDialog;
InventoryWindow *inventoryWindow;
+EmoteWindow *emoteWindow;
NpcIntegerDialog *npcIntegerDialog;
NpcListDialog *npcListDialog;
NpcTextDialog *npcTextDialog;
@@ -118,19 +124,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 +170,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 +200,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();
@@ -197,22 +208,18 @@ void createGuiWindows(Network *network)
skillDialog = new SkillDialog();
setupWindow = new Setup();
minimap = new Minimap();
- equipmentWindow = new EquipmentWindow(player_node->mEquipment.get());
+ equipmentWindow = new EquipmentWindow();
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 +229,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 +249,7 @@ void destroyGuiWindows()
delete sellDialog;
delete buySellDialog;
delete inventoryWindow;
+ delete emoteWindow;
delete npcIntegerDialog;
delete npcListDialog;
delete npcTextDialog;
@@ -252,10 +259,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 +283,8 @@ Game::Game(Network *network):
beingManager = new BeingManager(network);
floorItemManager = new FloorItemManager();
+ effectManager = new EffectManager();
+
particleEngine = new Particle(NULL);
particleEngine->setupEngine();
@@ -310,17 +319,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, 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.
+ * 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
*
- * 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,12 +384,12 @@ 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);
+ chatWindow->chatLog(_("Saving screenshot failed!"), BY_SERVER);
logger->log("Error: could not save screenshot.");
}
@@ -430,7 +435,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 +465,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();
}
@@ -487,114 +492,100 @@ void Game::handleInput()
gcn::Window *requestedWindow = NULL;
if (setupWindow->isVisible() &&
- keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
+ keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
{
keyboard.setNewKey((int) event.key.keysym.sym);
keyboard.callbackNewKey();
keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE);
return;
}
- // Keys pressed together with Alt/Meta
- // Emotions and some internal gui windows
- #ifndef __APPLE__
- if (event.key.keysym.mod & KMOD_LALT)
- #else
- if (event.key.keysym.mod & KMOD_LMETA)
- #endif
- {
- switch (event.key.keysym.sym)
- {
- case SDLK_p:
- // Screenshot (picture, hence the p)
- saveScreenshot();
- used = true;
- break;
-
- default:
- break;
-
- case SDLK_f:
- // Find path to mouse (debug purpose)
- viewport->toggleDebugPath();
- used = true;
- break;
-
- case SDLK_t:
- // Toggle accepting of incoming trade requests
- {
- 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);
- }
- 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;
}
}
- switch (event.key.keysym.sym)
+
+ if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT) ||
+ keyboard.isKeyActive(keyboard.KEY_OK))
+ {
+ // Input chat window
+ if (!(chatWindow->isInputFocused() ||
+ deathNotice ||
+ weightNotice))
+ {
+ // Quit by pressing Enter if the exit confirm is there
+ if (exitConfirm &&
+ keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT))
+ done = true;
+ // Close the Browser if opened
+ else if (helpWindow->isVisible() &&
+ keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT))
+ helpWindow->setVisible(false);
+ // Close the config window, cancelling changes if opened
+ else if (setupWindow->isVisible() &&
+ keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT))
+ setupWindow->action(gcn::ActionEvent(NULL, "cancel"));
+ // Submits the text and proceeds to the next dialog
+ else if (npcStringDialog->isVisible() &&
+ keyboard.isKeyActive(keyboard.KEY_OK))
+ npcStringDialog->action(gcn::ActionEvent(NULL, "ok"));
+ // Proceed to the next dialog option, or close the window
+ else if (npcTextDialog->isVisible() &&
+ keyboard.isKeyActive(keyboard.KEY_OK))
+ npcTextDialog->action(gcn::ActionEvent(NULL, "ok"));
+ // Choose the currently highlighted dialogue option
+ else if (npcListDialog->isVisible() &&
+ keyboard.isKeyActive(keyboard.KEY_OK))
+ npcListDialog->action(gcn::ActionEvent(NULL, "ok"));
+ // Submits the text and proceeds to the next dialog
+ else if (npcIntegerDialog->isVisible() &&
+ keyboard.isKeyActive(keyboard.KEY_OK))
+ npcIntegerDialog->action(gcn::ActionEvent(NULL, "ok"));
+ else if (!(keyboard.getKeyValue(
+ KeyboardConfig::KEY_TOGGLE_CHAT) ==
+ keyboard.getKeyValue(
+ KeyboardConfig::KEY_OK) &&
+ (npcStringDialog->isVisible() ||
+ npcTextDialog->isVisible() ||
+ npcListDialog->isVisible() ||
+ npcIntegerDialog->isVisible())))
+ {
+ chatWindow->requestChatFocus();
+ used = true;
+ }
+ }
+ }
+
+ const int tKey = keyboard.getKeyIndex(event.key.keysym.sym);
+ switch (tKey)
{
- case SDLK_PAGEUP:
+ case KeyboardConfig::KEY_SCROLL_CHAT_UP:
if (chatWindow->isVisible())
{
chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL);
used = true;
}
break;
-
- case SDLK_PAGEDOWN:
+ case KeyboardConfig::KEY_SCROLL_CHAT_DOWN:
if (chatWindow->isVisible())
{
chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL);
used = true;
+ return;
}
break;
-
- case SDLK_F1:
+ case KeyboardConfig::KEY_WINDOW_HELP:
// In-game Help
if (helpWindow->isVisible())
- {
helpWindow->setVisible(false);
- }
else
{
helpWindow->loadHelp("index");
@@ -602,75 +593,48 @@ void Game::handleInput()
}
used = true;
break;
-
- case SDLK_RETURN:
- // Input chat window
- if (chatWindow->isInputFocused() ||
- deathNotice != NULL ||
- weightNotice != NULL)
+ // Quitting confirmation dialog
+ case KeyboardConfig::KEY_QUIT:
+ if (!exitConfirm)
{
- break;
- }
-
- // Quit by pressing Enter if the exit confirm is there
- if (exitConfirm)
- {
- 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"));
- }
- // Else, open the chat edit box
- else
- {
- chatWindow->requestChatFocus();
- used = true;
- }
- break;
- // Quitting confirmation dialog
- case SDLK_ESCAPE:
- if (!exitConfirm) {
- exitConfirm = new ConfirmDialog(
- "Quit", "Are you sure you want to quit?");
+ 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;
-
default:
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 =
@@ -679,7 +643,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)
@@ -707,11 +672,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);
@@ -719,7 +685,6 @@ void Game::handleInput()
debugWindow->setVisible(false);
}
break;
-
case KeyboardConfig::KEY_WINDOW_STATUS:
requestedWindow = statusWindow;
break;
@@ -733,6 +698,7 @@ void Game::handleInput()
requestedWindow = skillDialog;
break;
case KeyboardConfig::KEY_WINDOW_MINIMAP:
+ minimap->toggle();
requestedWindow = minimap;
break;
case KeyboardConfig::KEY_WINDOW_CHAT:
@@ -747,6 +713,44 @@ 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;
+ case KeyboardConfig::KEY_SCREENSHOT:
+ // Screenshot (picture, hence the p)
+ saveScreenshot();
+ used = true;
+ break;
+ case KeyboardConfig::KEY_PATHFIND:
+ // Find path to mouse (debug purpose)
+ viewport->toggleDebugPath();
+ used = true;
+ break;
+ case KeyboardConfig::KEY_TRADE:
+ // Toggle accepting of incoming trade requests
+ 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);
+
+ used = true;
+ break;
}
}
@@ -754,14 +758,10 @@ void Game::handleInput()
{
requestedWindow->setVisible(!requestedWindow->isVisible());
if (requestedWindow->isVisible())
- {
requestedWindow->requestMoveToTop();
- }
used = true;
}
-
}
-
// Quit event
else if (event.type == SDL_QUIT)
{
@@ -781,7 +781,6 @@ void Game::handleInput()
logger->log("Warning: guichan input exception: %s", err);
}
}
-
} // End while
// If the user is configuring the keys then don't respond.
@@ -790,8 +789,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();
@@ -802,23 +800,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;
}
@@ -827,60 +825,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..d7d2a562 100644
--- a/src/game.h
+++ b/src/game.h
@@ -19,17 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef GAME_
-#define GAME_
+#ifndef GAME_H
+#define GAME_H
-#include <iosfwd>
#include <memory>
#include "configlistener.h"
-#define SPEECH_TIME 80
-#define SPEECH_MAX_TIME 100
-
class MessageHandler;
class Network;
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..172032dc 100644
--- a/src/graphics.h
+++ b/src/graphics.h
@@ -46,14 +46,16 @@ struct SDL_Surface;
* Sections 0, 2, 6 and 8 will remain as is. 1, 3, 4, 5 and 7 will be
* repeated to fit the size of the widget.
*/
-struct ImageRect {
+struct ImageRect
+{
Image *grid[9];
};
/**
* A central point of control for graphics.
*/
-class Graphics : public gcn::SDLGraphics {
+class Graphics : public gcn::SDLGraphics
+{
public:
/**
* Constructor.
@@ -95,17 +97,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
@@ -153,4 +153,6 @@ class Graphics : public gcn::SDLGraphics {
bool mFullscreen, mHWAccel;
};
+extern Graphics *graphics;
+
#endif
diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp
index 2d805b9c..a06b9a6e 100644
--- a/src/gui/browserbox.cpp
+++ b/src/gui/browserbox.cpp
@@ -21,15 +21,17 @@
#include <algorithm>
-#include "browserbox.h"
+#include <guichan/graphics.hpp>
+#include "browserbox.h"
+#include "color.h"
#include "linkhandler.h"
#include "truetypefont.h"
-BrowserBox::BrowserBox(unsigned int mode):
+BrowserBox::BrowserBox(unsigned int mode, bool opaque):
gcn::Widget(),
mMode(mode), mHighMode(UNDERLINE | BACKGROUND),
- mOpaque(true),
+ mOpaque(opaque),
mUseLinksAndUserColors(true),
mSelectedLink(-1),
mMaxRows(0)
@@ -98,12 +100,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 != "")
+ if (!tmp.empty())
{
- newRow += "##P";
+ newRow += "##>";
}
idx1 = tmp.find("@@");
}
@@ -122,7 +124,18 @@ void BrowserBox::addRow(const std::string &row)
//discard older rows when a row limit has been set
if (mMaxRows > 0)
{
- while (mTextRows.size() > mMaxRows) mTextRows.pop_front();
+ while (mTextRows.size() > mMaxRows)
+ {
+ mTextRows.pop_front();
+ for (unsigned int i = 0; i < mLinks.size(); i++)
+ {
+ mLinks[i].y1 -= font->getHeight();
+ mLinks[i].y2 -= font->getHeight();
+
+ if (mLinks[i].y1 < 0)
+ mLinks.erase(mLinks.begin() + i);
+ }
+ }
}
// Auto size mode
@@ -210,8 +223,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 +233,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 +241,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)
{
@@ -241,9 +251,10 @@ BrowserBox::draw(gcn::Graphics *graphics)
if (mSelectedLink >= 0)
{
+ bool valid;
if ((mHighMode & BACKGROUND))
{
- graphics->setColor(gcn::Color(HIGHLIGHT));
+ graphics->setColor(gcn::Color(textColor->getColor('H', valid)));
graphics->fillRectangle(gcn::Rectangle(
mLinks[mSelectedLink].x1,
mLinks[mSelectedLink].y1,
@@ -254,7 +265,7 @@ BrowserBox::draw(gcn::Graphics *graphics)
if ((mHighMode & UNDERLINE))
{
- graphics->setColor(gcn::Color(LINK));
+ graphics->setColor(gcn::Color(textColor->getColor('<', valid)));
graphics->drawLine(
mLinks[mSelectedLink].x1,
mLinks[mSelectedLink].y2,
@@ -265,6 +276,7 @@ BrowserBox::draw(gcn::Graphics *graphics)
int x = 0, y = 0;
int wrappedLines = 0;
+ int link = 0;
TrueTypeFont *font = static_cast<TrueTypeFont*>(getFont());
graphics->setColor(BLACK);
@@ -311,57 +323,36 @@ 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 = textColor->getColor(c, valid);
+ if (c == '<')
+ {
+ const int size = mLinks[link].x2 - mLinks[link].x1;
+ mLinks[link].x1 = x;
+ mLinks[link].y1 = y;
+ mLinks[link].x2 = mLinks[link].x1 + size;
+ mLinks[link].y2 = y + font->getHeight();
+ link++;
prevColor = selColor;
- selColor = BLACK;
+ }
+ if (valid)
+ {
+ selColor = rgb;
+ }
}
start += 3;
+
+ if (start == row.size())
+ {
+ break;
+ }
}
graphics->setColor(gcn::Color(selColor));
}
@@ -424,3 +415,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..5dde402e 100644
--- a/src/gui/browserbox.h
+++ b/src/gui/browserbox.h
@@ -22,15 +22,12 @@
#ifndef BROWSERBOX_H
#define BROWSERBOX_H
-#include <iosfwd>
+#include <list>
#include <vector>
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
-#include "../guichanfwd.h"
-#include "../main.h"
-
class LinkHandler;
struct BROWSER_LINK {
@@ -49,7 +46,7 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener
/**
* Constructor.
*/
- BrowserBox(unsigned int mode = AUTO_SIZE);
+ BrowserBox(unsigned int mode = AUTO_SIZE, bool opaque = true);
/**
* Destructor.
@@ -165,3 +162,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..1d3a04e4 100644
--- a/src/gui/button.cpp
+++ b/src/gui/button.cpp
@@ -19,8 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <guichan/exception.hpp>
+#include <guichan/font.hpp>
+
#include "button.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../resources/image.h"
@@ -28,13 +32,8 @@
#include "../utils/dtor.h"
-#include <guichan/exception.hpp>
-#include <guichan/graphics.hpp>
-#include <guichan/font.hpp>
-
-#include <algorithm>
-
int Button::mInstances = 0;
+float Button::mAlpha = config.getValue("guialpha", 0.8);
enum{
BUTTON_STANDARD, // 0
@@ -100,6 +99,7 @@ void Button::init()
data[x].gridX, data[y].gridY,
data[x + 1].gridX - data[x].gridX + 1,
data[y + 1].gridY - data[y].gridY + 1);
+ button[mode].grid[a]->setAlpha(mAlpha);
a++;
}
}
@@ -122,22 +122,29 @@ Button::~Button()
}
}
-void
-Button::draw(gcn::Graphics *graphics)
+void Button::draw(gcn::Graphics *graphics)
{
int mode;
- if (!isEnabled()) {
+ if (!isEnabled())
mode = BUTTON_DISABLED;
- }
- else if (isPressed() || mIsLogged) {
+ else if (isPressed() || mIsLogged)
mode = BUTTON_PRESSED;
- }
- else if (mHasMouse || isFocused()) {
+ else if (mHasMouse || isFocused())
mode = BUTTON_HIGHLIGHTED;
- }
- else {
+ else
mode = BUTTON_STANDARD;
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ for (int a = 0; a < 9; a++)
+ {
+ button[BUTTON_DISABLED].grid[a]->setAlpha(mAlpha);
+ button[BUTTON_PRESSED].grid[a]->setAlpha(mAlpha);
+ button[BUTTON_HIGHLIGHTED].grid[a]->setAlpha(mAlpha);
+ button[BUTTON_STANDARD].grid[a]->setAlpha(mAlpha);
+ }
}
static_cast<Graphics*>(graphics)->
@@ -148,7 +155,8 @@ Button::draw(gcn::Graphics *graphics)
int textX;
int textY = getHeight() / 2 - getFont()->getHeight() / 2;
- switch (getAlignment()) {
+ switch (getAlignment())
+ {
case gcn::Graphics::LEFT:
textX = 4;
break;
@@ -164,10 +172,8 @@ Button::draw(gcn::Graphics *graphics)
graphics->setFont(getFont());
- if (isPressed()) {
+ if (isPressed())
graphics->drawText(getCaption(), textX + 1, textY + 1, getAlignment());
- }
- else {
+ else
graphics->drawText(getCaption(), textX, textY, getAlignment());
- }
}
diff --git a/src/gui/button.h b/src/gui/button.h
index 0ec99245..abaf5c43 100644
--- a/src/gui/button.h
+++ b/src/gui/button.h
@@ -22,8 +22,6 @@
#ifndef BUTTON_H
#define BUTTON_H
-#include <iosfwd>
-
#include <guichan/widgets/button.hpp>
class ImageRect;
@@ -69,6 +67,7 @@ class Button : public gcn::Button
static ImageRect button[4]; /**< Button state graphics */
static int mInstances; /**< Number of button instances */
+ static float mAlpha;
bool mIsLogged; /**< Makes the button appear pressed all the time */
};
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..0f1cfede 100644
--- a/src/gui/buy.h
+++ b/src/gui/buy.h
@@ -25,9 +25,9 @@
#include <guichan/actionlistener.hpp>
#include <guichan/selectionlistener.hpp>
-#include "window.h"
+#include <SDL_types.h>
-#include "../guichanfwd.h"
+#include "window.h"
class Network;
class ShopItems;
@@ -40,7 +40,7 @@ class ListBox;
* \ingroup Interface
*/
class BuyDialog : public Window, public gcn::ActionListener,
- gcn::SelectionListener
+ public gcn::SelectionListener
{
public:
/**
@@ -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/char_select.cpp b/src/gui/char_select.cpp
index df57f969..8de4f5a7 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -19,13 +19,14 @@
* 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"
@@ -40,6 +41,8 @@
#include "../net/charserverhandler.h"
#include "../net/messageout.h"
+#include "../resources/colordb.h"
+
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
#include "../utils/trim.h"
@@ -69,7 +72,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 +85,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 +133,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 +144,21 @@ void CharSelectDialog::action(const gcn::ActionEvent &event)
{
state = EXIT_STATE;
}
- else if (event.getId() == "new" && n_character <= MAX_SLOT)
+ else if (event.getId() == "newdel")
{
- // Start new character dialog
- CharCreateDialog *charCreateDialog =
- new CharCreateDialog(this, mCharInfo->getPos(), mNetwork, mGender);
- charServerHandler.setCharCreateDialog(charCreateDialog);
- }
- else if (event.getId() == "delete")
- {
- // 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 +182,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 +231,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 +252,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 +269,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 +306,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..23de061d 100644
--- a/src/gui/char_select.h
+++ b/src/gui/char_select.h
@@ -22,17 +22,16 @@
#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 "../lockedarray.h"
-#include <guichan/actionlistener.hpp>
-
-class Player;
class LocalPlayer;
class Network;
+class Player;
class PlayerBox;
/**
@@ -65,8 +64,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;
@@ -110,14 +108,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener
*/
~CharCreateDialog();
- void
- action(const gcn::ActionEvent &event);
+ void action(const gcn::ActionEvent &event);
/**
* Unlocks the dialog, enabling the create character button again.
*/
- void
- unlock();
+ void unlock();
private:
/**
diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp
index 7be2441d..bc096379 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"
@@ -29,10 +28,7 @@
#include "../main.h"
#include "../serverinfo.h"
-#include "../net/network.h" // TODO this is just for iptostring, move that?
-
#include "../utils/gettext.h"
-#include "../utils/strprintf.h"
#include "../utils/tostring.h"
extern SERVER_INFO **server_info;
@@ -40,7 +36,8 @@ extern SERVER_INFO **server_info;
/**
* The list model for the server list.
*/
-class ServerListModel : public gcn::ListModel {
+class ServerListModel : public gcn::ListModel
+{
public:
virtual ~ServerListModel() {};
@@ -81,13 +78,12 @@ ServerSelectDialog::ServerSelectDialog(LoginData *loginData, int nextState):
add(mOkButton);
add(mCancelButton);
- if (n_server == 0) {
+ if (n_server == 0)
// Disable Ok button
mOkButton->setEnabled(false);
- } else {
+ else
// Select first server
mServerList->setSelected(1);
- }
setLocationRelativeTo(getParent());
setVisible(true);
@@ -99,31 +95,27 @@ ServerSelectDialog::~ServerSelectDialog()
delete mServerListModel;
}
-void
-ServerSelectDialog::action(const gcn::ActionEvent &event)
+void ServerSelectDialog::action(const gcn::ActionEvent &event)
{
- if (event.getId() == "ok") {
+ if (event.getId() == "ok")
+ {
mOkButton->setEnabled(false);
const SERVER_INFO *si = server_info[mServerList->getSelected()];
mLoginData->hostname = iptostring(si->address);
mLoginData->port = si->port;
mLoginData->updateHost = si->updateHost;
-
state = mNextState;
}
- else if (event.getId() == "cancel") {
+ else if (event.getId() == "cancel")
state = LOGIN_STATE;
- }
}
-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/char_server.h b/src/gui/char_server.h
index 9419c92d..49a5b47b 100644
--- a/src/gui/char_server.h
+++ b/src/gui/char_server.h
@@ -27,8 +27,6 @@
#include "window.h"
-#include "../guichanfwd.h"
-
class LoginData;
class ServerListModel;
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
index 87d843a0..484426dd 100644
--- a/src/gui/chat.cpp
+++ b/src/gui/chat.cpp
@@ -19,57 +19,61 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
-#include <sstream>
-
#include <guichan/focushandler.hpp>
-#include "chat.h"
-
#include "browserbox.h"
+#include "chat.h"
#include "chatinput.h"
+#include "itemlinkhandler.h"
+#include "recorder.h"
#include "scrollarea.h"
#include "sdlinput.h"
#include "windowcontainer.h"
#include "widgets/layout.h"
+#include "../beingmanager.h"
#include "../configuration.h"
#include "../game.h"
#include "../localplayer.h"
+#include "../party.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->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 +88,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.empty() ? '$' : 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");
+}
+
+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)
+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 +137,109 @@ void ChatWindow::chatLog(std::string line, int own)
}
}
- std::string lineColor = "##0"; // Equiv. to BrowserBox::BLACK
- switch (own) {
+ // *implements actions in a backwards compatible way*
+ if (own == BY_PLAYER &&
+ tmp.text.at(0) == '*' &&
+ tmp.text.at(tmp.text.length()-1) == '*')
+ {
+ tmp.text[0] = ' ';
+ tmp.text.erase(tmp.text.length() - 1);
+ own = ACT_IS;
+ }
+
+ 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.empty() && 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 +253,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 +270,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 +308,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 +324,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 +338,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 +348,69 @@ 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 */
+ trim(msg);
+
+ if (msg.compare("") == 0)
+ return;
+
+ // 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 (start+1 != end && 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);
+
+ trim(temp);
+
+ for (unsigned int i = 0; i < temp.size(); i++)
+ {
+ temp[i] = (char) tolower(temp[i]);
+ }
+
+ const ItemInfo itemInfo = ItemDB::get(temp);
+ if (itemInfo.getName() != _("Unknown item"))
+ {
+ 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 +418,38 @@ 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
+ {
+ msg = msg.substr(space);
+ trim(msg);
}
- else if (msg.substr(0, IS_ANNOUNCE_LENGTH) == IS_ANNOUNCE)
+
+ 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);
trim(msg);
std::size_t space = msg.find(" ");
std::string msg1;
+
if (space == std::string::npos)
{
msg1 = "";
@@ -317,33 +459,161 @@ 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) == '/')
+
+ if (!msg.empty() && 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->changeRecordingStatus(msg);
+ else if (command == "toggle")
+ {
+ if (msg.empty())
+ {
+ 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.empty())
+ {
+ 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.empty())
+ {
+ 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
+ */
+ 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 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.empty())
+ {
+ 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 (command == "me")
+ {
+ std::stringstream actionStr;
+ actionStr << "*" << msg << "*";
+ chatSend(player_node->getName(), actionStr.str());
}
- 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 +623,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 +649,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;
@@ -394,7 +667,7 @@ std::string ChatWindow::const_msg(CHATSKILL act)
msg += _("You cannot do that right now!");
break;
case RFAIL_ZENY:
- msg += _("Seems you need more Zeny... ;-)");
+ msg += _("Seems you need more GP... ;-)");
break;
case RFAIL_WEAPON:
msg += _("You cannot use this skill with that kind of weapon!");
@@ -412,8 +685,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 +724,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 +747,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(const std::string &item)
+{
+ std::ostringstream text;
+ text << "[" << item << "] ";
+ mChatInput->setText(mChatInput->getText() + text.str());
+ requestChatFocus();
+}
+
void ChatWindow::setVisible(bool isVisible)
{
Window::setVisible(isVisible);
@@ -484,70 +771,146 @@ 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.empty())
+ {
+ 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.empty())
{
chatLog(_("/announce: Global announcement (GM only)"), BY_SERVER);
chatLog(_("/clear: Clears this window"), BY_SERVER);
chatLog(_("/help: Display this help"), BY_SERVER);
- chatLog(_("/where: Display map name"), BY_SERVER);
- chatLog(_("/whisper <nick> <message>: Sends a private <message>"
- " to <nick>"), BY_SERVER);
+ chatLog(_("/me <message>: Tell something about yourself"), BY_SERVER);
+ chatLog(_("/msg <nick> <message>: Alternate form for /whisper"),
+ BY_SERVER);
+ chatLog(_("/party <command> <params>: Party commands"), BY_SERVER);
+ chatLog(_("/present: Get list of players present"), BY_SERVER);
+ chatLog(_("/record <filename>: Start recording the chat to an "
+ "external file"), BY_SERVER);
+ chatLog(_("/toggle: Determine whether <return> toggles the chat log"),
+ BY_SERVER);
chatLog(_("/w <nick> <message>: Short form for /whisper"), BY_SERVER);
+ chatLog(_("/where: Display map name"), BY_SERVER);
+ chatLog(_("/whisper <nick> <message>: Sends a private <message> "
+ "to <nick>"), 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 == "me")
+ {
+ chatLog(_("Command: /me <msg>"), BY_SERVER);
+ chatLog(_("This command tell others you are (doing) <msg>."),
+ BY_SERVER);
+ }
+ 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")
+ {
+ chatLog(_("Command: /record <filename>"), BY_SERVER);
+ chatLog(_("This command starts recording the chat log to the file "
+ "<filename>."), BY_SERVER);
+ chatLog(_("Command: /record"), BY_SERVER);
+ chatLog(_("This command finishes a recording session."), BY_SERVER);
+ }
+ 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..2fadb014 100644
--- a/src/gui/chat.h
+++ b/src/gui/chat.h
@@ -30,36 +30,23 @@
#include "window.h"
-#include "../guichanfwd.h"
-
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 5 // getting whispered at
+#define ACT_IS 6 // equivalent to "/me" on IRC
-#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 BY_LOGGER 7
/**
* gets in between usernick and message text depending on
@@ -127,14 +114,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 +178,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(const std::string &item);
+
/** Override to reset mTmpVisible */
void setVisible(bool visible);
@@ -199,6 +194,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 +210,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 +230,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..a4a50502 100644
--- a/src/gui/chatinput.h
+++ b/src/gui/chatinput.h
@@ -22,10 +22,10 @@
#ifndef CHATINPUT_H
#define CHATINPUT_H
-#include "textfield.h"
-
#include <guichan/focuslistener.hpp>
+#include "textfield.h"
+
/**
* The chat input hides when it loses focus. It is also invisible by default.
*/
diff --git a/src/gui/checkbox.cpp b/src/gui/checkbox.cpp
index b8fca2b8..511ed34c 100644
--- a/src/gui/checkbox.cpp
+++ b/src/gui/checkbox.cpp
@@ -21,12 +21,14 @@
#include "checkbox.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
int CheckBox::instances = 0;
+float CheckBox::mAlpha = config.getValue("guialpha", 0.8);
Image *CheckBox::checkBoxNormal;
Image *CheckBox::checkBoxChecked;
Image *CheckBox::checkBoxDisabled;
@@ -43,6 +45,13 @@ CheckBox::CheckBox(const std::string& caption, bool selected):
checkBoxChecked = checkBox->getSubImage(9, 0, 9, 10);
checkBoxDisabled = checkBox->getSubImage(18, 0, 9, 10);
checkBoxDisabledChecked = checkBox->getSubImage(27, 0, 9, 10);
+ if (config.getValue("opengl", 0))
+ {
+ checkBoxNormal->setAlpha(mAlpha);
+ checkBoxChecked->setAlpha(mAlpha);
+ checkBoxDisabled->setAlpha(mAlpha);
+ checkBoxDisabledChecked->setAlpha(mAlpha);
+ }
checkBox->decRef();
}
@@ -66,16 +75,26 @@ void CheckBox::drawBox(gcn::Graphics* graphics)
{
Image *box;
- if (isSelected()) {
- if (isEnabled()) {
+ if (isSelected())
+ {
+ if (isEnabled())
box = checkBoxChecked;
- } else {
+ else
box = checkBoxDisabledChecked;
- }
- } else if (isEnabled()) {
+ }
+ else if (isEnabled())
box = checkBoxNormal;
- } else {
+ else
box = checkBoxDisabled;
+
+ if (config.getValue("guialpha", 0.8) != mAlpha &&
+ config.getValue("opengl", 0))
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ checkBoxNormal->setAlpha(mAlpha);
+ checkBoxChecked->setAlpha(mAlpha);
+ checkBoxDisabled->setAlpha(mAlpha);
+ checkBoxDisabledChecked->setAlpha(mAlpha);
}
static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
diff --git a/src/gui/checkbox.h b/src/gui/checkbox.h
index 4b312d22..20adb43c 100644
--- a/src/gui/checkbox.h
+++ b/src/gui/checkbox.h
@@ -22,8 +22,6 @@
#ifndef CHECKBOX_H
#define CHECKBOX_H
-#include <iosfwd>
-
#include <guichan/widgets/checkbox.hpp>
class Image;
@@ -33,7 +31,8 @@ class Image;
*
* \ingroup GUI
*/
-class CheckBox : public gcn::CheckBox {
+class CheckBox : public gcn::CheckBox
+{
public:
/**
* Constructor.
@@ -52,6 +51,7 @@ class CheckBox : public gcn::CheckBox {
private:
static int instances;
+ static float mAlpha;
static Image *checkBoxNormal;
static Image *checkBoxChecked;
static Image *checkBoxDisabled;
diff --git a/src/gui/color.cpp b/src/gui/color.cpp
new file mode 100644
index 00000000..7a29025e
--- /dev/null
+++ b/src/gui/color.cpp
@@ -0,0 +1,146 @@
+/*
+ * Configurable text colors
+ * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
+ *
+ * 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 "color.h"
+
+#include "../configuration.h"
+
+#include "../utils/gettext.h"
+#include "../utils/tostring.h"
+
+Color::Color()
+{
+ addColor('C', 0x000000, _("Chat"));
+ addColor('G', 0xff0000, _("GM"));
+ addColor('H', 0xebc873, _("Highlight"));
+ addColor('Y', 0x1fa052, _("Player"));
+ addColor('W', 0x0000ff, _("Whisper"));
+ addColor('I', 0xa08527, _("Is"));
+ addColor('P', 0xff00d8, _("Party"));
+ addColor('S', 0x8415e2, _("Server"));
+ addColor('L', 0x919191, _("Logger"));
+ addColor('<', 0xe50d0d, _("Hyperlink"));
+ commit();
+}
+
+Color::~Color()
+{
+ for (ColVector::iterator col = mColVector.begin(),
+ colEnd = mColVector.end();
+ col != colEnd;
+ ++col)
+ {
+ config.setValue("color" + col->text, toString(col->rgb));
+ }
+}
+
+void Color::setColor(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 Color::getColor(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 Color::getElementAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return mColVector[i].text;
+}
+
+char Color::getColorCharAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return 'C';
+ }
+ return mColVector[i].ch;
+}
+
+void Color::addColor(const char c, const int rgb, const std::string &text)
+{
+ int trueRgb = (int)config.getValue("color" + text, rgb);
+ mColVector.push_back(colorElem(c, trueRgb, text));
+}
+
+int Color::getColorAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return 0;
+ }
+ return mColVector[i].rgb;
+}
+
+void Color::setColorAt(int i, int rgb)
+{
+ if (i >= 0 && i < getNumberOfElements())
+ {
+ mColVector[i].rgb = rgb;
+ }
+}
+
+void Color::commit()
+{
+ for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
+ i != iEnd;
+ ++i)
+ {
+ i->committedRgb = i->rgb;
+ }
+}
+
+void Color::rollback()
+{
+ for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
+ i != iEnd;
+ ++i)
+ {
+ i->rgb = i->committedRgb;
+ }
+}
diff --git a/src/gui/color.h b/src/gui/color.h
new file mode 100644
index 00000000..509448e7
--- /dev/null
+++ b/src/gui/color.h
@@ -0,0 +1,136 @@
+/*
+ * Configurable text colors
+ * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
+ *
+ * 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
+ */
+
+#ifndef COLOUR_H
+#define COLOUR_H
+
+#include <string>
+#include <vector>
+
+#include <guichan/listmodel.hpp>
+
+class Color : public gcn::ListModel
+{
+ public:
+ /**
+ * Constructor
+ */
+ Color();
+
+ /**
+ * Destructor
+ */
+ ~Color();
+
+ /**
+ * Define the color replacement for a character
+ *
+ * @param c charater to be replaced
+ * @param rgb color to replace character
+ */
+ void setColor(const char c, const int rgb);
+
+ /**
+ * Define the color replacement for a character
+ *
+ * @param c character to be replaced
+ * @param r red component
+ * @param g green component
+ * @param b blue component
+ */
+ void setColor(const char c, const int r, const int g, const int b)
+ {
+ setColor(c, (r << 16) | (g << 8) | b);
+ }
+
+ /**
+ * Return the color associated with a character, if exists
+ *
+ * @param c character requested
+ * @param valid indicate whether character is known
+ */
+ int getColor(const char c, bool &valid) const;
+
+ /**
+ * Return the number of colors known
+ */
+ int getNumberOfElements() {return mColVector.size(); }
+
+ /**
+ * Return the name of the ith color
+ *
+ * @param i index of color interested in
+ */
+ std::string getElementAt(int i);
+
+ /**
+ * Get the color for the element at index i in the current color
+ * model
+ */
+ int getColorAt(int i);
+
+ /**
+ * Get the character used by the color for the element at index i in
+ * the current color model
+ */
+ char getColorCharAt(int i);
+
+ /**
+ * Set the color for the element at index i
+ */
+ void setColorAt(int i, int rgb);
+
+ /**
+ * Commit the colors
+ */
+ void commit();
+
+ /**
+ * Rollback the colors
+ */
+ void rollback();
+
+ private:
+ struct colorElem
+ {
+ colorElem(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<colorElem> ColVector;
+ ColVector mColVector;
+
+ /**
+ * Initialise color
+ *
+ * @param c character that needs initialising
+ * @param rgb default color if not found in config
+ * @param text identifier of color
+ */
+ void addColor(const char c, const int rgb, const std::string &text);
+};
+
+extern Color *textColor;
+
+#endif
diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp
index 46b7c971..38697f3a 100644
--- a/src/gui/confirm_dialog.cpp
+++ b/src/gui/confirm_dialog.cpp
@@ -19,11 +19,12 @@
* 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 "scrollarea.h"
+#include "textbox.h"
#include "../utils/gettext.h"
@@ -31,32 +32,55 @@ 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->setTextWrapped(msg, 260);
+
+ 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);
- if (getParent()) {
+ if (getParent())
+ {
setLocationRelativeTo(getParent());
getParent()->moveToTop(this);
}
@@ -64,6 +88,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..3fa2b90d 100644
--- a/src/gui/confirm_dialog.h
+++ b/src/gui/confirm_dialog.h
@@ -26,13 +26,16 @@
#include "window.h"
+class ScrollArea;
+class TextBox;
/**
* An option dialog.
*
* \ingroup GUI
*/
-class ConfirmDialog : public Window, public gcn::ActionListener {
+class ConfirmDialog : public Window, public gcn::ActionListener
+{
public:
/**
* Constructor.
@@ -42,10 +45,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..a69698e9 100644
--- a/src/gui/connection.cpp
+++ b/src/gui/connection.cpp
@@ -19,20 +19,20 @@
* 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"
#include "../utils/gettext.h"
-namespace {
+namespace
+{
struct ConnectionActionListener : public gcn::ActionListener
{
void action(const gcn::ActionEvent &event) { state = EXIT_STATE; }
@@ -63,10 +63,10 @@ ConnectionDialog::ConnectionDialog():
void ConnectionDialog::logic()
{
mProgress += 0.005f;
+
if (mProgress > 1.0f)
- {
mProgress = 0.0f;
- }
+
mProgressBar->setProgress(mProgress);
Window::logic();
}
diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp
index 669aabd2..5a5acfad 100644
--- a/src/gui/debugwindow.cpp
+++ b/src/gui/debugwindow.cpp
@@ -19,14 +19,11 @@
* 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 "gui.h"
+#include "debugwindow.h"
#include "viewport.h"
#include "widgets/layout.h"
diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h
index 00119d15..e089de27 100644
--- a/src/gui/debugwindow.h
+++ b/src/gui/debugwindow.h
@@ -22,14 +22,10 @@
#ifndef DEBUGWINDOW_H
#define DEBUGWINDOW_H
-#include <iosfwd>
-
#include <guichan/actionlistener.hpp>
#include "window.h"
-#include "../guichanfwd.h"
-
/**
* The debug window.
*
diff --git a/src/gui/emotecontainer.cpp b/src/gui/emotecontainer.cpp
new file mode 100644
index 00000000..94ce9736
--- /dev/null
+++ b/src/gui/emotecontainer.cpp
@@ -0,0 +1,172 @@
+/*
+ * Extended support for activating emotes
+ * Copyright (C) 2009 Aethyra 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 <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..fefce793
--- /dev/null
+++ b/src/gui/emotecontainer.h
@@ -0,0 +1,136 @@
+/*
+ * Extended support for activating emotes
+ * Copyright (C) 2009 Aethyra 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
+ */
+
+#ifndef EMOTECONTAINER_H
+#define EMOTECONTAINER_H
+
+#include <list>
+#include <vector>
+
+#include <guichan/mouselistener.hpp>
+#include <guichan/widget.hpp>
+#include <guichan/widgetlistener.hpp>
+
+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..b66592c1
--- /dev/null
+++ b/src/gui/emoteshortcutcontainer.cpp
@@ -0,0 +1,204 @@
+/*
+ * Extended support for activating emotes
+ * Copyright (C) 2009 Aethyra 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 "emoteshortcutcontainer.h"
+
+#include "../animatedsprite.h"
+#include "../configuration.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():
+ ShortcutContainer(),
+ mEmoteClicked(false),
+ mEmoteMoved(0)
+{
+ addMouseListener(this);
+ addWidgetListener(this);
+
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png");
+
+ mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8));
+
+ // 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);
+ }
+ }
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ mBackgroundImg->setAlpha(mAlpha);
+ }
+}
+
+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..d32a9f79
--- /dev/null
+++ b/src/gui/emoteshortcutcontainer.h
@@ -0,0 +1,77 @@
+/*
+ * Extended support for activating emotes
+ * Copyright (C) 2009 Aethyra 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
+ */
+
+#ifndef EMOTESHORTCUTCONTAINER_H
+#define EMOTESHORTCUTCONTAINER_H
+
+#include <vector>
+
+#include "shortcutcontainer.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..f4a8999a
--- /dev/null
+++ b/src/gui/emotewindow.cpp
@@ -0,0 +1,77 @@
+/*
+ * Extended support for activating emotes
+ * Copyright (C) 2009 Aethyra 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 "button.h"
+#include "gui.h"
+#include "emotewindow.h"
+#include "emotecontainer.h"
+#include "scrollarea.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/buddywindow.h b/src/gui/emotewindow.h
index 4eed3a2c..8af24a7b 100644
--- a/src/gui/buddywindow.h
+++ b/src/gui/emotewindow.h
@@ -1,6 +1,6 @@
/*
- * The Mana World
- * Copyright (C) 2004 The Mana World Development Team
+ * Extended support for activating emotes
+ * Copyright (C) 2009 Aethyra Development Team
*
* This file is part of The Mana World.
*
@@ -19,38 +19,48 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef BUDDYWINDOW_H
-#define BUDDYWINDOW_H
+#ifndef EMOTEWINDOW_H
+#define EMOTEWINDOW_H
#include <guichan/actionlistener.hpp>
+#include <guichan/selectionlistener.hpp>
#include "window.h"
-#include "../guichanfwd.h"
-
-class BuddyList;
+class EmoteContainer;
+class TextBox;
/**
- * Window showing buddy list.
+ * Emote dialog.
*
* \ingroup Interface
*/
-class BuddyWindow : public Window, public gcn::ActionListener
+class EmoteWindow : public Window, gcn::ActionListener,
+ gcn::SelectionListener
{
public:
/**
* Constructor.
*/
- BuddyWindow();
+ EmoteWindow();
/**
- * Performs action.
+ * Called when receiving actions from the widgets.
*/
void action(const gcn::ActionEvent &event);
+ /**
+ * Returns the selected item.
+ */
+ int getSelectedEmote() const;
+
private:
- BuddyList *mBuddyList;
- gcn::ListBox *mListbox;
+ EmoteContainer *mEmotes;
+
+ gcn::Button *mUseButton;
+ gcn::ScrollArea *mEmoteScroll;
};
-#endif /* BUDDYWINDOW_H */
+extern EmoteWindow *emoteWindow;
+
+#endif
diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp
index aa6825f2..a2be6b00 100644
--- a/src/gui/equipmentwindow.cpp
+++ b/src/gui/equipmentwindow.cpp
@@ -19,14 +19,22 @@
* 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 "itempopup.h"
+#include "playerbox.h"
+#include "viewport.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 +42,60 @@
#include "../utils/gettext.h"
#include "../utils/tostring.h"
-EquipmentWindow::EquipmentWindow(Equipment *equipment):
+// 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():
Window(_("Equipment")),
- mEquipment(equipment)
+ mSelected(-1)
{
+ mItemPopup = new ItemPopup();
+
+ // 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();
+ }
+
+ mEquipment = player_node->mEquipment.get();
mInventory = player_node->getInventory();
}
EquipmentWindow::~EquipmentWindow()
{
+ delete mUnequip;
+ delete mItemPopup;
+ delete mPlayerBox;
}
void EquipmentWindow::draw(gcn::Graphics *graphics)
@@ -54,37 +103,148 @@ 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)
{
- static_cast<Graphics*>(graphics)->drawImage(
- image, 36 * (i % 4) + 10, 36 * (i / 4) + 25);
+ // Set color red.
+ g->setColor(gcn::Color(255, 0, 0));
}
+ else
+ {
+ // 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));
}
+}
- graphics->drawRectangle(gcn::Rectangle(160, 25, 32, 32));
+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;
+ }
+}
- if (!(item = mInventory->getItem(mEquipment->getArrows())))
- return;
+Item* EquipmentWindow::getItem(const int &x, const int &y)
+{
+ for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
+ {
+ gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY,
+ BOX_WIDTH, BOX_HEIGHT);
- image = item->getImage();
- if (image)
+ if (tRect.isPointInRect(x, y))
+ {
+ return (i != EQUIP_AMMO_SLOT) ?
+ mInventory->getItem(mEquipment->getEquipment(i)) :
+ mInventory->getItem(mEquipment->getArrows());
+ }
+ }
+ return NULL;
+}
+
+void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent)
+{
+ Window::mousePressed(mouseEvent);
+
+ const int x = mouseEvent.getX();
+ const int y = mouseEvent.getY();
+
+ Item* item;
+
+ if (mouseEvent.getButton() == gcn::MouseEvent::LEFT)
+ {
+ // Checks if any of the presses were in the equip boxes.
+ for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++)
+ {
+ 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;
+ }
+ }
+ }
+ }
+ else if (mouseEvent.getButton() == gcn::MouseEvent::RIGHT)
+ {
+ item = getItem(x, y);
+
+ if (!item)
+ return;
+
+ /* Convert relative to the window coordinates to absolute screen
+ * coordinates.
+ */
+ const int mx = x + getX();
+ const int my = y + getY();
+ viewport->showPopup(mx, my, item);
+ }
+}
+
+// Show ItemTooltip
+void EquipmentWindow::mouseMoved(gcn::MouseEvent &event)
+{
+ const int x = event.getX();
+ const int y = event.getY();
+
+ Item* item = getItem(x, y);
+
+ if (item)
+ {
+ int mouseX, mouseY;
+ SDL_GetMouseState(&mouseX, &mouseY);
+
+ mItemPopup->setItem(item->getInfo());
+ mItemPopup->setOpaque(false);
+ mItemPopup->view(x + getX(), y + getY());
+ }
+ else
{
- static_cast<Graphics*>(graphics)->drawImage(image, 160, 25);
+ mItemPopup->setVisible(false);
}
- graphics->drawText(toString(item->getQuantity()), 170, 62,
- gcn::Graphics::CENTER);
+}
+
+// Hide ItemTooltip
+void EquipmentWindow::mouseExited(gcn::MouseEvent &event)
+{
+ mItemPopup->setVisible(false);
}
diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h
index e2420134..c491062a 100644
--- a/src/gui/equipmentwindow.h
+++ b/src/gui/equipmentwindow.h
@@ -22,23 +22,37 @@
#ifndef EQUIPMENTWINDOW_H
#define EQUIPMENTWINDOW_H
+#include <guichan/actionlistener.hpp>
+
#include "window.h"
-#include "../inventory.h"
class Equipment;
+class Inventory;
+class Item;
+class ItemPopup;
+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:
/**
* Constructor.
*/
- EquipmentWindow(Equipment *equipment);
+ EquipmentWindow();
/**
* Destructor.
@@ -50,9 +64,43 @@ 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:
+ void mouseExited(gcn::MouseEvent &event);
+ void mouseMoved(gcn::MouseEvent &event);
+
+ Item* getItem(const int &x, const int &y);
+
Equipment *mEquipment;
Inventory *mInventory;
+ gcn::Button *mUnequip; /**< Button for unequipping. */
+ EquipBox mEquipBox[EQUIP_VECTOREND]; /**< Equipment Boxes. */
+
+ ItemPopup *mItemPopup;
+
+ 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..b9cfd789 100644
--- a/src/gui/focushandler.cpp
+++ b/src/gui/focushandler.cpp
@@ -21,13 +21,12 @@
#include "focushandler.h"
-
void FocusHandler::requestModalFocus(gcn::Widget *widget)
{
/* If there is another widget with modal focus, remove its modal focus
* and put it on the modal widget stack.
*/
- if (mModalFocusedWidget != NULL && mModalFocusedWidget != widget)
+ if (mModalFocusedWidget && mModalFocusedWidget != widget)
{
mModalStack.push_front(mModalFocusedWidget);
mModalFocusedWidget = NULL;
diff --git a/src/gui/focushandler.h b/src/gui/focushandler.h
index 124b5472..b0639bd8 100644
--- a/src/gui/focushandler.h
+++ b/src/gui/focushandler.h
@@ -26,8 +26,6 @@
#include <guichan/focushandler.hpp>
-#include "../guichanfwd.h"
-
/**
* The focus handler. This focus handler does exactly the same as the Guichan
* focus handler, but keeps a stack of modal widgets to be able to handle
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index 2da451a3..a7946993 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:
@@ -61,7 +63,8 @@ class GuiConfigListener : public ConfigListener
void optionChanged(const std::string &name)
{
- if (name == "customcursor") {
+ if (name == "customcursor")
+ {
bool bCustomCursor = config.getValue("customcursor", 1) == 1;
mGui->setUseCustomCursor(bCustomCursor);
}
@@ -105,8 +108,9 @@ Gui::Gui(Graphics *graphics):
// Set global font
std::string path = resman->getPath("fonts/dejavusans.ttf");
- try {
- const int fontSize = config.getValue("fontSize", 11);
+ try
+ {
+ const int fontSize = (int)config.getValue("fontSize", 11);
mGuiFont = new TrueTypeFont(path, fontSize);
}
catch (gcn::Exception e)
@@ -115,14 +119,28 @@ Gui::Gui(Graphics *graphics):
+ e.getMessage());
}
+ // Set bold font
+ path = resman->getPath("fonts/dejavusans-bold.ttf");
+ try
+ {
+ const int fontSize = (int)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 {
+ // Load hits' colorful 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 +176,7 @@ Gui::~Gui()
mMouseCursors->decRef();
delete mGuiFont;
+ delete boldFont;
delete viewport;
delete getTop();
@@ -167,12 +186,13 @@ Gui::~Gui()
void Gui::logic()
{
// Fade out mouse cursor after extended inactivity
- if (mMouseInactivityTimer < 100 * 15) {
+ if (mMouseInactivityTimer < 100 * 15)
+ {
++mMouseInactivityTimer;
mMouseCursorAlpha = std::min(1.0f, mMouseCursorAlpha + 0.05f);
- } else {
- mMouseCursorAlpha = std::max(0.0f, mMouseCursorAlpha - 0.005f);
}
+ else
+ mMouseCursorAlpha = std::max(0.0f, mMouseCursorAlpha - 0.005f);
gcn::Gui::logic();
}
@@ -217,9 +237,8 @@ void Gui::setUseCustomCursor(bool customCursor)
mMouseCursors =
resman->getImageSet("graphics/gui/mouse.png", 40, 40);
- if (!mMouseCursors) {
+ if (!mMouseCursors)
logger->error("Unable to load mouse cursors.");
- }
}
else
{
@@ -227,7 +246,8 @@ void Gui::setUseCustomCursor(bool customCursor)
SDL_ShowCursor(SDL_ENABLE);
// Unload the mouse cursor
- if (mMouseCursors) {
+ if (mMouseCursors)
+ {
mMouseCursors->decRef();
mMouseCursors = NULL;
}
diff --git a/src/gui/gui.h b/src/gui/gui.h
index 95cd5815..5c0c24f7 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;
@@ -115,7 +115,6 @@ class Gui : public gcn::Gui
};
extern Gui *gui; /**< The GUI system */
-extern Viewport *viewport; /**< The viewport */
extern SDLInput *guiInput; /**< GUI input */
/**
@@ -125,4 +124,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..ece2dce4 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"
@@ -32,8 +33,11 @@
HelpWindow::HelpWindow():
Window(_("Help"))
{
+ setMinWidth(300);
+ setMinHeight(250);
setContentSize(455, 350);
- setWindowName("Help");
+ setWindowName(_("Help"));
+ setResizable(true);
mBrowserBox = new BrowserBox();
mBrowserBox->setOpaque(false);
@@ -48,8 +52,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..98e3aa67 100644
--- a/src/gui/help.h
+++ b/src/gui/help.h
@@ -24,10 +24,8 @@
#include <guichan/actionlistener.hpp>
-#include "window.h"
#include "linkhandler.h"
-
-#include "../guichanfwd.h"
+#include "window.h"
class BrowserBox;
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..add78084 100644
--- a/src/gui/inttextfield.h
+++ b/src/gui/inttextfield.h
@@ -58,8 +58,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..af3b29a2 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -19,72 +19,101 @@
* 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 "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() + 280);
+
+ place(0, 0, mWeightLabel).setPadding(3);
+ place(1, 0, mWeightBar, 3);
+ place(4, 0, mSlotsLabel).setPadding(3);
+ place(5, 0, mSlotsBar, 2);
+ place(0, 1, mInvenScroll, 7, 4);
+ place(5, 5, mDropButton);
+ place(6, 5, mUseButton);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, mDropButton->getHeight());
loadWindowState();
+ setLocationRelativeTo(getParent());
+}
+
+InventoryWindow::~InventoryWindow()
+{
+ delete mWeightBar;
+ delete mSlotsBar;
+ delete mUseButton;
+ delete mDropButton;
+ delete mItems;
+ delete mWeightLabel;
+ delete mSlotsLabel;
+ delete mInvenScroll;
}
void InventoryWindow::logic()
@@ -95,15 +124,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 +166,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 +210,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..78d30461 100644
--- a/src/gui/inventorywindow.h
+++ b/src/gui/inventorywindow.h
@@ -27,10 +27,12 @@
#include "window.h"
-#include "../guichanfwd.h"
+#include "../localplayer.h"
class Item;
class ItemContainer;
+class ProgressBar;
+class TextBox;
/**
* Inventory dialog.
@@ -38,13 +40,18 @@ class ItemContainer;
* \ingroup Interface
*/
class InventoryWindow : public Window, gcn::ActionListener,
- gcn::SelectionListener
+ gcn::SelectionListener
{
public:
/**
* Constructor.
*/
- InventoryWindow();
+ InventoryWindow(int invSize = (INVENTORY_SIZE - 2));
+
+ /**
+ * Destructor.
+ */
+ ~InventoryWindow();
/**
* Logic (updates buttons and weight information).
@@ -61,30 +68,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..92be3d6e 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"
@@ -71,7 +70,8 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item):
resetAmount();
- switch (usage) {
+ switch (usage)
+ {
case AMOUNT_TRADE_ADD:
setCaption(_("Select amount of items to trade."));
okButton->setActionEventId("AddTrade");
diff --git a/src/gui/item_amount.h b/src/gui/item_amount.h
index d8eedadb..618d7d51 100644
--- a/src/gui/item_amount.h
+++ b/src/gui/item_amount.h
@@ -22,14 +22,10 @@
#ifndef ITEM_AMOUNT_WINDOW_H
#define ITEM_AMOUNT_WINDOW_H
-#include <iosfwd>
-
#include <guichan/actionlistener.hpp>
#include "window.h"
-#include "../guichanfwd.h"
-
class IntTextField;
class Item;
diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp
index a0885279..0beb5cfb 100644
--- a/src/gui/itemcontainer.cpp
+++ b/src/gui/itemcontainer.cpp
@@ -21,17 +21,21 @@
#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"
-#include "../resources/iteminfo.h"
#include "../resources/resourcemanager.h"
#include "../utils/tostring.h"
@@ -41,11 +45,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");
@@ -60,6 +67,7 @@ ItemContainer::ItemContainer(Inventory *inventory):
ItemContainer::~ItemContainer()
{
mSelImg->decRef();
+ delete mItemPopup;
}
void ItemContainer::logic()
@@ -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);
@@ -115,6 +124,7 @@ void ItemContainer::draw(gcn::Graphics *graphics)
}
// Draw item caption
+ graphics->setFont(getFont());
graphics->setColor(gcn::Color(0, 0, 0));
graphics->drawText(
(item->isEquipped() ? "Eq." : toString(item->getQuantity())),
@@ -138,6 +148,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 +170,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 +181,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 +191,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 +232,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 +250,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..71fcc5d0 100644
--- a/src/gui/itemcontainer.h
+++ b/src/gui/itemcontainer.h
@@ -22,15 +22,16 @@
#ifndef ITEMCONTAINER_H
#define ITEMCONTAINER_H
+#include <list>
+
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
#include <guichan/widgetlistener.hpp>
-#include <list>
-
class Image;
class Inventory;
class Item;
+class ItemPopup;
namespace gcn {
class SelectionListener;
@@ -41,14 +42,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 +106,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 +130,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..97c0b94f
--- /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 <sstream>
+#include <string>
+
+#include <SDL_mouse.h>
+
+#include "itemlinkhandler.h"
+#include "itempopup.h"
+
+#include "../resources/iteminfo.h"
+#include "../resources/itemdb.h"
+
+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..4c117f0a
--- /dev/null
+++ b/src/gui/itempopup.cpp
@@ -0,0 +1,216 @@
+/*
+ * 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 "scrollarea.h"
+#include "textbox.h"
+#include "windowcontainer.h"
+
+#include "widgets/layout.h"
+
+#include "../resources/iteminfo.h"
+
+#include "../utils/gettext.h"
+#include "../utils/tostring.h"
+
+ItemPopup::ItemPopup():
+ Window()
+{
+ setResizable(false);
+ setShowTitle(false);
+ setTitleBarHeight(0);
+
+ // Item Name
+ mItemName = new gcn::Label("Label");
+ mItemName->setFont(boldFont);
+ mItemName->setPosition(2, 2);
+
+ // Item Description
+ mItemDesc = new TextBox();
+ mItemDesc->setEditable(false);
+ 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);
+ 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);
+ 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());
+}
+
+ItemPopup::~ItemPopup()
+{
+ delete mItemName;
+ delete mItemDesc;
+ delete mItemDescScroll;
+ delete mItemEffect;
+ delete mItemEffectScroll;
+ delete mItemWeight;
+ delete mItemWeightScroll;
+}
+
+void ItemPopup::setItem(const ItemInfo &item)
+{
+ mItemName->setCaption(item.getName());
+ mItemName->setForegroundColor(getColor(item.getType()));
+ mItemName->setWidth(boldFont->getWidth(item.getName()));
+ mItemDesc->setTextWrapped(item.getDescription(), 196);
+ mItemEffect->setTextWrapped(item.getEffect(), 196);
+ mItemWeight->setTextWrapped(_("Weight: ") + toString(item.getWeight()) +
+ _(" grams"), 196);
+
+ int minWidth = mItemName->getWidth();
+
+ if (mItemDesc->getMinWidth() > minWidth)
+ minWidth = mItemDesc->getMinWidth();
+ if (mItemEffect->getMinWidth() > minWidth)
+ minWidth = mItemEffect->getMinWidth();
+ if (mItemWeight->getMinWidth() > minWidth)
+ minWidth = mItemWeight->getMinWidth();
+
+ minWidth += 8;
+ setWidth(minWidth);
+
+ int numRowsDesc = mItemDesc->getNumberOfRows();
+ int numRowsEffect = mItemEffect->getNumberOfRows();
+ int numRowsWeight = mItemWeight->getNumberOfRows();
+
+ mItemDescScroll->setDimension(gcn::Rectangle(2, 0, minWidth,
+ numRowsDesc * getFont()->getHeight()));
+
+ mItemEffectScroll->setDimension(gcn::Rectangle(2, 0, minWidth,
+ numRowsEffect * getFont()->getHeight()));
+
+ mItemWeightScroll->setDimension(gcn::Rectangle(2, 0, minWidth,
+ numRowsWeight * getFont()->getHeight()));
+
+ if (item.getEffect().empty())
+ {
+ setContentSize(minWidth, (numRowsDesc * getFont()->getHeight() +
+ (3 * getFont()->getHeight())));
+
+ mItemWeightScroll->setPosition(2,
+ (numRowsDesc * getFont()->getHeight()) +
+ (2 * getFont()->getHeight()));
+ }
+ else
+ {
+ setContentSize(minWidth, (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()));
+}
+
+gcn::Color ItemPopup::getColor(const std::string& type)
+{
+ gcn::Color color;
+
+ if (type.compare("generic") == 0)
+ color = 0x21a5b1;
+ else if (type.compare("equip-head") == 0)
+ color = 0x527fa4;
+ else if (type.compare("usable") == 0)
+ color = 0x268d24;
+ else if (type.compare("equip-torso") == 0)
+ color = 0xd12aa4;
+ else if (type.compare("equip-1hand") == 0)
+ color = 0xf42a2a;
+ else if (type.compare("equip-legs") == 0)
+ color = 0x699900;
+ else if (type.compare("equip-feet") == 0)
+ color = 0xaa1d48;
+ else if (type.compare("equip-2hand") == 0)
+ color = 0xf46d0e;
+ else if (type.compare("equip-shield") == 0)
+ color = 0x9c2424;
+ else if (type.compare("equip-ring") == 0)
+ color = 0x0000ff;
+ else if (type.compare("equip-arms") == 0)
+ color = 0x9c24e8;
+ else if (type.compare("equip-ammo") == 0)
+ color = 0x8b6311;
+ else
+ color = 0x000000;
+
+ return color;
+}
+
+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() - 10) < 0)
+ y = 0;
+ else
+ y = y - getHeight() - 10;
+ setPosition(x, y);
+ setVisible(true);
+ requestMoveToTop();
+}
diff --git a/src/gui/itempopup.h b/src/gui/itempopup.h
new file mode 100644
index 00000000..c820e3a0
--- /dev/null
+++ b/src/gui/itempopup.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ *
+ * 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 ITEMPOPUP_H
+#define ITEMPOPUP_H
+
+#include "window.h"
+
+class ItemInfo;
+class ScrollArea;
+class TextBox;
+
+class ItemPopup : public Window
+{
+ public:
+ ItemPopup();
+ ~ItemPopup();
+
+ void setItem(const ItemInfo &item);
+ unsigned int getNumRows();
+ void view(int x, int y);
+
+ private:
+ gcn::Label *mItemName;
+ TextBox *mItemDesc;
+ TextBox *mItemEffect;
+ TextBox *mItemWeight;
+ ScrollArea *mItemDescScroll;
+ ScrollArea *mItemEffectScroll;
+ ScrollArea *mItemWeightScroll;
+
+ gcn::Color getColor(const std::string& type);
+};
+
+#endif // ITEMPOPUP_H
diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp
index b2f70348..42e3b853 100644
--- a/src/gui/itemshortcutcontainer.cpp
+++ b/src/gui/itemshortcutcontainer.cpp
@@ -18,15 +18,19 @@
* 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 "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,30 +38,33 @@
#include "../utils/tostring.h"
ItemShortcutContainer::ItemShortcutContainer():
- mGridWidth(1),
- mGridHeight(1),
+ ShortcutContainer(),
mItemClicked(false),
mItemMoved(NULL)
{
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()
{
mBackgroundImg->decRef();
+ delete mItemPopup;
}
-void
-ItemShortcutContainer::logic()
+void ItemShortcutContainer::logic()
{
gcn::Widget::logic();
@@ -70,8 +77,7 @@ ItemShortcutContainer::logic()
}
}
-void
-ItemShortcutContainer::draw(gcn::Graphics *graphics)
+void ItemShortcutContainer::draw(gcn::Graphics *graphics)
{
Graphics *g = static_cast<Graphics*>(graphics);
@@ -87,7 +93,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 +104,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 =
@@ -127,37 +136,30 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics)
gcn::Graphics::CENTER);
}
}
-}
-void ItemShortcutContainer::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;
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8));
}
}
-void
-ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
+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 +173,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 +230,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..22d94ec2 100644
--- a/src/gui/itemshortcutcontainer.h
+++ b/src/gui/itemshortcutcontainer.h
@@ -23,20 +23,19 @@
#define ITEMSHORTCUTCONTAINER_H
#include <guichan/mouselistener.hpp>
-#include <guichan/widget.hpp>
-#include <guichan/widgetlistener.hpp>
+
+#include "shortcutcontainer.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 +59,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 +73,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;
+ void mouseExited(gcn::MouseEvent &event);
+ void mouseMoved(gcn::MouseEvent &event);
- Image *mBackgroundImg;
-
- 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..74d0b9ad 100644
--- a/src/gui/listbox.cpp
+++ b/src/gui/listbox.cpp
@@ -19,12 +19,16 @@
* 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 "color.h"
+#include "listbox.h"
+
+#include "../configuration.h"
+
+float ListBox::mAlpha = config.getValue("guialpha", 0.8);
ListBox::ListBox(gcn::ListModel *listModel):
gcn::ListBox(listModel)
@@ -36,29 +40,35 @@ void ListBox::draw(gcn::Graphics *graphics)
if (!mListModel)
return;
- graphics->setColor(gcn::Color(110, 160, 255));
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ mAlpha = config.getValue("guialpha", 0.8);
+
+ bool valid;
+ const int red = (textColor->getColor('H', valid) >> 16) & 0xFF;
+ const int green = (textColor->getColor('H', valid) >> 8) & 0xFF;
+ const int blue = textColor->getColor('H', valid) & 0xFF;
+ const int alpha = (int)(mAlpha * 255.0f);
+
+ graphics->setColor(gcn::Color(red, green, blue, alpha));
graphics->setFont(getFont());
- int fontHeight = getFont()->getHeight();
+ const int fontHeight = getFont()->getHeight();
// Draw rectangle below the selected list element
- if (mSelected >= 0) {
+ if (mSelected >= 0)
graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected,
getWidth(), fontHeight));
- }
// Draw the list elements
- graphics->setColor(gcn::Color(0, 0, 0));
- for (int i = 0, y = 0;
- i < mListModel->getNumberOfElements();
+ graphics->setColor(gcn::Color(0, 0, 0, 255));
+ for (int i = 0, y = 0; i < mListModel->getNumberOfElements();
++i, y += fontHeight)
{
graphics->drawText(mListModel->getElementAt(i), 1, y);
}
}
-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..12fcb955 100644
--- a/src/gui/listbox.h
+++ b/src/gui/listbox.h
@@ -47,6 +47,9 @@ class ListBox : public gcn::ListBox
void draw(gcn::Graphics *graphics);
void mouseDragged(gcn::MouseEvent &event);
+
+ private:
+ static float mAlpha;
};
#endif
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index 2b87f6df..90ceab1a 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 <guichan/widgets/label.hpp>
-#include "../main.h"
-#include "../logindata.h"
-
#include "button.h"
#include "checkbox.h"
+#include "listbox.h"
+#include "login.h"
#include "ok_dialog.h"
#include "passwordfield.h"
+#include "scrollarea.h"
#include "textfield.h"
+#include "widgets/dropdown.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,62 @@ 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");
+ std::vector<std::string> dfltPort;
+ dfltPort.push_back("6901");
+ mServerList = new DropDownList("MostRecent00", dfltServer, dfltPort,
+ MAX_SERVER_LIST_SIZE);
+ mServerListBox = new 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);
+ mServerDropDown->setOpaque(false);
+
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 +123,9 @@ LoginDialog::LoginDialog(LoginData *loginData):
LoginDialog::~LoginDialog()
{
+ delete mServerList;
+ delete mServerListBox;
+ delete mServerScrollArea;
}
void LoginDialog::action(const gcn::ActionEvent &event)
@@ -97,6 +133,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 +141,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 +158,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 +183,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.empty())
+ {
+ 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.empty())
+ {
+ 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.empty()) // 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.empty())
+ {
+ mServers.push_back(server);
+ mPorts.push_back(port);
+ }
+ }
+ if (mServers.empty())
+ {
+ 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..c0d6e755 100644
--- a/src/gui/login.h
+++ b/src/gui/login.h
@@ -22,14 +22,18 @@
#ifndef LOGIN_H
#define LOGIN_H
-#include <iosfwd>
+#include <string>
+#include <vector>
+
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
+#include <guichan/listmodel.hpp>
#include "window.h"
-#include "../guichanfwd.h"
+class DropDown;
class LoginData;
+class ScrollArea;
/**
* The login dialog.
@@ -67,18 +71,65 @@ 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;
+ gcn::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/menuwindow.h b/src/gui/menuwindow.h
index 9b784c35..9bb54e29 100644
--- a/src/gui/menuwindow.h
+++ b/src/gui/menuwindow.h
@@ -24,8 +24,6 @@
#include "window.h"
-#include "../guichanfwd.h"
-
/**
* The Button Menu.
*
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index f5c0c1e6..ccadf3e1 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,12 +33,18 @@
#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() + "Show", true);
setDefaultSize(5, 25, 100, 100);
+ setResizable(true);
+
loadWindowState();
}
@@ -43,6 +52,8 @@ Minimap::~Minimap()
{
if (mMapImage)
mMapImage->decRef();
+
+ config.setValue(getWindowName() + "Show", mShow);
}
void Minimap::setMapImage(Image *img)
@@ -53,13 +64,59 @@ 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() > titleWidth ?
+ mMapImage->getWidth() + offsetX : titleWidth);
+ setMaxHeight(mMapImage->getHeight() + offsetY);
+
+ // Make sure the window is within the minimum and maximum boundaries
+ // TODO: Shouldn't this be happening automatically within the Window
+ // class?
+ if (getMinWidth() > getWidth())
+ setWidth(getMinWidth());
+ else if (getMaxWidth() < getWidth())
+ setWidth(getMaxWidth());
+ if (getMinHeight() > getHeight())
+ setHeight(getMinHeight());
+ else if (getMaxHeight() < getHeight())
+ setHeight(getMaxHeight());
+
+ setContentSize(getWidth() - offsetX, getHeight() - offsetY);
+ setDefaultSize(getX(), getY(), getWidth(), getHeight());
+ resetToDefaultSize();
+
+ setVisible(mShow);
+ }
+ else
+ {
+ setVisible(false);
+ }
+}
+
+void Minimap::toggle()
+{
+ mShow = !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 +129,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 +144,7 @@ void Minimap::draw(gcn::Graphics *graphics)
if (mapOriginY > 0)
mapOriginY = 0;
}
+
static_cast<Graphics*>(graphics)->
drawImage(mMapImage, mapOriginX, mapOriginY);
}
@@ -122,10 +180,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..3ce0aacd 100644
--- a/src/gui/minimap.h
+++ b/src/gui/minimap.h
@@ -50,12 +50,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..7058d572 100644
--- a/src/gui/ministatus.cpp
+++ b/src/gui/ministatus.cpp
@@ -19,14 +19,14 @@
* 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 "../animatedsprite.h"
#include "../configuration.h"
#include "../graphics.h"
+#include "../localplayer.h"
#include "../utils/tostring.h"
@@ -90,29 +90,27 @@ 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)
/*
- if(config.getValue("xpBarMonsterCounterExp", 0)!=0)
+ if (config.getValue("xpBarMonsterCounterExp", 0)!=0)
{
updatedText << " | "
<< (int)(((float)player_node->mXpForNextLevel - (float)player_node->mXp)
diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h
index c6a36a98..f262a2a0 100644
--- a/src/gui/ministatus.h
+++ b/src/gui/ministatus.h
@@ -22,14 +22,11 @@
#ifndef MINISTATUS_H
#define MINISTATUS_H
-#include <iosfwd>
-#include <vector>
-
#include "window.h"
-#include "../guichanfwd.h"
-#include "../animatedsprite.h"
+#include <vector>
+class AnimatedSprite;
class ProgressBar;
/**
diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp
index 6ad698bc..b4313b70 100644
--- a/src/gui/npc_text.cpp
+++ b/src/gui/npc_text.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npc_text.h"
-
-#include <string>
-
-#include "browserbox.h"
#include "button.h"
+#include "npc_text.h"
#include "scrollarea.h"
+#include "textbox.h"
+
+#include "widgets/layout.h"
#include "../npc.h"
@@ -39,66 +38,55 @@ NpcTextDialog::NpcTextDialog():
setMinWidth(200);
setMinHeight(150);
- mBrowserBox = new BrowserBox(BrowserBox::AUTO_WRAP);
- mBrowserBox->setOpaque(true);
+ setDefaultSize(0, 0, 260, 200);
+
+ mTextBox = new TextBox;
+ mTextBox->setEditable(false);
+ mTextBox->setOpaque(false);
- scrollArea = new ScrollArea(mBrowserBox);
+ scrollArea = new ScrollArea(mTextBox);
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);
- setLocationRelativeTo(getParent());
-}
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
-void NpcTextDialog::clearText()
-{
- mBrowserBox->clearRows();
+ loadWindowState();
+ setLocationRelativeTo(getParent());
}
void NpcTextDialog::setText(const std::string &text)
{
- mBrowserBox->clearRows();
- mBrowserBox->addRow(text);
+ mText = text;
+ mTextBox->setTextWrapped(mText, scrollArea->getWidth() - 15);
}
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());
+ setText(mText + text + "\n");
}
void NpcTextDialog::action(const gcn::ActionEvent &event)
{
if (event.getId() == "ok")
{
- clearText();
+ setText("");
setVisible(false);
if (current_npc)
current_npc->nextDialog();
current_npc = 0;
}
}
+
+void NpcTextDialog::widgetResized(const gcn::Event &event)
+{
+ Window::widgetResized(event);
+
+ setText(mText);
+}
+
diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h
index c881467a..a07aa04f 100644
--- a/src/gui/npc_text.h
+++ b/src/gui/npc_text.h
@@ -22,12 +22,13 @@
#ifndef NPC_TEXT_H
#define NPC_TEXT_H
-#include <iosfwd>
+#include <string>
+
#include <guichan/actionlistener.hpp>
#include "window.h"
-class BrowserBox;
+class TextBox;
/**
* The npc text dialog.
@@ -45,13 +46,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);
@@ -76,10 +70,19 @@ class NpcTextDialog : public Window, public gcn::ActionListener
*/
void addText(const std::string &string);
+ /**
+ * Called when resizing the window.
+ *
+ * @param event The calling event
+ */
+ void widgetResized(const gcn::Event &event);
+
private:
gcn::Button *okButton;
gcn::ScrollArea *scrollArea;
- BrowserBox *mBrowserBox;
+ TextBox *mTextBox;
+
+ std::string mText;
};
#endif // NPC_TEXT_H
diff --git a/src/gui/npcintegerdialog.cpp b/src/gui/npcintegerdialog.cpp
index ec91d736..c58fc460 100644
--- a/src/gui/npcintegerdialog.cpp
+++ b/src/gui/npcintegerdialog.cpp
@@ -19,27 +19,23 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npcintegerdialog.h"
-
-#include <limits>
-#include <sstream>
-
#include "button.h"
#include "inttextfield.h"
+#include "npcintegerdialog.h"
+
+#include "widgets/layout.h"
#include "../npc.h"
#include "../utils/gettext.h"
-#include "../utils/tostring.h"
-
-#include "widgets/layout.h"
NpcIntegerDialog::NpcIntegerDialog():
Window(_("NPC Number Request"))
{
+ mValueField = new IntTextField();
+
mDecButton = new Button("-", "decvalue", this);
mIncButton = new Button("+", "incvalue", this);
- mValueField = new IntTextField();
okButton = new Button(_("OK"), "ok", this);
cancelButton = new Button(_("Cancel"), "cancel", this);
resetButton = new Button(_("Reset"), "reset", this);
@@ -61,9 +57,6 @@ NpcIntegerDialog::NpcIntegerDialog():
reflowLayout(175, 0);
setLocationRelativeTo(getParent());
-
- mValueField->setActionEventId("valuefield");
- mValueField->addKeyListener(this);
}
void NpcIntegerDialog::setRange(const int min, const int max)
@@ -107,5 +100,16 @@ void NpcIntegerDialog::action(const gcn::ActionEvent &event)
setVisible(false);
current_npc->integerInput(mValueField->getValue());
current_npc = 0;
+ mValueField->reset();
}
}
+
+bool NpcIntegerDialog::isInputFocused()
+{
+ return mValueField->isFocused();
+}
+
+void NpcIntegerDialog::requestFocus()
+{
+ mValueField->requestFocus();
+}
diff --git a/src/gui/npcintegerdialog.h b/src/gui/npcintegerdialog.h
index 983c46fe..10ec60b9 100644
--- a/src/gui/npcintegerdialog.h
+++ b/src/gui/npcintegerdialog.h
@@ -22,16 +22,10 @@
#ifndef GUI_NPCINTEGERDIALOG_H
#define GUI_NPCINTEGERDIALOG_H
-#include <iosfwd>
-#include <vector>
-
#include <guichan/actionlistener.hpp>
-#include <guichan/keylistener.hpp>
#include "window.h"
-#include "../guichanfwd.h"
-
class IntTextField;
/**
@@ -39,8 +33,7 @@ class IntTextField;
*
* \ingroup Interface
*/
-class NpcIntegerDialog : public Window, public gcn::ActionListener,
- public gcn::KeyListener
+class NpcIntegerDialog : public Window, public gcn::ActionListener
{
public:
/**
@@ -68,6 +61,16 @@ class NpcIntegerDialog : public Window, public gcn::ActionListener,
*/
void setRange(const int min, const int max);
+ /**
+ * Checks whether NpcStringDialog is Focused or not.
+ */
+ bool isInputFocused();
+
+ /**
+ * Requests the textfield to take focus for input.
+ */
+ void requestFocus();
+
private:
gcn::Button *mDecButton;
gcn::Button *mIncButton;
diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp
index 4b05df5a..7d8a362a 100644
--- a/src/gui/npclistdialog.cpp
+++ b/src/gui/npclistdialog.cpp
@@ -19,13 +19,14 @@
* 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 "scrollarea.h"
+
+#include "widgets/layout.h"
#include "../npc.h"
@@ -39,30 +40,25 @@ NpcListDialog::NpcListDialog():
setMinWidth(200);
setMinHeight(150);
+ setDefaultSize(0, 0, 260, 200);
+
mItemList = new ListBox(this);
+ mItemList->setWrappingEnabled(true);
scrollArea = new ScrollArea(mItemList);
okButton = new Button(_("OK"), "ok", this);
cancelButton = new Button(_("Cancel"), "cancel", this);
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");
- mItemList->addActionListener(this);
+ place(0, 0, scrollArea, 5).setPadding(3);
+ place(3, 1, okButton);
+ place(4, 1, cancelButton);
- add(scrollArea);
- add(okButton);
- add(cancelButton);
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
+ loadWindowState();
setLocationRelativeTo(getParent());
}
@@ -90,24 +86,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..30167a5e 100644
--- a/src/gui/npclistdialog.h
+++ b/src/gui/npclistdialog.h
@@ -22,7 +22,6 @@
#ifndef GUI_NPCLISTDIALOG_H
#define GUI_NPCLISTDIALOG_H
-#include <iosfwd>
#include <vector>
#include <guichan/actionlistener.hpp>
@@ -30,8 +29,6 @@
#include "window.h"
-#include "../guichanfwd.h"
-
/**
* The npc list dialog.
*
@@ -49,13 +46,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..718c416f 100644
--- a/src/gui/npcstringdialog.cpp
+++ b/src/gui/npcstringdialog.cpp
@@ -19,18 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npcstringdialog.h"
-
-#include <limits>
-#include <sstream>
-
#include "button.h"
+#include "npcstringdialog.h"
#include "textfield.h"
#include "../npc.h"
#include "../utils/gettext.h"
-#include "../utils/tostring.h"
#include "widgets/layout.h"
@@ -38,12 +33,13 @@ NpcStringDialog::NpcStringDialog():
Window(_("NPC Text Request"))
{
mValueField = new TextField("");
+
okButton = new Button(_("OK"), "ok", this);
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,9 +65,15 @@ void NpcStringDialog::action(const gcn::ActionEvent &event)
setVisible(false);
current_npc->stringInput(mValueField->getText());
current_npc = 0;
+ mValueField->setText("");
}
bool NpcStringDialog::isInputFocused()
{
return mValueField->isFocused();
}
+
+void NpcStringDialog::requestFocus()
+{
+ mValueField->requestFocus();
+}
diff --git a/src/gui/npcstringdialog.h b/src/gui/npcstringdialog.h
index 5aea2de0..1933e0f1 100644
--- a/src/gui/npcstringdialog.h
+++ b/src/gui/npcstringdialog.h
@@ -22,16 +22,10 @@
#ifndef GUI_NPCSTRINGDIALOG_H
#define GUI_NPCSTRINGDIALOG_H
-#include <iosfwd>
-#include <vector>
-
#include <guichan/actionlistener.hpp>
-#include <guichan/keylistener.hpp>
#include "window.h"
-#include "../guichanfwd.h"
-
/**
* The npc integer input dialog.
*
@@ -69,6 +63,11 @@ class NpcStringDialog : public Window, public gcn::ActionListener
*/
bool isInputFocused();
+ /**
+ * Requests the textfield to take focus for input.
+ */
+ void requestFocus();
+
private:
gcn::TextField *mValueField;
gcn::Button *okButton;
diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp
index a2134d5d..2c67e71f 100644
--- a/src/gui/ok_dialog.cpp
+++ b/src/gui/ok_dialog.cpp
@@ -19,10 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "ok_dialog.h"
-#include "textbox.h"
+#include <guichan/font.hpp>
+
#include "button.h"
+#include "ok_dialog.h"
#include "scrollarea.h"
+#include "textbox.h"
#include "../utils/gettext.h"
@@ -30,25 +32,44 @@ 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->setTextWrapped(msg, 260);
- 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 +77,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..3a438513 100644
--- a/src/gui/ok_dialog.h
+++ b/src/gui/ok_dialog.h
@@ -26,6 +26,9 @@
#include "window.h"
+class ScrollArea;
+class TextBox;
+
/**
* An 'Ok' button dialog.
*
@@ -41,10 +44,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.cpp b/src/gui/passwordfield.cpp
index 09b6abda..345ee1c3 100644
--- a/src/gui/passwordfield.cpp
+++ b/src/gui/passwordfield.cpp
@@ -21,8 +21,6 @@
#include "passwordfield.h"
-#include <string>
-
PasswordField::PasswordField(const std::string& text):
TextField(text)
{
diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h
index d6082e3f..42f8d187 100644
--- a/src/gui/passwordfield.h
+++ b/src/gui/passwordfield.h
@@ -22,6 +22,8 @@
#ifndef PASSWORDFIELD_H
#define PASSWORDFIELD_H
+#include <string>
+
#include "textfield.h"
/**
@@ -29,7 +31,8 @@
*
* \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..f99ce6ef 100644
--- a/src/gui/playerbox.cpp
+++ b/src/gui/playerbox.cpp
@@ -19,12 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
-
#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"
@@ -32,6 +32,7 @@
#include "../utils/dtor.h"
int PlayerBox::instances = 0;
+float PlayerBox::mAlpha = config.getValue("guialpha", 0.8);
ImageRect PlayerBox::background;
PlayerBox::PlayerBox(const Player *player):
@@ -54,6 +55,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 +85,21 @@ 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))
+ {
+ mPlayer->getSprite(i)->draw(static_cast<Graphics*>(graphics), x, y);
+ }
+ }
+ }
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ for (int a = 0; a < 9; a++)
+ {
+ background.grid[a]->setAlpha(config.getValue("guialpha", 0.8));
+ }
}
}
diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h
index d66db4d4..7c08defd 100644
--- a/src/gui/playerbox.h
+++ b/src/gui/playerbox.h
@@ -51,8 +51,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.
@@ -67,6 +66,7 @@ class PlayerBox : public gcn::ScrollArea
private:
const Player *mPlayer; /**< The character used for display */
+ static float mAlpha;
static int instances;
static ImageRect background;
};
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 06a2ad87..3503d0ea 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -19,16 +19,13 @@
* 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,7 +36,9 @@
#include "../npc.h"
#include "../player_relations.h"
-#include "../resources/iteminfo.h"
+#include "../net/messageout.h"
+#include "../net/protocol.h"
+
#include "../resources/itemdb.h"
#include "../utils/gettext.h"
@@ -77,34 +76,35 @@ void PopupMenu::showPopup(int x, int y, Being *being)
// 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(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;
+ case PlayerRelation::NEUTRAL:
+ mBrowserBox->addRow(strprintf(_("@@friend|Befriend %s@@"), name.c_str()));
+
+ case PlayerRelation::FRIEND:
+ mBrowserBox->addRow(strprintf(_("@@disregard|Disregard %s@@"), name.c_str()));
+ mBrowserBox->addRow(strprintf(_("@@ignore|Ignore %s@@"), name.c_str()));
+ break;
+
+ case PlayerRelation::DISREGARDED:
+ mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str()));
+ mBrowserBox->addRow(strprintf(_("@@ignore|Completely ignore %s@@"), name.c_str()));
+ break;
+
+ case PlayerRelation::IGNORED:
+ mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str()));
+ break;
}
- //mBrowserBox->addRow("@@follow|Follow " + name + "@@");
- //mBrowserBox->addRow("@@buddy|Add " + name + " to Buddy List@@");
+ //mBrowserBox->addRow(_("@@follow|Follow ") + name + "@@");
+ //mBrowserBox->addRow(_("@@buddy|Add ") + name + " to Buddy List@@");
+
+ mBrowserBox->addRow("##3---");
+ mBrowserBox->addRow(strprintf(_("@@party-invite|Invite %s to party@@"), name.c_str()));
}
break;
@@ -148,7 +148,7 @@ void PopupMenu::handleLink(const std::string& link)
// Talk To action
if (link == "talk" &&
- being != NULL &&
+ being &&
being->getType() == Being::NPC &&
current_npc == 0)
{
@@ -157,7 +157,7 @@ void PopupMenu::handleLink(const std::string& link)
// Trade action
else if (link == "trade" &&
- being != NULL &&
+ being &&
being->getType() == Being::PLAYER)
{
player_node->trade(being);
@@ -166,35 +166,35 @@ void PopupMenu::handleLink(const std::string& link)
// Attack action
else if (link == "attack" &&
- being != NULL &&
+ being &&
being->getType() == Being::PLAYER)
{
player_node->attack(being, true);
}
else if (link == "unignore" &&
- being != NULL &&
+ being &&
being->getType() == Being::PLAYER)
{
player_relations.setRelation(being->getName(), PlayerRelation::NEUTRAL);
}
else if (link == "ignore" &&
- being != NULL &&
+ being &&
being->getType() == Being::PLAYER)
{
player_relations.setRelation(being->getName(), PlayerRelation::IGNORED);
}
else if (link == "disregard" &&
- being != NULL &&
+ being &&
being->getType() == Being::PLAYER)
{
player_relations.setRelation(being->getName(), PlayerRelation::DISREGARDED);
}
else if (link == "friend" &&
- being != NULL &&
+ being &&
being->getType() == Being::PLAYER)
{
player_relations.setRelation(being->getName(), PlayerRelation::FRIEND);
@@ -208,7 +208,7 @@ void PopupMenu::handleLink(const std::string& link)
/*
// Add Buddy action
- else if ((link == "buddy") && being != NULL && being->isPlayer())
+ else if ((link == "buddy") && being && being->isPlayer())
{
if (!buddyWindow->isVisible())
buddyWindow->setVisible(true);
@@ -217,7 +217,7 @@ void PopupMenu::handleLink(const std::string& link)
}*/
// Pick Up Floor Item action
- else if ((link == "pickup") && mFloorItem != NULL)
+ else if ((link == "pickup") && mFloorItem)
{
player_node->pickUp(mFloorItem);
}
@@ -247,15 +247,22 @@ void PopupMenu::handleLink(const std::string& link)
}
}
+ else if (link == "chat")
+ {
+ chatWindow->addItemText(mItem->getInfo().getName());
+ }
+
else if (link == "drop")
{
new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem);
}
-
- else if (link == "description")
+ else if (link == "party-invite" &&
+ being &&
+ 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
@@ -288,7 +295,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@@"));
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..c7ccfe39 100644
--- a/src/gui/progressbar.cpp
+++ b/src/gui/progressbar.cpp
@@ -19,17 +19,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <guichan/font.hpp>
+
+#include "gui.h"
#include "progressbar.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
-#include <guichan/font.hpp>
-
ImageRect ProgressBar::mBorder;
int ProgressBar::mInstances = 0;
+float ProgressBar::mAlpha = config.getValue("guialpha", 0.8);
ProgressBar::ProgressBar(float progress,
unsigned int width, unsigned int height,
@@ -55,6 +58,12 @@ ProgressBar::ProgressBar(float progress,
mBorder.grid[6] = dBorders->getSubImage(0, 15, 4, 4);
mBorder.grid[7] = dBorders->getSubImage(4, 15, 3, 4);
mBorder.grid[8] = dBorders->getSubImage(7, 15, 4, 4);
+
+ for (int i = 0; i < 9; i++)
+ {
+ mBorder.grid[i]->setAlpha(mAlpha);
+ }
+
dBorders->decRef();
}
@@ -92,12 +101,27 @@ void ProgressBar::logic()
void ProgressBar::draw(gcn::Graphics *graphics)
{
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ if (config.getValue("opengl", 0))
+ mAlpha = config.getValue("guialpha", 0.8);
+ else
+ mAlpha = 1.0f;
+ for (int i = 0; i < 9; i++)
+ {
+ mBorder.grid[i]->setAlpha(mAlpha);
+ }
+ }
+
static_cast<Graphics*>(graphics)->
drawImageRect(0, 0, getWidth(), getHeight(), mBorder);
+ const int alpha = (int)(mAlpha * 255.0f);
+
// The bar
if (mProgress > 0) {
- graphics->setColor(gcn::Color(mRed, mGreen, mBlue, 200));
+
+ graphics->setColor(gcn::Color(mRed, mGreen, mBlue, alpha));
graphics->fillRectangle(gcn::Rectangle(4, 4,
(int) (mProgress * (getWidth() - 8)),
getHeight() - 8));
@@ -105,20 +129,22 @@ 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;
graphics->setFont(f);
- graphics->setColor(gcn::Color(0, 0, 0));
+ graphics->setColor(gcn::Color(0, 0, 0, alpha));
graphics->drawText(mText, textX + 1, textY, gcn::Graphics::CENTER);
graphics->drawText(mText, textX, textY - 1, gcn::Graphics::CENTER);
graphics->drawText(mText, textX, textY + 1, gcn::Graphics::CENTER);
graphics->drawText(mText, textX - 1, textY, gcn::Graphics::CENTER);
- graphics->setColor(gcn::Color(255, 255, 255));
+ graphics->setColor(gcn::Color(255, 255, 255, alpha));
graphics->drawText(mText, textX, textY, gcn::Graphics::CENTER);
+
+ graphics->setColor(gcn::Color(0, 0, 0));
}
}
diff --git a/src/gui/progressbar.h b/src/gui/progressbar.h
index a4b30b04..2c1b22da 100644
--- a/src/gui/progressbar.h
+++ b/src/gui/progressbar.h
@@ -22,12 +22,12 @@
#ifndef PROGRESSBAR_H
#define PROGRESSBAR_H
+#include <string>
+
#include <guichan/widget.hpp>
#include <SDL_types.h>
-#include <string>
-
class ImageRect;
/**
@@ -81,12 +81,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; }
@@ -110,6 +110,7 @@ class ProgressBar : public gcn::Widget
static ImageRect mBorder;
static int mInstances;
+ static float mAlpha;
};
#endif
diff --git a/src/gui/radiobutton.cpp b/src/gui/radiobutton.cpp
index 245112a7..c8ae2fad 100644
--- a/src/gui/radiobutton.cpp
+++ b/src/gui/radiobutton.cpp
@@ -21,12 +21,14 @@
#include "radiobutton.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
int RadioButton::instances = 0;
+float RadioButton::mAlpha = config.getValue("guialpha", 0.8);
Image *RadioButton::radioNormal;
Image *RadioButton::radioChecked;
Image *RadioButton::radioDisabled;
@@ -43,6 +45,10 @@ RadioButton::RadioButton(const std::string& caption, const std::string& group,
radioChecked = resman->getImage("graphics/gui/radioin.png");
radioDisabled = resman->getImage("graphics/gui/radioout.png");
radioDisabledChecked = resman->getImage("graphics/gui/radioin.png");
+ radioNormal->setAlpha(mAlpha);
+ radioChecked->setAlpha(mAlpha);
+ radioDisabled->setAlpha(mAlpha);
+ radioDisabledChecked->setAlpha(mAlpha);
}
instances++;
@@ -63,32 +69,37 @@ RadioButton::~RadioButton()
void RadioButton::drawBox(gcn::Graphics* graphics)
{
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ radioNormal->setAlpha(mAlpha);
+ radioChecked->setAlpha(mAlpha);
+ radioDisabled->setAlpha(mAlpha);
+ radioDisabledChecked->setAlpha(mAlpha);
+ }
+
Image *box = NULL;
- if (isSelected()) {
- if (isEnabled()) {
+ if (isSelected())
+ {
+ if (isEnabled())
box = radioChecked;
- } else {
+ else
box = radioDisabledChecked;
- }
- } else if (isEnabled()) {
+ }
+ else if (isEnabled())
box = radioNormal;
- } else {
+ else
box = radioDisabled;
- }
- if (box != NULL) {
+ if (box)
static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
- }
}
void RadioButton::draw(gcn::Graphics* graphics)
{
-
- graphics->pushClipArea(gcn::Rectangle(1,
- 1,
- getWidth() - 1,
- getHeight() - 1));
+ graphics->pushClipArea(gcn::Rectangle(1, 1, getWidth() - 1,
+ getHeight() - 1));
drawBox(graphics);
diff --git a/src/gui/radiobutton.h b/src/gui/radiobutton.h
index 2d2bdbb7..3d952b3f 100644
--- a/src/gui/radiobutton.h
+++ b/src/gui/radiobutton.h
@@ -26,11 +26,11 @@
class Image;
-
/*
* Guichan based RadioButton with custom look
*/
-class RadioButton : public gcn::RadioButton {
+class RadioButton : public gcn::RadioButton
+{
public:
/*
* Constructor.
@@ -56,6 +56,7 @@ class RadioButton : public gcn::RadioButton {
private:
static int instances;
+ static float mAlpha;
static Image *radioNormal;
static Image *radioChecked;
static Image *radioDisabled;
diff --git a/src/gui/recorder.cpp b/src/gui/recorder.cpp
new file mode 100644
index 00000000..40ef974b
--- /dev/null
+++ b/src/gui/recorder.cpp
@@ -0,0 +1,116 @@
+/*
+ * A chat recorder
+ * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net>
+ *
+ * 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 <physfs.h>
+
+#include "button.h"
+#include "chat.h"
+#include "recorder.h"
+#include "windowcontainer.h"
+
+#include "widgets/layout.h"
+
+#include "../utils/trim.h"
+
+Recorder::Recorder(ChatWindow *chat, const std::string &title,
+ const std::string &buttonTxt) :
+ Window(title)
+{
+ setWindowName(_("Recorder"));
+ const int offsetX = 2 * getPadding() + 10;
+ const int offsetY = getTitleBarHeight() + getPadding() + 10;
+
+ mChat = chat;
+ Button *button = new Button(buttonTxt, "activate", this);
+ setDefaultSize(0, windowContainer->getHeight() - 123 - button->getHeight() -
+ offsetY, button->getWidth() + offsetX, button->getHeight() +
+ offsetY);
+
+ place(0, 0, button);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
+
+ loadWindowState();
+}
+
+Recorder::~Recorder()
+{
+}
+
+void Recorder::record(const std::string &msg)
+{
+ if (mStream.is_open())
+ {
+ mStream << msg << std::endl;
+ }
+}
+
+void Recorder::changeRecordingStatus(const std::string &msg)
+{
+ std::string msgCopy = msg;
+ trim(msgCopy);
+
+ if (msgCopy.empty())
+ {
+ if (mStream.is_open())
+ {
+ mStream.close();
+ 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);
+ }
+ }
+ else 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);
+ const std::string file =
+ std::string(PHYSFS_getUserDir()) + "/.tmw/" + msgCopy;
+
+ mStream.open(file.c_str(), std::ios_base::trunc);
+
+ if (mStream.is_open())
+ setVisible(true);
+ else
+ mChat->chatLog(_("Failed to start recording."), BY_SERVER);
+ }
+}
+
+void Recorder::action(const gcn::ActionEvent &event)
+{
+ changeRecordingStatus("");
+}
diff --git a/src/gui/recorder.h b/src/gui/recorder.h
new file mode 100644
index 00000000..0bbab012
--- /dev/null
+++ b/src/gui/recorder.h
@@ -0,0 +1,76 @@
+/*
+ * A chat recorder
+ * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net>
+ *
+ * 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
+ */
+
+#ifndef RECORD_H
+#define RECORD_H
+
+#include <fstream>
+#include <string>
+
+#include <guichan/actionlistener.hpp>
+
+#include "window.h"
+
+#include "../utils/gettext.h"
+
+class ChatWindow;
+
+class Recorder : public Window, public gcn::ActionListener
+{
+ public:
+ Recorder(ChatWindow *chat, const std::string &title = _("Recording..."),
+ const std::string &buttonTxt = _("Stop recording"));
+
+ virtual ~Recorder();
+
+ /*
+ * Outputs the message to the recorder file
+ *
+ * @param msg the line to write to the recorded file.
+ */
+ void record(const std::string &msg);
+
+ /*
+ * Outputs the message to the recorder file
+ *
+ * @param msg The file to write out to. If null, then stop recording.
+ */
+ void changeRecordingStatus(const std::string &msg);
+
+ /*
+ * Whether or not the recorder is in use.
+ */
+ bool isRecording() {return (bool) mStream.is_open();}
+
+ /*
+ * called when the button is pressed
+ *
+ * @param event is the event that is generated
+ */
+ void action(const gcn::ActionEvent &event);
+
+ private:
+ ChatWindow *mChat;
+
+ std::ofstream mStream;
+};
+
+#endif
diff --git a/src/gui/register.cpp b/src/gui/register.cpp
index 5605ef96..e17f5902 100644
--- a/src/gui/register.cpp
+++ b/src/gui/register.cpp
@@ -19,30 +19,27 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "register.h"
-
-#include <string>
-#include <sstream>
-
#include <guichan/widgets/label.hpp>
-#include "../main.h"
#include "../configuration.h"
#include "../log.h"
#include "../logindata.h"
+#include "../main.h"
#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 "widgets/layout.h"
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
+#include "../utils/tostring.h"
/**
* Listener used while dealing with wrong data. It is used to direct the focus
@@ -80,10 +77,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 +96,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 +111,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 +122,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);
@@ -216,7 +221,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 +243,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.empty())
+ {
+ 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..9588e07e 100644
--- a/src/gui/register.h
+++ b/src/gui/register.h
@@ -22,12 +22,12 @@
#ifndef REGISTER_H
#define REGISTER_H
-#include <iosfwd>
+#include <string>
+
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
#include "window.h"
-#include "../guichanfwd.h"
class LoginData;
class OkDialog;
@@ -72,10 +72,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..bc3a62dc 100644
--- a/src/gui/scrollarea.cpp
+++ b/src/gui/scrollarea.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
-
#include "scrollarea.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../resources/image.h"
@@ -31,19 +30,22 @@
#include "../utils/dtor.h"
int ScrollArea::instances = 0;
+float ScrollArea::mAlpha = config.getValue("guialpha", 0.8);
ImageRect ScrollArea::background;
ImageRect ScrollArea::vMarker;
Image *ScrollArea::buttons[4][2];
-ScrollArea::ScrollArea(bool gc):
+ScrollArea::ScrollArea(bool gc, bool opaque):
gcn::ScrollArea(),
+ mOpaque(opaque),
mGC(gc)
{
init();
}
-ScrollArea::ScrollArea(gcn::Widget *widget, bool gc):
+ScrollArea::ScrollArea(gcn::Widget *widget, bool gc, bool opaque):
gcn::ScrollArea(widget),
+ mOpaque(opaque),
mGC(gc)
{
init();
@@ -52,9 +54,8 @@ ScrollArea::ScrollArea(gcn::Widget *widget, bool gc):
ScrollArea::~ScrollArea()
{
// Garbage collection
- if (mGC) {
+ if (mGC)
delete getContent();
- }
instances--;
@@ -88,12 +89,15 @@ void ScrollArea::init()
const int bggridy[4] = {0, 3, 28, 31};
int a = 0, x, y;
- for (y = 0; y < 3; y++) {
- for (x = 0; x < 3; x++) {
+ for (y = 0; y < 3; y++)
+ {
+ for (x = 0; x < 3; x++)
+ {
background.grid[a] = textbox->getSubImage(
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 +110,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++;
}
}
@@ -146,7 +153,7 @@ void ScrollArea::logic()
// When no scrollbar in a certain direction, adapt content size to match
// the content dimension exactly.
- if (content != NULL)
+ if (content)
{
if (getHorizontalScrollPolicy() == gcn::ScrollArea::SHOW_NEVER)
{
@@ -188,6 +195,16 @@ void ScrollArea::draw(gcn::Graphics *graphics)
mScrollbarWidth));
}
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ for (int a = 0; a < 9; a++)
+ {
+ background.grid[a]->setAlpha(mAlpha);
+ vMarker.grid[a]->setAlpha(mAlpha);
+ }
+ }
+
drawChildren(graphics);
}
@@ -197,7 +214,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 +225,12 @@ void ScrollArea::setOpaque(bool opaque)
{
mOpaque = opaque;
- if (mOpaque) {
+ if (mOpaque)
+ {
setFrameSize(2);
}
- else {
+ else
+ {
setFrameSize(0);
}
}
@@ -220,7 +240,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..33ebc692 100644
--- a/src/gui/scrollarea.h
+++ b/src/gui/scrollarea.h
@@ -38,12 +38,12 @@ class ScrollArea : public gcn::ScrollArea
/**
* Constructor.
*/
- ScrollArea(bool gc = true);
+ ScrollArea(bool gc = true, bool opaque = true);
/**
* Constructor.
*/
- ScrollArea(gcn::Widget *content, bool gc = true);
+ ScrollArea(gcn::Widget *content, bool gc = true, bool opaque = true);
/**
* Destructor.
@@ -100,6 +100,7 @@ class ScrollArea : public gcn::ScrollArea
void drawHMarker(gcn::Graphics *graphics);
static int instances;
+ static float mAlpha;
static ImageRect background;
static ImageRect vMarker;
static Image *buttons[4][2];
diff --git a/src/gui/sdlinput.cpp b/src/gui/sdlinput.cpp
index f68dc9c8..51442798 100644
--- a/src/gui/sdlinput.cpp
+++ b/src/gui/sdlinput.cpp
@@ -228,7 +228,7 @@ int SDLInput::convertMouseButton(int button)
int SDLInput::convertKeyCharacter(SDL_Event event)
{
SDL_keysym keysym = event.key.keysym;
-
+
int value = keysym.unicode;
switch (keysym.sym)
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index cc6f02d5..e4be7921 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -19,25 +19,19 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "sell.h"
-
-#include <cassert>
-
#include <guichan/widgets/label.hpp>
#include "button.h"
-#include "shoplistbox.h"
#include "scrollarea.h"
+#include "sell.h"
#include "shop.h"
+#include "shoplistbox.h"
#include "slider.h"
#include "widgets/layout.h"
-#include "../item.h"
#include "../npc.h"
-#include "../resources/iteminfo.h"
-
#include "../net/messageout.h"
#include "../net/protocol.h"
diff --git a/src/gui/sell.h b/src/gui/sell.h
index 8e639a3d..c11a7b7c 100644
--- a/src/gui/sell.h
+++ b/src/gui/sell.h
@@ -25,9 +25,9 @@
#include <guichan/actionlistener.hpp>
#include <guichan/selectionlistener.hpp>
-#include "window.h"
+#include <SDL_types.h>
-#include "../guichanfwd.h"
+#include "window.h"
class Item;
class Network;
diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp
index d38fb2e3..09eaeff0 100644
--- a/src/gui/setup.cpp
+++ b/src/gui/setup.cpp
@@ -19,31 +19,30 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup.h"
-
#include "button.h"
+#include "setup.h"
#include "setup_audio.h"
+#include "setup_colors.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 +57,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 +90,10 @@ Setup::Setup():
panel->addTab(_("Keyboard"), tab);
mTabs.push_back(tab);
+ tab = new Setup_Colors();
+ panel->addTab(_("Colors"), tab);
+ mTabs.push_back(tab);
+
tab = new Setup_Players();
panel->addTab(_("Players"), tab);
mTabs.push_back(tab);
@@ -131,6 +135,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..5c189882 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"
@@ -110,8 +109,8 @@ void Setup_Audio::cancel()
sound.setMusicVolume(mMusicVolume);
mMusicSlider->setValue(mMusicVolume);
- config.setValue("sound", mSoundEnabled ? 1 : 0);
- config.setValue("sfxVolume", mSfxVolume ? 1 : 0);
+ config.setValue("sound", mSoundEnabled ? true : false);
+ config.setValue("sfxVolume", mSfxVolume);
config.setValue("musicVolume", mMusicVolume);
}
diff --git a/src/gui/setup_audio.h b/src/gui/setup_audio.h
index 5345d3cf..9e951895 100644
--- a/src/gui/setup_audio.h
+++ b/src/gui/setup_audio.h
@@ -22,11 +22,9 @@
#ifndef GUI_SETUP_AUDIO_H
#define GUI_SETUP_AUDIO_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
-#include "../guichanfwd.h"
+#include "setuptab.h"
class Setup_Audio : public SetupTab, public gcn::ActionListener
{
diff --git a/src/gui/setup_colors.cpp b/src/gui/setup_colors.cpp
new file mode 100644
index 00000000..372dbd17
--- /dev/null
+++ b/src/gui/setup_colors.cpp
@@ -0,0 +1,249 @@
+/*
+ * Configurable text colors
+ * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
+ *
+ * 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 <string>
+#include <cmath>
+
+#include <guichan/listmodel.hpp>
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/slider.hpp>
+
+#include "browserbox.h"
+#include "color.h"
+#include "itemlinkhandler.h"
+#include "listbox.h"
+#include "scrollarea.h"
+#include "setup_colors.h"
+#include "slider.h"
+#include "textfield.h"
+
+#include "widgets/layouthelper.h"
+
+#include "../configuration.h"
+
+#include "../utils/gettext.h"
+#include "../utils/tostring.h"
+
+Setup_Colors::Setup_Colors() :
+ mSelected(-1)
+{
+ setOpaque(false);
+
+ mColorBox = new ListBox(textColor);
+ mColorBox->setActionEventId("color_box");
+ mColorBox->addActionListener(this);
+
+ mScroll = new ScrollArea(mColorBox);
+ mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+
+ mPreview = new BrowserBox(BrowserBox::AUTO_WRAP);
+ mPreview->setOpaque(false);
+
+ // Replace this later with a more appropriate link handler. For now, this'll
+ // do, as it'll do nothing when clicked on.
+ mPreview->setLinkHandler(new ItemLinkHandler());
+
+ mPreviewBox = new ScrollArea(mPreview);
+ mPreviewBox->setHeight(20);
+ mPreviewBox->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER,
+ gcn::ScrollArea::SHOW_NEVER);
+
+ 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(160);
+ 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(160);
+ 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(160);
+ 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, 4, 7).setPadding(2);
+ place(0, 7, mPreviewBox, 4).setPadding(2);
+ place(0, 8, mRedLabel, 2);
+ place(2, 8, mRedSlider);
+ place(3, 8, mRedText).setPadding(1);
+ place(0, 9, mGreenLabel, 2);
+ place(2, 9, mGreenSlider);
+ place(3, 9, mGreenText).setPadding(1);
+ place(0, 10, mBlueLabel, 2);
+ place(2, 10, mBlueSlider);
+ place(3, 10, mBlueText).setPadding(1);
+
+ setDimension(gcn::Rectangle(0, 0, 290, 250));
+}
+
+Setup_Colors::~Setup_Colors()
+{
+ delete mRedLabel;
+ delete mRedSlider;
+ delete mRedText;
+
+ delete mGreenLabel;
+ delete mGreenSlider;
+ delete mGreenText;
+
+ delete mBlueLabel;
+ delete mBlueSlider;
+ delete mBlueText;
+
+ delete mScroll;
+}
+
+void Setup_Colors::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "color_box")
+ {
+ mSelected = mColorBox->getSelected();
+ int col = textColor->getColorAt(mSelected);
+ char ch = textColor->getColorCharAt(mSelected);
+ std::string msg;
+
+ if (ch == '<')
+ msg = toString("@@|") +
+ _("This is what the color looks like") + "@@";
+ else
+ msg = "##" + toString(ch) +
+ _("This is what the color looks like");
+
+ mPreview->clearRows();
+ mPreview->addRow(msg);
+ setEntry(mRedSlider, mRedText, col >> 16);
+ setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff);
+ setEntry(mBlueSlider, mBlueText, col & 0xff);
+ return;
+ }
+
+ if (event.getId() == "slider_red")
+ {
+ mRedText->setText(toString(std::floor(mRedSlider->getValue())));
+ updateColor();
+ return;
+ }
+
+ if (event.getId() == "slider_green")
+ {
+ mGreenText->setText(toString(std::floor(mGreenSlider->getValue())));
+ updateColor();
+ return;
+ }
+
+ if (event.getId() == "slider_blue")
+ {
+ mBlueText->setText(toString(std::floor(mBlueSlider->getValue())));
+ updateColor();
+ return;
+ }
+}
+
+void Setup_Colors::setEntry(gcn::Slider *s, TextField *t, int value)
+{
+ s->setValue(value);
+ char buffer[100];
+ sprintf(buffer, "%d", value);
+ t->setText(buffer);
+}
+
+void Setup_Colors::apply()
+{
+ textColor->commit();
+}
+
+void Setup_Colors::cancel()
+{
+ textColor->rollback();
+ int col = textColor->getColorAt(mSelected);
+ setEntry(mRedSlider, mRedText, col >> 16);
+ setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff);
+ setEntry(mBlueSlider, mBlueText, col & 0xff);
+}
+
+void Setup_Colors::listen(const TextField *tf)
+{
+ if (tf == mRedText)
+ {
+ mRedSlider->setValue(tf->getValue());
+ updateColor();
+ return;
+ }
+ if (tf == mGreenText)
+ {
+ mGreenSlider->setValue(tf->getValue());
+ updateColor();
+ return;
+ }
+ if (tf == mBlueText)
+ {
+ mBlueSlider->setValue(tf->getValue());
+ updateColor();
+ return;
+ }
+}
+
+void Setup_Colors::updateColor()
+{
+ if (mSelected == -1)
+ {
+ return;
+ }
+ int rgb = static_cast<int>(mRedSlider->getValue()) << 16 |
+ static_cast<int>(mGreenSlider->getValue()) << 8 |
+ static_cast<int>(mBlueSlider->getValue());
+ textColor->setColorAt(mSelected, rgb);
+}
diff --git a/src/gui/setup_colors.h b/src/gui/setup_colors.h
new file mode 100644
index 00000000..8fd1ba59
--- /dev/null
+++ b/src/gui/setup_colors.h
@@ -0,0 +1,75 @@
+/*
+ * Configurable text colors
+ * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
+ *
+ * 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
+ */
+
+#ifndef SETUP_COLOURS_H
+#define SETUP_COLOURS_H
+
+#include <string>
+
+#include <guichan/actionlistener.hpp>
+
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/listbox.hpp>
+
+#include "setuptab.h"
+#include "textfield.h"
+
+#include "../guichanfwd.h"
+
+class BrowserBox;
+
+class Setup_Colors : public SetupTab, public gcn::ActionListener,
+ public TextFieldListener
+{
+ public:
+ Setup_Colors();
+ ~Setup_Colors();
+ void apply();
+ void cancel();
+ void action(const gcn::ActionEvent &event);
+
+ void listen(const TextField *tf);
+ private:
+ gcn::ListBox *mColorBox;
+ gcn::ScrollArea *mScroll;
+ BrowserBox *mPreview;
+ gcn::ScrollArea *mPreviewBox;
+ int mSelected;
+
+ gcn::Label *mRedLabel;
+ gcn::Slider *mRedSlider;
+ TextField *mRedText;
+ int mRedValue;
+
+ gcn::Label *mGreenLabel;
+ gcn::Slider *mGreenSlider;
+ TextField *mGreenText;
+ int mGreenValue;
+
+ gcn::Label *mBlueLabel;
+ gcn::Slider *mBlueSlider;
+ TextField *mBlueText;
+ int mBlueValue;
+
+ void setEntry(gcn::Slider *s, TextField *t, int value);
+ void updateColor();
+};
+#endif
diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp
index f8fc194f..2ebcdbde 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"
@@ -42,7 +41,7 @@ Setup_Joystick::Setup_Joystick():
{
setOpaque(false);
- mOriginalJoystickEnabled = (int)config.getValue("joystickEnabled", 0) != 0;
+ mOriginalJoystickEnabled = !config.getValue("joystickEnabled", false);
mJoystickEnabled->setSelected(mOriginalJoystickEnabled);
mJoystickEnabled->addActionListener(this);
@@ -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..eba8a2cc 100644
--- a/src/gui/setup_joystick.h
+++ b/src/gui/setup_joystick.h
@@ -22,11 +22,9 @@
#ifndef GUI_SETUP_JOYSTICK_H
#define GUI_SETUP_JOYSTICK_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
-#include "../guichanfwd.h"
+#include "setuptab.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..5d7519ef 100644
--- a/src/gui/setup_keyboard.cpp
+++ b/src/gui/setup_keyboard.cpp
@@ -1,6 +1,7 @@
/*
- * The Mana World
- * Copyright (C) 2007 The Mana World Development Team
+ * Custom keyboard shortcuts configuration
+ * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au>
+ * Copyright (C) 2009 The Mana World Development Team
*
* This file is part of The Mana World.
*
@@ -19,7 +20,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,17 +29,15 @@
#include "listbox.h"
#include "ok_dialog.h"
#include "scrollarea.h"
+#include "setup_keyboard.h"
#include "widgets/layouthelper.h"
-#include "../configuration.h"
#include "../keyboardconfig.h"
#include "../utils/gettext.h"
#include "../utils/tostring.h"
-#include <SDL_keyboard.h>
-
/**
* The list model for key function list.
*
@@ -79,11 +78,10 @@ Setup_Keyboard::Setup_Keyboard():
refreshKeys();
- mKeyList->setDimension(gcn::Rectangle(0, 0, 185, 140));
mKeyList->addActionListener(this);
- mKeyList->setSelected(-1);
ScrollArea *scrollArea = new ScrollArea(mKeyList);
+ scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
mAssignKeyButton = new Button(_("Assign"), "assign", this);
mAssignKeyButton->addActionListener(this);
@@ -140,9 +138,8 @@ void Setup_Keyboard::action(const gcn::ActionEvent &event)
{
if (event.getSource() == mKeyList)
{
- if (!mKeySetting) {
+ if (!mKeySetting)
mAssignKeyButton->setEnabled(true);
- }
}
else if (event.getId() == "assign")
{
@@ -186,7 +183,8 @@ void Setup_Keyboard::refreshKeys()
void Setup_Keyboard::keyUnresolved()
{
- if (mKeySetting) {
+ if (mKeySetting)
+ {
newKeyCallback(keyboard.getNewKeyIndex());
keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE);
}
diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h
index f04be792..dee12135 100644
--- a/src/gui/setup_keyboard.h
+++ b/src/gui/setup_keyboard.h
@@ -1,6 +1,6 @@
/*
- * The Mana World
- * Copyright (C) 2007 The Mana World Development Team
+ * Custom keyboard shortcuts configuration
+ * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au>
*
* This file is part of The Mana World.
*
@@ -22,14 +22,13 @@
#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 "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..d25117de 100644
--- a/src/gui/setup_players.cpp
+++ b/src/gui/setup_players.cpp
@@ -19,26 +19,27 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup_players.h"
+#include <string>
+#include <vector>
+
+#include <guichan/widgets/label.hpp>
#include "button.h"
#include "checkbox.h"
+#include "listbox.h"
#include "ok_dialog.h"
+#include "scrollarea.h"
+#include "setup_players.h"
+#include "table.h"
+#include "widgets/dropdown.h"
#include "widgets/layouthelper.h"
#include "../configuration.h"
#include "../log.h"
-#include "../player_relations.h"
-#include "../sound.h"
#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
@@ -136,8 +137,12 @@ public:
std::string name = (*player_names)[r];
gcn::Widget *widget = new gcn::Label(name);
mWidgets.push_back(widget);
+ gcn::ListModel *playerRelation = new PlayerRelationListModel();
- gcn::DropDown *choicebox = new gcn::DropDown(new PlayerRelationListModel());
+ gcn::DropDown *choicebox = new DropDown(playerRelation,
+ new ScrollArea(),
+ new ListBox(playerRelation),
+ false);
choicebox->setSelected(player_relations.getRelation(name));
mWidgets.push_back(choicebox);
}
@@ -198,7 +203,7 @@ public:
virtual std::string getElementAt(int i)
{
if (i >= getNumberOfElements()) {
- return "???";
+ return _("???");
}
return (*player_relations.getPlayerIgnoreStrategies())[i]->mDescription;
}
@@ -220,18 +225,22 @@ Setup_Players::Setup_Players():
player_relations.getDefault() & PlayerRelation::TRADE)),
mDefaultWhisper(new CheckBox(_("Allow whispers"),
player_relations.getDefault() & PlayerRelation::WHISPER)),
- mDeleteButton(new Button(_("Delete"), ACTION_DELETE, this)),
- mIgnoreActionChoicesBox(new gcn::DropDown(new IgnoreChoicesListModel()))
+ mDeleteButton(new Button(_("Delete"), ACTION_DELETE, this))
{
setOpaque(false);
+ mPlayerTable->setOpaque(false);
int table_width = NAME_COLUMN_WIDTH + RELATION_CHOICE_COLUMN_WIDTH;
mPlayerTableTitleModel->fixColumnWidth(NAME_COLUMN, NAME_COLUMN_WIDTH);
mPlayerTableTitleModel->fixColumnWidth(RELATION_CHOICE_COLUMN,
RELATION_CHOICE_COLUMN_WIDTH);
- mPlayerTitleTable->setDimension(gcn::Rectangle(10, 10, table_width, 10));
+ mPlayerTitleTable->setDimension(gcn::Rectangle(10, 10, table_width - 1, 10));
mPlayerTitleTable->setBackgroundColor(gcn::Color(0xbf, 0xbf, 0xbf));
+ gcn::ListModel *ignoreChoices = new IgnoreChoicesListModel();
+ mIgnoreActionChoicesBox = new DropDown(ignoreChoices, new ScrollArea(),
+ new ListBox(ignoreChoices), false);
+
for (int i = 0; i < COLUMNS_NR; i++)
{
mPlayerTableTitleModel->set(0, i,
diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h
index d380d9f6..74247b77 100644
--- a/src/gui/setup_players.h
+++ b/src/gui/setup_players.h
@@ -22,20 +22,19 @@
#ifndef GUI_SETUP_PLAYERS_H
#define GUI_SETUP_PLAYERS_H
-#include "setuptab.h"
-
-#include "scrollarea.h"
-#include "button.h"
-#include "table.h"
#include <guichan/actionlistener.hpp>
-#include "../guichanfwd.h"
+#include "setuptab.h"
#include "../player_relations.h"
+class GuiTable;
class PlayerTableModel;
+class StaticTableModel;
-class Setup_Players : public SetupTab, public gcn::ActionListener, public PlayerRelationsListener
+class Setup_Players : public SetupTab,
+ public gcn::ActionListener,
+ public PlayerRelationsListener
{
public:
Setup_Players();
@@ -55,13 +54,13 @@ private:
PlayerTableModel *mPlayerTableModel;
GuiTable *mPlayerTable;
GuiTable *mPlayerTitleTable;
- ScrollArea *mPlayerScrollArea;
+ gcn::ScrollArea *mPlayerScrollArea;
gcn::CheckBox *mPersistIgnores;
gcn::CheckBox *mDefaultTrading;
gcn::CheckBox *mDefaultWhisper;
- Button *mDeleteButton;
+ gcn::Button *mDeleteButton;
gcn::DropDown *mIgnoreActionChoicesBox;
};
diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp
index 53041a9c..c02025c8 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"
@@ -104,9 +104,12 @@ ModeListModel::ModeListModel()
}
Setup_Video::Setup_Video():
- mFullScreenEnabled(config.getValue("screen", 0)),
- mOpenGLEnabled(config.getValue("opengl", 0)),
- mCustomCursorEnabled(config.getValue("customcursor", 1)),
+ mFullScreenEnabled(config.getValue("screen", false)),
+ mOpenGLEnabled(config.getValue("opengl", false)),
+ mCustomCursorEnabled(config.getValue("customcursor", true)),
+ mParticleEffectsEnabled(config.getValue("particleeffects", true)),
+ mSpeechBubbleEnabled(config.getValue("speechbubble", true)),
+ mNameEnabled(config.getValue("showownname", false)),
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));
}
@@ -264,7 +280,7 @@ void Setup_Video::apply()
{
// Full screen changes
bool fullscreen = mFsCheckBox->isSelected();
- if (fullscreen != (config.getValue("screen", 0) == 1))
+ if (fullscreen != (config.getValue("screen", false) == 1))
{
/* The OpenGL test is only necessary on Windows, since switching
* to/from full screen works fine on Linux. On Windows we'd have to
@@ -275,7 +291,7 @@ void Setup_Video::apply()
#if defined(WIN32) || defined(__APPLE__)
// checks for opengl usage
- if (!(config.getValue("opengl", 0) == 1))
+ if (!(config.getValue("opengl", false) == 1))
{
#endif
if (!graphics->setFullscreen(fullscreen))
@@ -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());
}
@@ -297,13 +313,13 @@ void Setup_Video::apply()
_("Restart needed for changes to take effect."));
}
#endif
- config.setValue("screen", fullscreen ? 1 : 0);
+ config.setValue("screen", fullscreen ? true : false);
}
// OpenGL change
if (mOpenGLCheckBox->isSelected() != mOpenGLEnabled)
{
- config.setValue("opengl", mOpenGLCheckBox->isSelected() ? 1 : 0);
+ config.setValue("opengl", mOpenGLCheckBox->isSelected() ? true : false);
// OpenGL can currently only be changed by restarting, notify user.
new OkDialog(_("Changing OpenGL"),
@@ -314,11 +330,14 @@ void Setup_Video::apply()
config.setValue("fpslimit", mFps);
// We sync old and new values at apply time
- mFullScreenEnabled = config.getValue("screen", 0);
- mCustomCursorEnabled = config.getValue("customcursor", 1);
+ mFullScreenEnabled = config.getValue("screen", false);
+ mCustomCursorEnabled = config.getValue("customcursor", true);
+ mParticleEffectsEnabled = config.getValue("particleeffects", true);
+ mSpeechBubbleEnabled = config.getValue("speechbubble", true);
+ mNameEnabled = config.getValue("showownname", false);
mOpacity = config.getValue("guialpha", 0.8);
- mOverlayDetail = (int)config.getValue("OverlayDetail", 2);
- mOpenGLEnabled = config.getValue("opengl", 0);
+ mOverlayDetail = (int) config.getValue("OverlayDetail", 2);
+ mOpenGLEnabled = config.getValue("opengl", false);
}
int Setup_Video::updateSlider(gcn::Slider *slider, gcn::TextField *field,
@@ -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);
@@ -355,22 +377,59 @@ void Setup_Video::cancel()
updateSlider(mScrollRadiusSlider, mScrollRadiusField, "ScrollRadius");
updateSlider(mScrollLazinessSlider, mScrollLazinessField, "ScrollLaziness");
- config.setValue("screen", mFullScreenEnabled ? 1 : 0);
- config.setValue("customcursor", mCustomCursorEnabled ? 1 : 0);
+ config.setValue("screen", mFullScreenEnabled ? true : false);
+ config.setValue("customcursor", mCustomCursorEnabled ? true : false);
+ config.setValue("particleeffects", mParticleEffectsEnabled ? true : false);
+ config.setValue("speechbubble", mSpeechBubbleEnabled ? true : false);
+ config.setValue("showownname", mNameEnabled ? true : false);
config.setValue("guialpha", mOpacity);
- config.setValue("opengl", mOpenGLEnabled ? 1 : 0);
+ config.setValue("opengl", mOpenGLEnabled ? true : false);
}
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());
+
+ // 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());
}
else if (event.getId() == "customcursor")
{
config.setValue("customcursor",
- mCustomCursorCheckBox->isSelected() ? 1 : 0);
+ mCustomCursorCheckBox->isSelected() ? true : false);
+ }
+ else if (event.getId() == "particleeffects")
+ {
+ config.setValue("particleeffects",
+ mParticleEffectsCheckBox->isSelected() ? true : false);
+ 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() ? true : false);
+ }
+ 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() ? true : false);
}
else if (event.getId() == "fpslimitslider")
{
diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h
index b7011186..303b5bfc 100644
--- a/src/gui/setup_video.h
+++ b/src/gui/setup_video.h
@@ -22,12 +22,10 @@
#ifndef GUI_SETUP_VIDEO_H
#define GUI_SETUP_VIDEO_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
-#include "../guichanfwd.h"
+#include "setuptab.h"
class Setup_Video : public SetupTab, public gcn::ActionListener,
public gcn::KeyListener
@@ -53,6 +51,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 +63,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..e0db4c59 100644
--- a/src/gui/shop.h
+++ b/src/gui/shop.h
@@ -27,10 +27,10 @@
#include <guichan/listmodel.hpp>
-#include "../resources/image.h"
-
#include "../shopitem.h"
+class ShopItem;
+
class ShopItems : public gcn::ListModel
{
public:
diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp
index 2517d749..8aed3c77 100644
--- a/src/gui/shoplistbox.cpp
+++ b/src/gui/shoplistbox.cpp
@@ -19,19 +19,20 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "shoplistbox.h"
-
#include <guichan/font.hpp>
-#include <guichan/graphics.hpp>
#include <guichan/listmodel.hpp>
-#include <guichan/mouseinput.hpp>
-#include <guichan/imagefont.hpp>
-#include <guichan/basiccontainer.hpp>
+#include "color.h"
+#include "shop.h"
+#include "shoplistbox.h"
+
+#include "../configuration.h"
#include "../graphics.h"
const int ITEM_ICON_SIZE = 32;
+float ShopListBox::mAlpha = config.getValue("guialpha", 0.8);
+
ShopListBox::ShopListBox(gcn::ListModel *listModel):
ListBox(listModel),
mPlayerMoney(0)
@@ -59,6 +60,15 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics)
if (!mListModel)
return;
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ mAlpha = config.getValue("guialpha", 0.8);
+
+ bool valid;
+ const int red = (textColor->getColor('H', valid) >> 16) & 0xFF;
+ const int green = (textColor->getColor('H', valid) >> 8) & 0xFF;
+ const int blue = textColor->getColor('H', valid) & 0xFF;
+ const int alpha = (int)(mAlpha * 255.0f);
+
Graphics *graphics = static_cast<Graphics*>(gcnGraphics);
graphics->setFont(getFont());
@@ -68,16 +78,16 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics)
i < mListModel->getNumberOfElements();
++i, y += mRowHeight)
{
- gcn::Color backgroundColor = gcn::Color(0xffffff);
+ gcn::Color backgroundColor = gcn::Color(255, 255, 255, alpha);
if (i == mSelected)
{
- backgroundColor = gcn::Color(110, 160, 255);
+ backgroundColor = gcn::Color(red, green, blue, alpha);
}
else if (mShopItems &&
mPlayerMoney < mShopItems->at(i)->getPrice() && mPriceCheck)
{
- backgroundColor = gcn::Color(0x919191);
+ backgroundColor = gcn::Color(145, 145, 145, alpha);
}
graphics->setColor(backgroundColor);
diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h
index bad848d6..cde4786e 100644
--- a/src/gui/shoplistbox.h
+++ b/src/gui/shoplistbox.h
@@ -23,7 +23,8 @@
#define SHOPLISTBOX_H
#include "listbox.h"
-#include "shop.h"
+
+class ShopItems;
/**
* A list box, meant to be used inside a scroll area. Same as the Guichan list
@@ -84,6 +85,8 @@ class ShopListBox : public ListBox
unsigned int mRowHeight; /**< Row Height */
+ static float mAlpha;
+
bool mPriceCheck;
};
diff --git a/src/gui/shortcutcontainer.cpp b/src/gui/shortcutcontainer.cpp
new file mode 100644
index 00000000..4472818e
--- /dev/null
+++ b/src/gui/shortcutcontainer.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 "../configuration.h"
+
+#include "../resources/image.h"
+
+#include "../utils/tostring.h"
+
+float ShortcutContainer::mAlpha = config.getValue("guialpha", 0.8);
+
+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..f5f06163
--- /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>
+
+class Image;
+
+/**
+ * A generic shortcut container.
+ *
+ * \ingroup GUI
+ */
+class ShortcutContainer : public gcn::Widget,
+ public gcn::WidgetListener,
+ public gcn::MouseListener
+{
+ public:
+ /**
+ * Constructor. Initializes the shortcut container.
+ */
+ ShortcutContainer();
+
+ /**
+ * Destructor.
+ */
+ ~ShortcutContainer(){}
+
+ /**
+ * Draws the shortcuts
+ */
+ 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;
+
+ static float mAlpha;
+
+ 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..b6987b3e 100644
--- a/src/gui/itemshortcutwindow.cpp
+++ b/src/gui/shortcutwindow.cpp
@@ -19,23 +19,27 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "itemshortcutwindow.h"
-
-#include "itemshortcutcontainer.h"
#include "scrollarea.h"
+#include "shortcutcontainer.h"
+#include "shortcutwindow.h"
+
+#include "../configuration.h"
static const int SCROLL_PADDING = 0;
-ItemShortcutWindow::ItemShortcutWindow()
+int ShortcutWindow::mInstances = 0;
+
+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;
+
+ mInstances++;
const int border = SCROLL_PADDING * 2 + getPadding() * 2;
setMinWidth(mItems->getBoxWidth() + border);
@@ -43,6 +47,15 @@ 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 - (mInstances * mItems->getBoxWidth()) -
+ (mInstances * 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 +66,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..64592328 100644
--- a/src/gui/itemshortcutwindow.h
+++ b/src/gui/shortcutwindow.h
@@ -19,31 +19,31 @@
* 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;
class ScrollArea;
+class ShortcutContainer;
/**
* A window around the ItemShortcutContainer.
*
* \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 +51,15 @@ class ItemShortcutWindow : public Window
void widgetResized(const gcn::Event &event);
private:
- ItemShortcutContainer *mItems;
+ ShortcutWindow();
+ ShortcutContainer *mItems;
ScrollArea *mScrollArea;
+
+ static int mInstances;
};
-extern ItemShortcutWindow *itemShortcutWindow;
+extern ShortcutWindow *itemShortcutWindow;
+extern ShortcutWindow *emoteShortcutWindow;
#endif
diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp
index 4afd913d..03711a47 100644
--- a/src/gui/skill.cpp
+++ b/src/gui/skill.cpp
@@ -21,13 +21,15 @@
#include <guichan/widgets/label.hpp>
-#include "skill.h"
-
#include "button.h"
#include "listbox.h"
#include "scrollarea.h"
+#include "skill.h"
+#include "table.h"
#include "windowcontainer.h"
+#include "widgets/layout.h"
+
#include "../localplayer.h"
#include "../log.h"
@@ -36,13 +38,18 @@
#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;
bool modifiable;
};
+static const SkillInfo fakeSkillInfo = {
+ _("Mystery Skill"),
+ false
+};
+
std::vector<SkillInfo> skill_db;
static void initSkillinfo();
@@ -58,14 +65,17 @@ public:
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()
@@ -75,15 +85,11 @@ public:
virtual void update()
{
- static const SkillInfo fakeSkillInfo = {
- _("Mystery Skill"),
- false
- };
-
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];
@@ -120,37 +126,35 @@ SkillDialog::SkillDialog():
{
initSkillinfo();
mTableModel = new SkillGuiTableModel(this);
- mTable.setModel(mTableModel);
- mTable.setLinewiseSelection(true);
-
- setWindowName("Skills");
+ mTable = new GuiTable(mTableModel);
+ mTable->setOpaque(false);
+ mTable->setLinewiseSelection(true);
+ mTable->setWrappingEnabled(true);
+ mTable->setActionEventId("skill");
+ mTable->addActionListener(this);
+
+ setWindowName(_("Skills"));
setCloseButton(true);
setDefaultSize(windowContainer->getWidth() - 260, 25, 255, 260);
-// mSkillListBox = new ListBox(this);
- ScrollArea *skillScrollArea = new ScrollArea(&mTable);
+ setMinHeight(50 + mTableModel->getHeight());
+ setMinWidth(200);
+
+ 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);
- add(skillScrollArea);
- add(mPointsLabel);
- add(mIncButton);
- add(mUseButton);
+ place(0, 0, skillScrollArea, 5).setPadding(3);
+ place(0, 1, mPointsLabel, 2);
+ place(3, 2, mIncButton);
+ place(4, 2, mUseButton);
-// mSkillListBox->addActionListener(this);
- mTable.addActionListener(this);
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
setLocationRelativeTo(getParent());
loadWindowState();
@@ -158,6 +162,7 @@ SkillDialog::SkillDialog():
SkillDialog::~SkillDialog()
{
+ delete mTable;
}
void SkillDialog::action(const gcn::ActionEvent &event)
@@ -165,22 +170,25 @@ void SkillDialog::action(const gcn::ActionEvent &event)
if (event.getId() == "inc")
{
// Increment skill
- int selectedSkill = mTable.getSelectedRow();//mSkillListBox->getSelected();
+ int selectedSkill = mTable->getSelectedRow();
if (selectedSkill >= 0)
- {
player_node->raiseSkill(mSkillList[selectedSkill]->id);
- }
}
- else if (event.getId() == "skill")
+ else if (event.getId() == "skill" && mTable->getSelectedRow() > -1)
{
- mIncButton->setEnabled(
- mTable.getSelectedRow() > -1 &&
- player_node->mSkillPoint > 0);
+ SKILL *skill = mSkillList[mTable->getSelectedRow()];
+ SkillInfo const *info;
+
+ if (skill->id >= 0 && (unsigned int) skill->id < skill_db.size())
+ info = &skill_db[skill->id];
+ else
+ info = &fakeSkillInfo;
+
+ mIncButton->setEnabled(player_node->mSkillPoint > 0 &&
+ info->modifiable);
}
else if (event.getId() == "close")
- {
setVisible(false);
- }
}
void SkillDialog::update()
@@ -188,9 +196,10 @@ void SkillDialog::update()
mPointsLabel->setCaption(strprintf(_("Skill points: %d"),
player_node->mSkillPoint));
- int selectedSkill = mTable.getSelectedRow();
+ int selectedSkill = mTable->getSelectedRow();
- if (selectedSkill >= 0) {
+ if (selectedSkill >= 0)
+ {
int skillId = mSkillList[selectedSkill]->id;
bool modifiable;
@@ -201,10 +210,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 +225,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 +244,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;
}
@@ -271,7 +284,8 @@ static void initSkillinfo()
std::string name = XML::getProperty(node, "name", "");
bool modifiable = !atoi(XML::getProperty(node, "fixed", "0").c_str());
- if (index >= 0) {
+ if (index >= 0)
+ {
skill_db.resize(index + 1, emptySkillInfo);
skill_db[index].name = name;
skill_db[index].modifiable = modifiable;
diff --git a/src/gui/skill.h b/src/gui/skill.h
index 893a61e7..0600d106 100644
--- a/src/gui/skill.h
+++ b/src/gui/skill.h
@@ -24,19 +24,16 @@
#include <vector>
-#include <guichan/listmodel.hpp>
#include <guichan/actionlistener.hpp>
#include "window.h"
-#include "table.h"
-
-#include "../guichanfwd.h"
struct SKILL {
short id; /**< Index into "skill_db" array */
short lv, sp;
};
+class GuiTable;
class SkillGuiTableModel;
/**
@@ -71,7 +68,8 @@ class SkillDialog : public Window, public gcn::ActionListener
const std::vector<SKILL*>& getSkills() const { return mSkillList; }
private:
- GuiTable mTable;//gcn::ListBox *mSkillListBox;
+ GuiTable *mTable;
+ ScrollArea *skillScrollArea;
SkillGuiTableModel *mTableModel;
gcn::Label *mPointsLabel;
gcn::Button *mIncButton;
diff --git a/src/gui/slider.cpp b/src/gui/slider.cpp
index 37136012..9bfa840f 100644
--- a/src/gui/slider.cpp
+++ b/src/gui/slider.cpp
@@ -21,6 +21,7 @@
#include "slider.h"
+#include "../configuration.h"
#include "../graphics.h"
#include "../resources/image.h"
@@ -28,6 +29,7 @@
Image *Slider::hStart, *Slider::hMid, *Slider::hEnd, *Slider::hGrip;
Image *Slider::vStart, *Slider::vMid, *Slider::vEnd, *Slider::vGrip;
+float Slider::mAlpha = config.getValue("guialpha", 0.8);
int Slider::mInstances = 0;
Slider::Slider(double scaleEnd):
@@ -107,6 +109,20 @@ void Slider::draw(gcn::Graphics *graphics)
int x = 0;
int y = (h - hStart->getHeight()) / 2;
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ hStart->setAlpha(mAlpha);
+ hMid->setAlpha(mAlpha);
+ hEnd->setAlpha(mAlpha);
+ hGrip->setAlpha(mAlpha);
+
+ vStart->setAlpha(mAlpha);
+ vMid->setAlpha(mAlpha);
+ vEnd->setAlpha(mAlpha);
+ vGrip->setAlpha(mAlpha);
+ }
+
static_cast<Graphics*>(graphics)->drawImage(hStart, x, y);
w -= hStart->getWidth() + hEnd->getWidth();
diff --git a/src/gui/slider.h b/src/gui/slider.h
index 1fe668c5..56ea334a 100644
--- a/src/gui/slider.h
+++ b/src/gui/slider.h
@@ -26,7 +26,6 @@
class Image;
-
/**
* Slider widget. Same as the Guichan slider but with custom look.
*
@@ -67,6 +66,7 @@ class Slider : public gcn::Slider {
static Image *hStart, *hMid, *hEnd, *hGrip;
static Image *vStart, *vMid, *vEnd, *vGrip;
+ static float mAlpha;
static int mInstances;
};
diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp
new file mode 100644
index 00000000..dd404a63
--- /dev/null
+++ b/src/gui/speechbubble.cpp
@@ -0,0 +1,95 @@
+/*
+ * Speech bubbles
+ * Copyright (C) 2008 The Legend of Mazzeroth 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 <guichan/font.hpp>
+
+#include <guichan/widgets/label.hpp>
+
+#include "gui.h"
+#include "scrollarea.h"
+#include "speechbubble.h"
+#include "textbox.h"
+
+#include "../utils/gettext.h"
+
+SpeechBubble::SpeechBubble():
+ Window(_("Speech"), false, NULL, "graphics/gui/speechbubble.xml")
+{
+ 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());
+}
+
+SpeechBubble::~SpeechBubble()
+{
+ delete mCaption;
+ delete mSpeechBox;
+ delete mSpeechArea;
+}
+
+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)
+{
+ int width = mCaption->getWidth() + 3;
+ mSpeechBox->setTextWrapped(mText, 130 > width ? 130 : width);
+
+ const int fontHeight = getFont()->getHeight();
+ const int numRows = mSpeechBox->getNumberOfRows() + 1;
+
+ if (width < mSpeechBox->getMinWidth())
+ width = mSpeechBox->getMinWidth();
+
+ setContentSize(width + fontHeight, (numRows * fontHeight) + 6);
+ mSpeechArea->setDimension(gcn::Rectangle(4, fontHeight + 3, width + 5,
+ (numRows * 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..d2d81332
--- /dev/null
+++ b/src/gui/speechbubble.h
@@ -0,0 +1,48 @@
+/*
+ * Speech bubbles
+ * Copyright (C) 2008 The Legend of Mazzeroth 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
+ */
+
+#ifndef SPEECHBUBBLE_H
+#define SPEECHBUBBLE_H
+
+#include "window.h"
+
+class ScrollArea;
+class TextBox;
+
+class SpeechBubble : public Window
+{
+ public:
+ SpeechBubble();
+ ~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 39a298f7..683a9a41 100644
--- a/src/gui/status.cpp
+++ b/src/gui/status.cpp
@@ -19,14 +19,15 @@
* 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 "widgets/layout.h"
+
#include "../localplayer.h"
#include "../utils/gettext.h"
@@ -37,87 +38,30 @@ 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);
- loadWindowState();
+ (windowContainer->getHeight() - 255) / 2, 400, 345);
// ----------------------
// Status Part
// ----------------------
mLvlLabel = new gcn::Label(strprintf(_("Level: %d"), 0));
- mGpLabel = new gcn::Label(strprintf(_("Job: %d"), 0));
- mJobLvlLabel = new gcn::Label(strprintf(_("Money: %d GP"), 0));
+ mJobLvlLabel = new gcn::Label(strprintf(_("Job: %d"), 0));
+ mGpLabel = new gcn::Label(strprintf(_("Money: %d GP"), 0));
mHpLabel = new gcn::Label(_("HP:"));
mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34);
- mHpValueLabel = new gcn::Label;
mXpLabel = new gcn::Label(_("Exp:"));
mXpBar = new ProgressBar(1.0f, 80, 15, 143, 192, 211);
- mXpValueLabel = new gcn::Label;
mMpLabel = new gcn::Label(_("MP:"));
mMpBar = new ProgressBar(1.0f, 80, 15, 26, 102, 230);
- mMpValueLabel = new gcn::Label;
-
- mJobXpLabel = new gcn::Label(_("Job:"));
- mJobXpBar = new ProgressBar(1.0f, 80, 15, 220, 135, 203);
- mJobValueLabel = new gcn::Label;
-
- int y = 3;
- int x = 5;
-
- mLvlLabel->setPosition(x, y);
- x += mLvlLabel->getWidth() + 40;
- mJobLvlLabel->setPosition(x, y);
- x += mJobLvlLabel->getWidth() + 40;
- mGpLabel->setPosition(x, y);
-
- y += mLvlLabel->getHeight() + 5; // Next Row
- x = 5;
-
- mHpLabel->setPosition(x, y);
- x += mHpLabel->getWidth() + 5;
- mHpBar->setPosition(x, y);
- x += mHpBar->getWidth() + 5;
- mHpValueLabel->setPosition(x, y);
-
- mXpLabel->setPosition(175, y);
- mXpBar->setPosition(205, y);
- mXpValueLabel->setPosition(290, y);
-
- y += mHpLabel->getHeight() + 5; // Next Row
- x = 5;
-
- mMpLabel->setPosition(x, y);
- x += mMpLabel->getWidth() + 5;
- mMpBar->setPosition(x, y);
- x += mMpBar->getWidth() + 5;
- mMpValueLabel->setPosition(x, y);
-
- mJobXpLabel->setPosition(175, y);
- mJobXpBar->setPosition(205, y);
- mJobValueLabel->setPosition(290, y);
-
- add(mLvlLabel);
- add(mJobLvlLabel);
- add(mGpLabel);
- add(mHpLabel);
- add(mHpValueLabel);
- add(mMpLabel);
- add(mMpValueLabel);
- add(mXpLabel);
- add(mXpValueLabel);
- add(mJobXpLabel);
- add(mJobValueLabel);
- add(mHpBar);
- add(mMpBar);
- add(mXpBar);
- add(mJobXpBar);
+
+ mJobLabel = new gcn::Label(_("Job:"));
+ mJobBar = new ProgressBar(1.0f, 80, 15, 220, 135, 203);
// ----------------------
// Stats Part
@@ -127,6 +71,7 @@ StatusWindow::StatusWindow(LocalPlayer *player):
gcn::Label *mStatsTitleLabel = new gcn::Label(_("Stats"));
gcn::Label *mStatsTotalLabel = new gcn::Label(_("Total"));
gcn::Label *mStatsCostLabel = new gcn::Label(_("Cost"));
+ mStatsTotalLabel->setAlignment(gcn::Graphics::CENTER);
// Derived Stats
mStatsAttackLabel = new gcn::Label(_("Attack:"));
@@ -149,10 +94,13 @@ StatusWindow::StatusWindow(LocalPlayer *player):
mStatsReflexPoints = new gcn::Label;
// New labels
- for (int i = 0; i < 6; i++) {
- mStatsLabel[i] = new gcn::Label;
+ for (int i = 0; i < 6; i++)
+ {
+ mStatsLabel[i] = new gcn::Label("0");
+ mStatsLabel[i]->setAlignment(gcn::Graphics::CENTER);
mStatsDisplayLabel[i] = new gcn::Label;
mPointsLabel[i] = new gcn::Label("0");
+ mPointsLabel[i]->setAlignment(gcn::Graphics::CENTER);
}
mRemainingStatsPointsLabel = new gcn::Label;
@@ -164,68 +112,53 @@ StatusWindow::StatusWindow(LocalPlayer *player):
mStatsButton[4] = new Button("+", "DEX", this);
mStatsButton[5] = new Button("+", "LUK", this);
-
- // Set position
- mStatsTitleLabel->setPosition(mMpLabel->getX(), mMpLabel->getY() + 23 );
- mStatsTotalLabel->setPosition(110, mStatsTitleLabel->getY() + 15);
- int totalLabelY = mStatsTotalLabel->getY();
- mStatsCostLabel->setPosition(170, totalLabelY);
-
+ // Assemble
+ ContainerPlacer place;
+ place = getPlacer(0, 0);
+
+ place(0, 0, mLvlLabel, 3);
+ place(5, 0, mJobLvlLabel, 3);
+ place(8, 0, mGpLabel, 3);
+ place(1, 1, mHpLabel).setPadding(3);
+ place(2, 1, mHpBar, 3);
+ place(6, 1, mXpLabel).setPadding(3);
+ place(7, 1, mXpBar, 3);
+ place(1, 2, mMpLabel).setPadding(3);
+ place(2, 2, mMpBar, 3);
+ place(6, 2, mJobLabel).setPadding(3);
+ place(7, 2, mJobBar, 3);
+ place.getCell().matchColWidth(0, 1);
+ place = getPlacer(0, 3);
+ place(0, 0, mStatsTitleLabel, 5);
+ place(5, 1, mStatsTotalLabel, 5);
+ place(12, 1, mStatsCostLabel, 5);
for (int i = 0; i < 6; i++)
{
- mStatsLabel[i]->setPosition(5, mStatsTotalLabel->getY() + (i * 23) + 15);
- mStatsDisplayLabel[i]->setPosition(115,
- totalLabelY + (i * 23) + 15);
- mStatsButton[i]->setPosition(145, totalLabelY + (i * 23) + 10);
- mPointsLabel[i]->setPosition(175, totalLabelY + (i * 23) + 15);
+ place(0, 2 + i, mStatsLabel[i], 7).setPadding(5);
+ place(7, 2 + i, mStatsDisplayLabel[i]).setPadding(5);
+ place(10, 2 + i, mStatsButton[i]);
+ place(12, 2 + i, mPointsLabel[i]).setPadding(5);
}
+ place(14, 2, mStatsAttackLabel, 7).setPadding(5);
+ place(14, 3, mStatsDefenseLabel, 7).setPadding(5);
+ place(14, 4, mStatsMagicAttackLabel, 7).setPadding(5);
+ place(14, 5, mStatsMagicDefenseLabel, 7).setPadding(5);
+ place(14, 6, mStatsAccuracyLabel, 7).setPadding(5);
+ place(14, 7, mStatsEvadeLabel, 7).setPadding(5);
+ place(14, 8, mStatsReflexLabel, 7).setPadding(5);
+ place(21, 2, mStatsAttackPoints, 3).setPadding(5);
+ place(21, 3, mStatsDefensePoints, 3).setPadding(5);
+ place(21, 4, mStatsMagicAttackPoints, 3).setPadding(5);
+ place(21, 5, mStatsMagicDefensePoints, 3).setPadding(5);
+ place(21, 6, mStatsAccuracyPoints, 3).setPadding(5);
+ place(21, 7, mStatsEvadePoints, 3).setPadding(5);
+ place(21, 8, mStatsReflexPoints, 3).setPadding(5);
+ place(0, 8, mRemainingStatsPointsLabel, 3).setPadding(5);
+
+ Layout &layout = getLayout();
+ layout.setRowHeight(0, Layout::AUTO_SET);
- mRemainingStatsPointsLabel->setPosition(5, mPointsLabel[5]->getY() + 25);
-
- mStatsAttackLabel->setPosition(220, mStatsLabel[0]->getY());
- mStatsDefenseLabel->setPosition(220, mStatsLabel[1]->getY());
- mStatsMagicAttackLabel->setPosition(220, mStatsLabel[2]->getY());
- mStatsMagicDefenseLabel->setPosition(220, mStatsLabel[3]->getY());
- mStatsAccuracyLabel->setPosition(220, mStatsLabel[4]->getY());
- mStatsEvadeLabel->setPosition(220, mStatsLabel[5]->getY());
- mStatsReflexLabel->setPosition(220, mRemainingStatsPointsLabel->getY());
-
- mStatsAttackPoints->setPosition(310, mStatsLabel[0]->getY());
- mStatsDefensePoints->setPosition(310, mStatsLabel[1]->getY());
- mStatsMagicAttackPoints->setPosition(310, mStatsLabel[2]->getY());
- mStatsMagicDefensePoints->setPosition(310, mStatsLabel[3]->getY());
- mStatsAccuracyPoints->setPosition(310, mStatsLabel[4]->getY());
- mStatsEvadePoints->setPosition(310, mStatsLabel[5]->getY());
- mStatsReflexPoints->setPosition(310, mRemainingStatsPointsLabel->getY());
-
- // Assemble
- add(mStatsTitleLabel);
- add(mStatsTotalLabel);
- add(mStatsCostLabel);
- for(int i = 0; i < 6; i++)
- {
- add(mStatsLabel[i]);
- add(mStatsDisplayLabel[i]);
- add(mStatsButton[i]);
- add(mPointsLabel[i]);
- }
- add(mStatsAttackLabel);
- add(mStatsDefenseLabel);
- add(mStatsMagicAttackLabel);
- add(mStatsMagicDefenseLabel);
- add(mStatsAccuracyLabel);
- add(mStatsEvadeLabel);
- add(mStatsReflexLabel);
-
- add(mStatsAttackPoints);
- add(mStatsDefensePoints);
- add(mStatsMagicAttackPoints);
- add(mStatsMagicDefensePoints);
- add(mStatsAccuracyPoints);
- add(mStatsEvadePoints);
- add(mStatsReflexPoints);
-
- add(mRemainingStatsPointsLabel);
+ loadWindowState();
}
void StatusWindow::update()
@@ -241,21 +174,17 @@ void StatusWindow::update()
mGpLabel->setCaption(strprintf(_("Money: %d GP"), mPlayer->mGp));
mGpLabel->adjustSize();
- mHpValueLabel->setCaption(toString(mPlayer->mHp) +
- "/" + toString(mPlayer->mMaxHp));
- mHpValueLabel->adjustSize();
+ mHpBar->setText(toString(mPlayer->mHp) +
+ "/" + toString(mPlayer->mMaxHp));
- mMpValueLabel->setCaption(toString(mPlayer->mMp) +
- "/" + toString(mPlayer->mMaxMp));
- mMpValueLabel->adjustSize();
+ mMpBar->setText(toString(mPlayer->mMp) +
+ "/" + toString(mPlayer->mMaxMp));
- mXpValueLabel->setCaption(toString(mPlayer->getXp()) +
- "/" + toString(mPlayer->mXpForNextLevel));
- mXpValueLabel->adjustSize();
+ mXpBar->setText(toString(mPlayer->getXp()) +
+ "/" + toString(mPlayer->mXpForNextLevel));
- mJobValueLabel->setCaption(toString(mPlayer->mJobXp) +
- "/" + toString(mPlayer->mJobXpForNextLevel));
- mJobValueLabel->adjustSize();
+ mJobBar->setText(toString(mPlayer->mJobXp) +
+ "/" + toString(mPlayer->mJobXpForNextLevel));
// HP Bar coloration
if (mPlayer->mHp < int(mPlayer->mMaxHp / 3))
@@ -276,7 +205,7 @@ void StatusWindow::update()
mXpBar->setProgress(
(float) mPlayer->getXp() / (float) mPlayer->mXpForNextLevel);
- mJobXpBar->setProgress(
+ mJobBar->setProgress(
(float) mPlayer->mJobXp / (float) mPlayer->mJobXpForNextLevel);
// Stats Part
@@ -341,30 +270,6 @@ void StatusWindow::update()
// Reflex %
mStatsReflexPoints->setCaption(toString(mPlayer->DEX / 4)); // + counter
mStatsReflexPoints->adjustSize();
-
- // Update Second column widgets position
- mJobLvlLabel->setPosition(mLvlLabel->getX() + mLvlLabel->getWidth() + 20,
- mLvlLabel->getY());
- mGpLabel->setPosition(mJobLvlLabel->getX() + mJobLvlLabel->getWidth() + 20,
- mJobLvlLabel->getY());
-
- mXpLabel->setPosition(
- mHpValueLabel->getX() + mHpValueLabel->getWidth() + 10,
- mHpLabel->getY());
- mXpBar->setPosition(
- mXpLabel->getX() + mXpLabel->getWidth() + 5,
- mXpLabel->getY());
- mXpValueLabel->setPosition(
- mXpBar->getX() + mXpBar->getWidth() + 5,
- mXpLabel->getY());
-
- mJobXpLabel->setPosition(mXpBar->getX() - mJobXpLabel->getWidth() - 5,
- mMpLabel->getY());
- mJobXpBar->setPosition(
- mJobXpLabel->getX() + mJobXpLabel->getWidth() + 5,
- mJobXpLabel->getY());
- mJobValueLabel->setPosition(mJobXpBar->getX() + mJobXpBar->getWidth() + 5,
- mJobXpLabel->getY());
}
void StatusWindow::draw(gcn::Graphics *g)
diff --git a/src/gui/status.h b/src/gui/status.h
index 6d360caf..00a48f4e 100644
--- a/src/gui/status.h
+++ b/src/gui/status.h
@@ -22,18 +22,13 @@
#ifndef STATUS_H
#define STATUS_H
-#include <iosfwd>
-
#include <guichan/actionlistener.hpp>
#include "window.h"
-#include "../guichanfwd.h"
-
class LocalPlayer;
class ProgressBar;
-
/**
* The player status dialog.
*
@@ -70,11 +65,9 @@ class StatusWindow : public Window, public gcn::ActionListener
*/
gcn::Label *mLvlLabel, *mJobLvlLabel;
gcn::Label *mGpLabel;
- gcn::Label *mHpLabel, *mHpValueLabel;
- gcn::Label *mMpLabel, *mMpValueLabel;
- gcn::Label *mXpLabel, *mXpValueLabel, *mJobXpLabel, *mJobValueLabel;
+ gcn::Label *mHpLabel, *mMpLabel, *mXpLabel, *mJobLabel;
ProgressBar *mHpBar, *mMpBar;
- ProgressBar *mXpBar, *mJobXpBar;
+ ProgressBar *mXpBar, *mJobBar;
/**
* Derived Statistics captions
diff --git a/src/gui/table.cpp b/src/gui/table.cpp
index f6678737..567272f0 100644
--- a/src/gui/table.cpp
+++ b/src/gui/table.cpp
@@ -19,13 +19,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <guichan/actionlistener.hpp>
+#include <guichan/graphics.hpp>
+#include <guichan/key.hpp>
+
+#include "color.h"
#include "table.h"
-#include <guichan/graphics.hpp>
-#include <guichan/actionlistener.hpp>
+#include "../configuration.h"
-#include <cassert>
+#include "../utils/dtor.h"
+float GuiTable::mAlpha = config.getValue("guialpha", 0.8);
class GuiTableActionListener : public gcn::ActionListener
{
@@ -50,7 +55,8 @@ GuiTableActionListener::GuiTableActionListener(GuiTable *table, gcn::Widget *wid
mColumn(column),
mWidget(widget)
{
- if (widget) {
+ if (widget)
+ {
widget->addActionListener(this);
widget->_setParent(table);
}
@@ -58,7 +64,8 @@ GuiTableActionListener::GuiTableActionListener(GuiTable *table, gcn::Widget *wid
GuiTableActionListener::~GuiTableActionListener()
{
- if (mWidget) {
+ if (mWidget)
+ {
mWidget->removeActionListener(this);
mWidget->_setParent(NULL);
}
@@ -71,14 +78,20 @@ void GuiTableActionListener::action(const gcn::ActionEvent& actionEvent)
}
-GuiTable::GuiTable(TableModel *initial_model) :
+GuiTable::GuiTable(TableModel *initial_model, gcn::Color background,
+ bool opacity) :
mLinewiseMode(false),
+ mWrappingEnabled(false),
+ mOpaque(opacity),
+ mBackgroundColor(background),
mModel(NULL),
mSelectedRow(0),
mSelectedColumn(0),
mTopWidget(NULL)
{
setModel(initial_model);
+ setFocusable(true);
+
addMouseListener(this);
addKeyListener(this);
}
@@ -95,7 +108,8 @@ TableModel *GuiTable::getModel() const
void GuiTable::setModel(TableModel *new_model)
{
- if (mModel) {
+ if (mModel)
+ {
uninstallActionListeners();
mModel->removeListener(this);
}
@@ -103,13 +117,13 @@ void GuiTable::setModel(TableModel *new_model)
mModel = new_model;
installActionListeners();
- if (new_model) {
+ if (new_model)
+ {
new_model->installListener(this);
recomputeDimensions();
}
}
-
void GuiTable::recomputeDimensions()
{
int rows_nr = mModel->getRows();
@@ -169,10 +183,62 @@ int GuiTable::getColumnWidth(int i)
return 0;
}
-void GuiTable::uninstallActionListeners()
+void GuiTable::setSelectedRow(int selected)
{
- for (std::vector<GuiTableActionListener *>::const_iterator it = action_listeners.begin(); it != action_listeners.end(); it++)
- delete *it;
+ if (!mModel)
+ {
+ mSelectedRow = -1;
+ }
+ else
+ {
+ if (selected < 0 && !mWrappingEnabled)
+ {
+ mSelectedRow = -1;
+ }
+ else if (selected >= mModel->getRows() && mWrappingEnabled)
+ {
+ mSelectedRow = 0;
+ }
+ else if ((selected >= mModel->getRows() && !mWrappingEnabled) ||
+ (selected < 0 && mWrappingEnabled))
+ {
+ mSelectedRow = mModel->getRows() - 1;
+ }
+ else
+ {
+ mSelectedRow = selected;
+ }
+ }
+}
+
+void GuiTable::setSelectedColumn(int selected)
+{
+ if (!mModel)
+ {
+ mSelectedColumn = -1;
+ }
+ else
+ {
+ if ((selected >= mModel->getColumns() && mWrappingEnabled) ||
+ (selected < 0 && !mWrappingEnabled))
+ {
+ mSelectedColumn = 0;
+ }
+ else if ((selected >= mModel->getColumns() && !mWrappingEnabled) ||
+ (selected < 0 && mWrappingEnabled))
+ {
+ mSelectedColumn = mModel->getColumns() - 1;
+ }
+ else
+ {
+ mSelectedColumn = selected;
+ }
+ }
+}
+
+void GuiTable::uninstallActionListeners(void)
+{
+ delete_all(action_listeners);
action_listeners.clear();
}
@@ -185,10 +251,11 @@ void GuiTable::installActionListeners()
int columns = mModel->getColumns();
for (int row = 0; row < rows; ++row)
- for (int column = 0; column < columns; ++column) {
+ for (int column = 0; column < columns; ++column)
+ {
gcn::Widget *widget = mModel->getElementAt(row, column);
action_listeners.push_back(new GuiTableActionListener(this, widget,
- row, column));
+ row, column));
}
_setFocusHandler(_getFocusHandler()); // propagate focus handler to widgets
@@ -197,12 +264,22 @@ void GuiTable::installActionListeners()
// -- widget ops
void GuiTable::draw(gcn::Graphics* graphics)
{
- graphics->setColor(getBackgroundColor());
- graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
-
if (!mModel)
return;
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ mAlpha = config.getValue("guialpha", 0.8);
+
+ if (mOpaque)
+ {
+ const int red = getBackgroundColor().r;
+ const int green = getBackgroundColor().g;
+ const int blue = getBackgroundColor().b;
+ const int alpha = (int)(mAlpha * 255.0f);
+ graphics->setColor(gcn::Color(red, green, blue, alpha));
+ graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
+ }
+
// First, determine how many rows we need to draw, and where we should start.
int first_row = -(getY() / getRowHeight());
@@ -224,44 +301,68 @@ void GuiTable::draw(gcn::Graphics* graphics)
int height = getRowHeight();
int y_offset = first_row * height;
- for (int r = first_row; r < first_row + rows_nr; ++r) {
+ for (int r = first_row; r < first_row + rows_nr; ++r)
+ {
int x_offset = 0;
- for (int c = first_column; c <= last_column; ++c) {
+ for (int c = first_column; c <= last_column; ++c)
+ {
gcn::Widget *widget = mModel->getElementAt(r, c);
int width = getColumnWidth(c);
- if (widget) {
+ if (widget)
+ {
gcn::Rectangle bounds(x_offset, y_offset, width, height);
- if (widget == mTopWidget) {
+ if (widget == mTopWidget)
+ {
bounds.height = widget->getHeight();
bounds.width = widget->getWidth();
}
widget->setDimension(bounds);
+ if (!mLinewiseMode && c == mSelectedColumn && r == mSelectedRow)
+ {
+ bool valid;
+ const int red =
+ (textColor->getColor('H', valid) >> 16) & 0xFF;
+ const int green =
+ (textColor->getColor('H', valid) >> 8) & 0xFF;
+ const int blue = textColor->getColor('H', valid) & 0xFF;
+ const int alpha = (int)(mAlpha * 127.0f);
+
+ graphics->setColor(gcn::Color(red, green, blue, alpha));
+ graphics->fillRectangle(bounds);
+ }
+
graphics->pushClipArea(bounds);
widget->draw(graphics);
graphics->popClipArea();
-
- if (!mLinewiseMode
- && c == mSelectedColumn
- && r == mSelectedRow)
- graphics->drawRectangle(bounds);
}
x_offset += width;
}
- if (mLinewiseMode
- && r == mSelectedRow)
- graphics->drawRectangle(gcn::Rectangle(0, y_offset,
+ if (mLinewiseMode && r == mSelectedRow)
+ {
+ bool valid;
+ const int red =
+ (textColor->getColor('H', valid) >> 16) & 0xFF;
+ const int green =
+ (textColor->getColor('H', valid) >> 8) & 0xFF;
+ const int blue = textColor->getColor('H', valid) & 0xFF;
+ const int alpha = (int)(mAlpha * 127.0f);
+
+ graphics->setColor(gcn::Color(red, green, blue, alpha));
+ graphics->fillRectangle(gcn::Rectangle(0, y_offset,
x_offset, height));
+ }
y_offset += height;
}
- if (mTopWidget) {
+ if (mTopWidget)
+ {
gcn::Rectangle bounds = mTopWidget->getDimension();
graphics->pushClipArea(bounds);
mTopWidget->draw(graphics);
@@ -269,21 +370,17 @@ void GuiTable::draw(gcn::Graphics* graphics)
}
}
-void GuiTable::logic()
-{
-}
-
void GuiTable::moveToTop(gcn::Widget *widget)
{
gcn::Widget::moveToTop(widget);
- this->mTopWidget = widget;
+ mTopWidget = widget;
}
void GuiTable::moveToBottom(gcn::Widget *widget)
{
gcn::Widget::moveToBottom(widget);
- if (widget == this->mTopWidget)
- this->mTopWidget = NULL;
+ if (widget == mTopWidget)
+ mTopWidget = NULL;
}
gcn::Rectangle GuiTable::getChildrenArea()
@@ -294,17 +391,62 @@ gcn::Rectangle GuiTable::getChildrenArea()
// -- KeyListener notifications
void GuiTable::keyPressed(gcn::KeyEvent& keyEvent)
{
-}
+ gcn::Key key = keyEvent.getKey();
+
+ if (key.getValue() == gcn::Key::ENTER || key.getValue() == gcn::Key::SPACE)
+ {
+ distributeActionEvent();
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::UP)
+ {
+ setSelectedRow(mSelectedRow - 1);
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::DOWN)
+ {
+ setSelectedRow(mSelectedRow + 1);
+
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::LEFT)
+ {
+ setSelectedColumn(mSelectedColumn - 1);
+
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::RIGHT)
+ {
+ setSelectedColumn(mSelectedColumn + 1);
+
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::HOME)
+ {
+ setSelectedRow(0);
+ setSelectedColumn(0);
+ keyEvent.consume();
+ }
+ else if (key.getValue() == gcn::Key::END)
+ {
+ setSelectedRow(mModel->getRows() - 1);
+ setSelectedColumn(mModel->getColumns() - 1);
+ keyEvent.consume();
+ }
+}
// -- MouseListener notifications
void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent)
{
- if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) {
+ if (mouseEvent.getButton() == gcn::MouseEvent::LEFT)
+ {
int row = getRowForY(mouseEvent.getY());
int column = getColumnForX(mouseEvent.getX());
- if (row > -1 && column > -1) {
+ if (row > -1 && column > -1 &&
+ row < mModel->getRows() && column < mModel->getColumns())
+ {
mSelectedColumn = column;
mSelectedRow = row;
}
@@ -315,10 +457,25 @@ void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent)
void GuiTable::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent)
{
+ if (isFocused())
+ {
+ if (getSelectedRow() >= 0 )
+ {
+ setSelectedRow(getSelectedRow() - 1);
+ }
+
+ mouseEvent.consume();
+ }
}
void GuiTable::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent)
{
+ if (isFocused())
+ {
+ setSelectedRow(getSelectedRow() + 1);
+
+ mouseEvent.consume();
+ }
}
void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent)
@@ -328,10 +485,13 @@ void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent)
// -- TableModelListener notifications
void GuiTable::modelUpdated(bool completed)
{
- if (completed) {
+ if (completed)
+ {
recomputeDimensions();
installActionListeners();
- } else { // before the update?
+ }
+ else
+ { // before the update?
mTopWidget = NULL; // No longer valid in general
uninstallActionListeners();
}
@@ -342,18 +502,18 @@ gcn::Widget *GuiTable::getWidgetAt(int x, int y)
int row = getRowForY(y);
int column = getColumnForX(x);
- if (mTopWidget
- && mTopWidget->getDimension().isPointInRect(x, y))
+ if (mTopWidget && mTopWidget->getDimension().isPointInRect(x, y))
return mTopWidget;
- if (row > -1
- && column > -1) {
+ if (row > -1 && column > -1)
+ {
gcn::Widget *w = mModel->getElementAt(row, column);
if (w && w->isFocusable())
return w;
else
return NULL; // Grab the event locally
- } else
+ }
+ else
return NULL;
}
@@ -361,8 +521,7 @@ int GuiTable::getRowForY(int y)
{
int row = y / getRowHeight();
- if (row < 0
- || row >= mModel->getRows())
+ if (row < 0 || row >= mModel->getRows())
return -1;
else
return row;
@@ -373,20 +532,19 @@ int GuiTable::getColumnForX(int x)
int column;
int delta = 0;
- for (column = 0; column < mModel->getColumns(); column++) {
+ for (column = 0; column < mModel->getColumns(); column++)
+ {
delta += getColumnWidth(column);
if (x <= delta)
break;
}
- if (column < 0
- || column >= mModel->getColumns())
+ if (column < 0 || column >= mModel->getColumns())
return -1;
else
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..841f6ef2 100644
--- a/src/gui/table.h
+++ b/src/gui/table.h
@@ -24,14 +24,11 @@
#include <vector>
-#include <guichan/gui.hpp>
#include <guichan/keylistener.hpp>
#include <guichan/mouselistener.hpp>
-#include <guichan/platform.hpp>
#include <guichan/widget.hpp>
#include "table_model.h"
-#include "../guichanfwd.h"
class GuiTableActionListener;
@@ -53,7 +50,8 @@ class GuiTable : public gcn::Widget,
friend class GuiTableActionListener;
public:
- GuiTable(TableModel * initial_model = NULL);
+ GuiTable(TableModel * initial_model = NULL, gcn::Color background = 0xffffff,
+ bool opacity = true);
virtual ~GuiTable();
@@ -67,25 +65,36 @@ public:
*
* Note that actions issued by widgets returned from the model will update
* the table selection, but only AFTER any event handlers installed within
- * the widget have been triggered. To be notified after such an update,
- * add an action listener to the table instead.
+ * the widget have been triggered. To be notified after such an update, add
+ * an action listener to the table instead.
*/
void setModel(TableModel *m);
+ const TableModel* getModel() {return mModel;}
+
void setSelected(int row, int column);
int getSelectedRow();
int getSelectedColumn();
- gcn::Rectangle getChildrenArea();
+ void setSelectedRow(int selected);
+
+ void setSelectedColumn(int selected);
+
+ bool isWrappingEnabled() const {return mWrappingEnabled;}
+
+ void setWrappingEnabled(bool wrappingEnabled)
+ {mWrappingEnabled = wrappingEnabled;}
+
+ gcn::Rectangle getChildrenArea(void);
/**
- * Toggle whether to use linewise selection mode, in which the table
- * selects an entire line at a time, rather than a single cell.
+ * Toggle whether to use linewise selection mode, in which the table selects
+ * an entire line at a time, rather than a single cell.
*
- * Note that column information is tracked even in linewise selection
- * mode; this mode therefore only affects visualisation.
+ * Note that column information is tracked even in linewise selection mode;
+ * this mode therefore only affects visualisation.
*
* Disabled by default.
*
@@ -96,8 +105,6 @@ public:
// Inherited from Widget
virtual void draw(gcn::Graphics* graphics);
- virtual void logic();
-
virtual gcn::Widget *getWidgetAt(int x, int y);
virtual void moveToTop(gcn::Widget *child);
@@ -109,6 +116,21 @@ public:
// Inherited from KeyListener
virtual void keyPressed(gcn::KeyEvent& keyEvent);
+ /**
+ * 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) {mOpaque = opaque;}
+
+ /**
+ * Checks if the table is opaque, that is if the table area displays its
+ * background.
+ *
+ * @return True if the table is opaque, false otherwise.
+ */
+ virtual bool isOpaque() const {return mOpaque;}
// Inherited from MouseListener
virtual void mousePressed(gcn::MouseEvent& mouseEvent);
@@ -136,6 +158,15 @@ private:
int getColumnForX(int x); // -1 on error
void recomputeDimensions();
bool mLinewiseMode;
+ bool mWrappingEnabled;
+ bool mOpaque;
+
+ static float mAlpha;
+
+ /**
+ * Holds the background color of the table.
+ */
+ gcn::Color mBackgroundColor;
TableModel *mModel;
diff --git a/src/gui/table_model.cpp b/src/gui/table_model.cpp
index 7bc29b47..4fa13bae 100644
--- a/src/gui/table_model.cpp
+++ b/src/gui/table_model.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "table_model.h"
-
#include <guichan/widget.hpp>
-#include <cstdlib>
+
+#include "table_model.h"
#include "../utils/dtor.h"
@@ -49,7 +48,6 @@ 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
@@ -143,3 +141,21 @@ 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);
+}
+
diff --git a/src/gui/table_model.h b/src/gui/table_model.h
index d245d7bd..9ca36120 100644
--- a/src/gui/table_model.h
+++ b/src/gui/table_model.h
@@ -22,10 +22,6 @@
#ifndef TABLE_MODEL_H
#define TABLE_MODEL_H
-#include "../guichanfwd.h"
-
-#include <guichan/gui.hpp>
-
#include <set>
#include <vector>
@@ -133,6 +129,8 @@ public:
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);
diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp
index 75f0b5a1..2a86d549 100644
--- a/src/gui/textbox.cpp
+++ b/src/gui/textbox.cpp
@@ -19,21 +19,21 @@
* 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()
{
setOpaque(false);
setFrameSize(0);
+ mMinWidth = getWidth();
}
-void TextBox::setTextWrapped(const std::string &text)
+void TextBox::setTextWrapped(const std::string &text, int minDimension)
{
// Make sure parent scroll area sets width of this widget
if (getParent())
@@ -41,8 +41,13 @@ void TextBox::setTextWrapped(const std::string &text)
getParent()->logic();
}
+ // Take the supplied minimum dimension as a starting point and try to beat it
+ mMinWidth = minDimension;
+
std::stringstream wrappedStream;
std::string::size_type newlinePos, lastNewlinePos = 0;
+ int minWidth = 0;
+ int xpos;
do
{
@@ -57,7 +62,18 @@ 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;
+
+ spacePos = text.rfind(" ", text.size());
+
+ if (spacePos != std::string::npos)
+ {
+ const std::string word = text.substr(spacePos + 1);
+ const int length = getFont()->getWidth(word);
+
+ if (length > mMinWidth)
+ mMinWidth = length;
+ }
do
{
@@ -73,7 +89,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,22 +101,46 @@ 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);
+ if (newlinePos == std::string::npos)
+ newlinePos = text.size();
+ 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());
if (text.find("\n", lastNewlinePos) != std::string::npos)
- {
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..10a81fc0 100644
--- a/src/gui/textbox.h
+++ b/src/gui/textbox.h
@@ -31,7 +31,8 @@
*
* \ingroup GUI
*/
-class TextBox : public gcn::TextBox {
+class TextBox : public gcn::TextBox
+{
public:
/**
* Constructor.
@@ -41,7 +42,15 @@ class TextBox : public gcn::TextBox {
/**
* Sets the text after wrapping it to the current width of the widget.
*/
- void setTextWrapped(const std::string &text);
+ void setTextWrapped(const std::string &text, int minDimension);
+
+ /**
+ * Get the minimum text width for the text box.
+ */
+ int getMinWidth() { return mMinWidth; }
+
+ private:
+ int mMinWidth;
};
#endif
diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp
index f7b02cbf..99a95a2e 100644
--- a/src/gui/textfield.cpp
+++ b/src/gui/textfield.cpp
@@ -19,14 +19,12 @@
* 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"
@@ -37,10 +35,13 @@
#undef DELETE //Win32 compatibility hack
int TextField::instances = 0;
+float TextField::mAlpha = config.getValue("guialpha", 0.8);
ImageRect TextField::skin;
TextField::TextField(const std::string& text):
- gcn::TextField(text)
+ gcn::TextField(text),
+ mNumeric(false),
+ mListener(0)
{
setFrameSize(2);
@@ -51,9 +52,6 @@ TextField::TextField(const std::string& text):
Image *textbox = resman->getImage("graphics/gui/deepbox.png");
int gridx[4] = {0, 3, 28, 31};
int gridy[4] = {0, 3, 28, 31};
- //Image *textbox = resman->getImage("graphics/gui/textbox.png");
- //int gridx[4] = {0, 5, 26, 31};
- //int gridy[4] = {0, 5, 26, 31};
int a = 0, x, y;
for (y = 0; y < 3; y++) {
@@ -62,6 +60,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++;
}
}
@@ -93,6 +92,15 @@ void TextField::draw(gcn::Graphics *graphics)
graphics->setColor(getForegroundColor());
graphics->setFont(getFont());
graphics->drawText(mText, 1 - mXScroll, 1);
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ for (int a = 0; a < 9; a++)
+ {
+ skin.grid[a]->setAlpha(mAlpha);
+ }
+ }
}
void TextField::drawFrame(gcn::Graphics *graphics)
@@ -105,6 +113,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..73824615 100644
--- a/src/gui/textfield.h
+++ b/src/gui/textfield.h
@@ -25,6 +25,13 @@
#include <guichan/widgets/textfield.hpp>
class ImageRect;
+class TextField;
+
+class TextFieldListener
+{
+ public:
+ virtual void listen(const TextField *value) = 0;
+};
/**
* A text field.
@@ -54,13 +61,48 @@ 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 float mAlpha;
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..af30d1fe 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,26 +30,28 @@
#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"
-#include "../resources/iteminfo.h"
-
#include "../utils/gettext.h"
#include "../utils/strprintf.h"
#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 +63,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 +110,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 +125,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 +181,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 +228,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 +245,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 +279,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..8e6636df 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;
@@ -92,7 +91,7 @@ TrueTypeFont::TrueTypeFont(const std::string &filename, int size)
++fontCounter;
mFont = TTF_OpenFont(filename.c_str(), size);
- if (mFont == NULL)
+ if (!mFont)
{
throw GCN_EXCEPTION("SDLTrueTypeFont::SDLTrueTypeFont: " +
std::string(TTF_GetError()));
diff --git a/src/gui/truetypefont.h b/src/gui/truetypefont.h
index 6f0671a2..cd68a94e 100644
--- a/src/gui/truetypefont.h
+++ b/src/gui/truetypefont.h
@@ -25,7 +25,6 @@
#include <string>
#include <guichan/font.hpp>
-#include <guichan/graphics.hpp>
#ifndef __APPLE__
#include <SDL/SDL_ttf.h>
#else
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index 96c2e95c..b3861b27 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>
@@ -28,23 +26,26 @@
#include <guichan/widgets/label.hpp>
+// Curl should be included after Guichan to avoid Windows redefinitions
+#include <curl/curl.h>
+
#include "browserbox.h"
#include "button.h"
#include "progressbar.h"
#include "scrollarea.h"
+#include "updatewindow.h"
-// Curl should be included after Guichan to avoid Windows redefinitions
-#include <curl/curl.h>
+#include "widgets/layout.h"
#include "../configuration.h"
#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,8 +69,7 @@ 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());
@@ -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);
@@ -210,7 +205,7 @@ void UpdaterWindow::loadNews()
// Tokenize and add each line separately
char *line = strtok(mMemoryBuffer, "\n");
- while (line != NULL)
+ while (line)
{
mBrowserBox->addRow(line);
line = strtok(NULL, "\n");
@@ -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++;
@@ -414,7 +408,7 @@ void UpdaterWindow::download()
mDownloadComplete = false;
mThread = SDL_CreateThread(UpdaterWindow::downloadThread, this);
- if (mThread == NULL)
+ if (!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());
diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h
index 3acbfb7e..4ada3c3a 100644
--- a/src/gui/updatewindow.h
+++ b/src/gui/updatewindow.h
@@ -23,13 +23,12 @@
#define _UPDATERWINDOW_H
#include <guichan/actionlistener.hpp>
+
#include <string>
#include <vector>
#include "window.h"
-#include "../guichanfwd.h"
-
#include "../utils/mutex.h"
class BrowserBox;
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index ff0883f7..f5a6edb4 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -19,33 +19,26 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "viewport.h"
-
-#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"
#include "../npc.h"
#include "../textmanager.h"
-#include "../resources/animation.h"
#include "../resources/monsterinfo.h"
#include "../resources/resourcemanager.h"
-#include "../resources/image.h"
-#include "../resources/imageset.h"
#include "../utils/tostring.h"
-#include <cassert>
-
extern volatile int tick_time;
Viewport::Viewport():
@@ -70,76 +63,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 +86,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 +167,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 +210,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
Beings &beings = beingManager->getAll();
for (BeingIterator i = beings.begin(); i != beings.end(); i++)
{
+ (*i)->drawSpeech(-(int) mPixelViewX, -(int) mPixelViewY);
(*i)->drawEmotion(graphics, -(int) mPixelViewX, -(int) mPixelViewY);
}
@@ -276,8 +221,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
WindowContainer::draw(gcnGraphics);
}
-void
-Viewport::logic()
+void Viewport::logic()
{
WindowContainer::logic();
@@ -294,49 +238,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 +252,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,13 +263,14 @@ 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)))
+ else if ((floorItem = floorItemManager->findByCoordinates(tilex,
+ tiley)))
{
mPopupMenu->showPopup(event.getX(), event.getY(), floorItem);
return;
@@ -384,9 +291,7 @@ Viewport::mousePressed(gcn::MouseEvent &event)
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 +305,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 +358,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..522ea734 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -27,15 +27,14 @@
#include "windowcontainer.h"
#include "../configlistener.h"
-#include "../being.h"
+#include "../position.h"
-class Map;
class FloorItem;
+class Graphics;
class ImageSet;
class Item;
+class Map;
class PopupMenu;
-class Graphics;
-class SimpleAnimation;
/**
* The viewport on the map. Displays the current map and handles mouse input
@@ -62,97 +61,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,22 +132,12 @@ 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;
PopupMenu *mPopupMenu; /**< Popup menu. */
};
+extern Viewport *viewport; /**< The viewport */
+
#endif
diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp
new file mode 100644
index 00000000..79d9ff06
--- /dev/null
+++ b/src/gui/widgets/dropdown.cpp
@@ -0,0 +1,203 @@
+/*
+ * 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 "../color.h"
+#include "../listbox.h"
+#include "../scrollarea.h"
+
+#include "../../configuration.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;
+float DropDown::mAlpha = config.getValue("guialpha", 0.8);
+
+DropDown::DropDown(gcn::ListModel *listModel, gcn::ScrollArea *scrollArea,
+ gcn::ListBox *listBox, bool opacity):
+ gcn::DropDown::DropDown(listModel, scrollArea, listBox),
+ mOpaque(opacity)
+{
+ 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");
+
+ buttons[0][0]->setAlpha(mAlpha);
+ buttons[0][1]->setAlpha(mAlpha);
+ buttons[1][0]->setAlpha(mAlpha);
+ buttons[1][1]->setAlpha(mAlpha);
+
+ // 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);
+ skin.grid[a]->setAlpha(mAlpha);
+ 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();
+ }
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+
+ buttons[0][0]->setAlpha(mAlpha);
+ buttons[0][1]->setAlpha(mAlpha);
+ buttons[1][0]->setAlpha(mAlpha);
+ buttons[1][1]->setAlpha(mAlpha);
+
+ for (int a = 0; a < 9; a++)
+ {
+ skin.grid[a]->setAlpha(mAlpha);
+ }
+ }
+
+ bool valid;
+ const int alpha = (int)(mAlpha * 255.0f);
+ gcn::Color faceColor = getBaseColor();
+ faceColor.a = alpha;
+ gcn::Color highlightColor = textColor->getColor('H', valid);
+ highlightColor.a = alpha;
+ gcn::Color shadowColor = faceColor - 0x303030;
+ shadowColor.a = alpha;
+
+ if (mOpaque)
+ {
+ int red = getBackgroundColor().r;
+ int green = getBackgroundColor().g;
+ int blue = getBackgroundColor().b;
+ graphics->setColor(gcn::Color(red, green, blue, alpha));
+ graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h));
+
+ red = getForegroundColor().r;
+ green = getForegroundColor().g;
+ blue = getForegroundColor().b;
+ graphics->setColor(gcn::Color(red, green, blue, alpha));
+ }
+
+ 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 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..e5919dc7
--- /dev/null
+++ b/src/gui/widgets/dropdown.h
@@ -0,0 +1,99 @@
+/*
+ * 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 <guichan/widgets/dropdown.hpp>
+
+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,
+ bool opacity = true);
+
+ /**
+ * Destructor.
+ */
+ ~DropDown();
+
+ void draw(gcn::Graphics* graphics);
+
+ void drawFrame(gcn::Graphics* graphics);
+
+ /**
+ * Sets the widget to be opaque, that is sets the widget to display its
+ * background.
+ *
+ * @param opaque True if the widget should be opaque, false otherwise.
+ */
+ void setOpaque(bool opaque) {mOpaque = opaque;}
+
+ /**
+ * Checks if the widget is opaque, that is if the widget area displays
+ * its background.
+ *
+ * @return True if the widget is opaque, false otherwise.
+ */
+ bool isOpaque() const {return mOpaque;}
+
+
+ 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;
+ static float mAlpha;
+
+ bool mOpaque;
+};
+
+#endif // end DROPDOWN_H
+
diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp
index 00689575..fa264e37 100644
--- a/src/gui/widgets/resizegrip.cpp
+++ b/src/gui/widgets/resizegrip.cpp
@@ -19,10 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "resizegrip.h"
-
#include <guichan/graphics.hpp>
+#include "resizegrip.h"
+
+#include "../../configuration.h"
#include "../../graphics.h"
#include "../../resources/image.h"
@@ -30,14 +31,16 @@
Image *ResizeGrip::gripImage = 0;
int ResizeGrip::mInstances = 0;
+float ResizeGrip::mAlpha = config.getValue("guialpha", 0.8);
-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);
+ gripImage->setAlpha(mAlpha);
}
mInstances++;
@@ -56,8 +59,13 @@ ResizeGrip::~ResizeGrip()
}
}
-void
-ResizeGrip::draw(gcn::Graphics *graphics)
+void ResizeGrip::draw(gcn::Graphics *graphics)
{
+ if (config.getValue("guialpha", 0.8) != mAlpha)
+ {
+ mAlpha = config.getValue("guialpha", 0.8);
+ gripImage->setAlpha(mAlpha);
+ }
+
static_cast<Graphics*>(graphics)->drawImage(gripImage, 0, 0);
}
diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h
index 5c6ea4bd..620c133f 100644
--- a/src/gui/widgets/resizegrip.h
+++ b/src/gui/widgets/resizegrip.h
@@ -39,7 +39,7 @@ class ResizeGrip : public gcn::Widget
/**
* Constructor.
*/
- ResizeGrip();
+ ResizeGrip(std::string image = "graphics/gui/resize.png");
/**
* Destructor.
@@ -54,6 +54,7 @@ class ResizeGrip : public gcn::Widget
private:
static Image *gripImage; /**< Resize grip image */
static int mInstances; /**< Number of resize grip instances */
+ static float mAlpha;
};
#endif
diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp
index c54b2390..21402c89 100644
--- a/src/gui/widgets/tab.cpp
+++ b/src/gui/widgets/tab.cpp
@@ -19,12 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
+#include <guichan/widgets/label.hpp>
#include "tab.h"
-
#include "tabbedarea.h"
+#include "../../configuration.h"
#include "../../graphics.h"
#include "../../resources/image.h"
@@ -33,6 +33,7 @@
#include "../../utils/dtor.h"
int Tab::mInstances = 0;
+float Tab::mAlpha = config.getValue("guialpha", 0.8);
enum{
TAB_STANDARD, // 0
@@ -50,10 +51,10 @@ struct TabData
};
static TabData const data[TAB_COUNT] = {
- {"graphics/gui/tab.png", 0, 0},
- {"graphics/gui/tab.png", 9, 4},
- {"graphics/gui/tabselected.png", 16, 19},
- {"graphics/gui/tab.png", 25, 23}
+ { "graphics/gui/tab.png", 0, 0 },
+ { "graphics/gui/tab.png", 9, 4 },
+ { "graphics/gui/tabselected.png", 16, 19 },
+ { "graphics/gui/tab.png", 25, 23 }
};
ImageRect Tab::tabImg[TAB_COUNT];
@@ -79,6 +80,7 @@ Tab::~Tab()
void Tab::init()
{
setFrameSize(0);
+ mHighlighted = false;
if (mInstances == 0)
{
@@ -98,6 +100,7 @@ void Tab::init()
data[x].gridX, data[y].gridY,
data[x + 1].gridX - data[x].gridX + 1,
data[y + 1].gridY - data[y].gridY + 1);
+ tabImg[mode].grid[a]->setAlpha(mAlpha);
a++;
}
}
@@ -109,16 +112,33 @@ void Tab::init()
void Tab::draw(gcn::Graphics *graphics)
{
- int mode;
+ int mode = TAB_STANDARD;
// check which type of tab to draw
- if (mTabbedArea && mTabbedArea->isTabSelected(this))
+ if (mTabbedArea)
{
- mode = TAB_SELECTED;
+ if (mTabbedArea->isTabSelected(this))
+ {
+ mode = TAB_SELECTED;
+ // if tab is selected, it doesnt need to highlight activity
+ mLabel->setForegroundColor(gcn::Color(0, 0, 0));
+ mHighlighted = false;
+ }
+ else if (mHighlighted)
+ {
+ mode = TAB_HIGHLIGHTED;
+ mLabel->setForegroundColor(gcn::Color(255, 0, 0));
+ }
}
- else
+
+ if (config.getValue("guialpha", 0.8) != mAlpha)
{
- mode = TAB_STANDARD;
+ mAlpha = config.getValue("guialpha", 0.8);
+ for (int a = 0; a < 9; a++)
+ {
+ tabImg[TAB_SELECTED].grid[a]->setAlpha(mAlpha);
+ tabImg[TAB_STANDARD].grid[a]->setAlpha(mAlpha);
+ }
}
// draw tab
@@ -128,3 +148,8 @@ void Tab::draw(gcn::Graphics *graphics)
// draw label
drawChildren(graphics);
}
+
+void Tab::setHighlighted(bool high)
+{
+ mHighlighted = high;
+}
diff --git a/src/gui/widgets/tab.h b/src/gui/widgets/tab.h
index 8382df83..3af4e2bf 100644
--- a/src/gui/widgets/tab.h
+++ b/src/gui/widgets/tab.h
@@ -47,12 +47,20 @@ class Tab : public gcn::Tab
*/
void draw(gcn::Graphics *graphics);
+ /**
+ * Set tab highlighted
+ */
+ void setHighlighted(bool high);
+
private:
/** Load images if no other instances exist yet */
void init();
static ImageRect tabImg[4]; /**< Tab state graphics */
static int mInstances; /**< Number of tab instances */
+ static float mAlpha;
+
+ bool mHighlighted;
};
#endif
diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp
index c4e22bff..5ff7c4bc 100644
--- a/src/gui/widgets/tabbedarea.cpp
+++ b/src/gui/widgets/tabbedarea.cpp
@@ -90,7 +90,7 @@ void TabbedArea::addTab(Tab *tab, gcn::Widget *widget)
mTabContainer->add(tab);
mTabs.push_back(std::pair<Tab*, gcn::Widget*>(tab, widget));
- if (mSelectedTab == NULL)
+ if (!mSelectedTab)
{
setSelectedTab(tab);
}
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index ed5bb8fc..797b4be9 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -24,11 +24,9 @@
#include <climits>
#include <guichan/exception.hpp>
-#include <guichan/widgets/icon.hpp>
-
-#include "window.h"
#include "gui.h"
+#include "window.h"
#include "windowcontainer.h"
#include "widgets/layout.h"
@@ -36,30 +34,30 @@
#include "../configlistener.h"
#include "../configuration.h"
-#include "../graphics.h"
#include "../log.h"
#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;
}
};
-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 +70,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 +120,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 +144,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();
}
}
@@ -199,6 +188,15 @@ void Window::draw(gcn::Graphics *graphics)
getPadding()
);
}
+
+ // Update window alpha values
+ if (mAlphaChanged)
+ {
+ for_each(border.grid, border.grid + 9,
+ std::bind2nd(std::mem_fun(&Image::setAlpha),
+ config.getValue("guialpha", 0.8)));
+ closeImage->setAlpha(config.getValue("guialpha", 0.8));
+ }
drawChildren(graphics);
}
@@ -524,6 +522,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.empty())
+ 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.empty())
+ {
+ 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..518de6e9 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..62704d1b 100644
--- a/src/gui/windowcontainer.h
+++ b/src/gui/windowcontainer.h
@@ -30,7 +30,8 @@
*
* \ingroup GUI
*/
-class WindowContainer : public gcn::Container {
+class WindowContainer : public gcn::Container
+{
public:
/**
* Do GUI logic. This functions adds automatic deletion of objects that
diff --git a/src/guichanfwd.h b/src/guichanfwd.h
index 2e97db68..4863421c 100644
--- a/src/guichanfwd.h
+++ b/src/guichanfwd.h
@@ -22,7 +22,8 @@
#ifndef GUICHANFWD_H
#define GUICHANFWD_H
-namespace gcn {
+namespace gcn
+{
class ActionListener;
class AllegroGraphics;
class AllegroImage;
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..3ca26e1e 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -19,30 +19,30 @@
* 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"
struct SlotUsed : public std::unary_function<Item*, bool>
{
- bool operator()(const Item *item) const {
+ bool operator()(const Item *item) const
+ {
return item && item->getId() != -1 && item->getQuantity() > 0;
}
};
-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,11 +58,10 @@ 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];
- }
+
return NULL;
}
@@ -73,46 +72,41 @@ 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) {
+ if (!mItems[index] && id > 0)
+ {
Item *item = new Item(id, quantity, equipment);
item->setInvIndex(index);
mItems[index] = item;
- } else if (id > 0) {
+ }
+ else if (id > 0)
+ {
mItems[index]->setId(id);
mItems[index]->setQuantity(quantity);
mItems[index]->setEquipment(equipment);
- } else if (mItems[index]) {
+ }
+ else if (mItems[index])
+ {
removeItemAt(index);
}
}
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++) {
- if (mItems[i] && mItems[i]->getId() == id) {
+ for (int i = 0; i < mSize; i++)
+ if (mItems[i] && mItems[i]->getId() == id)
removeItemAt(i);
- }
- }
}
void Inventory::removeItemAt(int index)
@@ -123,34 +117,30 @@ void Inventory::removeItemAt(int index)
bool Inventory::contains(Item *item) const
{
- for (int i = 0; i < INVENTORY_SIZE; i++) {
- if (mItems[i] && mItems[i]->getId() == item->getId()) {
+ for (int i = 0; i < mSize; i++)
+ if (mItems[i] && mItems[i]->getId() == item->getId())
return true;
- }
- }
return false;
}
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--) {
- if (SlotUsed()(mItems[i])) {
+ for (int i = mSize - 1; i >= 0; i--)
+ if (SlotUsed()(mItems[i]))
return i;
- }
- }
return -1;
}
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..3404b0e3 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"
@@ -34,9 +33,8 @@ ItemShortcut::ItemShortcut():
mItemSelected(-1)
{
for (int i = 0; i < SHORTCUT_ITEMS; i++)
- {
mItems[i] = -1;
- }
+
load();
}
@@ -52,9 +50,7 @@ void ItemShortcut::load()
int itemId = (int) config.getValue("shortcut" + toString(i), -1);
if (itemId != -1)
- {
mItems[i] = itemId;
- }
}
}
@@ -74,13 +70,15 @@ void ItemShortcut::useItem(int index)
Item *item = player_node->getInventory()->findItem(mItems[index]);
if (item && item->getQuantity())
{
- if (item->isEquipment()) {
- if (item->isEquipped()) {
+ if (item->isEquipment())
+ {
+ if (item->isEquipped())
player_node->unequipItem(item);
- } else {
+ else
player_node->equipItem(item);
- }
- } else {
+ }
+ else
+ {
player_node->useItem(item);
}
}
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..7e9a2285 100644
--- a/src/joystick.cpp
+++ b/src/joystick.cpp
@@ -19,13 +19,12 @@
* 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>
-
int Joystick::joystickCount = 0;
void Joystick::init()
diff --git a/src/joystick.h b/src/joystick.h
index aebd4b5f..4c5390c2 100644
--- a/src/joystick.h
+++ b/src/joystick.h
@@ -30,12 +30,16 @@ class Joystick
/**
* Number of buttons we can handle.
*/
- enum { MAX_BUTTONS = 6 };
+ enum
+ {
+ MAX_BUTTONS = 6
+ };
/**
* Directions, to be used as bitmask values.
*/
- enum {
+ enum
+ {
UP = 1,
DOWN = 2,
LEFT = 4,
diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp
index 9ae7ed68..5a0c0678 100644
--- a/src/keyboardconfig.cpp
+++ b/src/keyboardconfig.cpp
@@ -1,6 +1,6 @@
/*
- * The Mana World
- * Copyright (C) 2007 The Mana World Development Team
+ * Custom keyboard shortcuts configuration
+ * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au>
*
* This file is part of The Mana World.
*
@@ -19,52 +19,83 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "keyboardconfig.h"
#include "configuration.h"
+#include "keyboardconfig.h"
#include "log.h"
+#include "gui/sdlinput.h"
#include "gui/setup_keyboard.h"
+#include "utils/gettext.h"
+#include "utils/strprintf.h"
+
struct KeyData
{
const char *configField;
int defaultValue;
- const char *caption;
+ std::string caption;
};
// keyData must be in same order as enum keyAction.
static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = {
- {"keyMoveUp", SDLK_UP, "Move Up"},
- {"keyMoveDown", SDLK_DOWN, "Move Down"},
- {"keyMoveLeft", SDLK_LEFT, "Move Left"},
- {"keyMoveRight", SDLK_RIGHT, "Move Right"},
- {"keyAttack", SDLK_LCTRL, "Attack"},
- {"keySmilie", SDLK_LALT, "Smilie"},
- {"keyTarget", SDLK_LSHIFT, "Target"},
- {"keyTargetClosest", SDLK_a, "Target Closest"},
- {"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"},
- {"keyShortcut4", SDLK_4, "Item Shortcut 4"},
- {"keyShortcut5", SDLK_5, "Item Shortcut 5"},
- {"keyShortcut6", SDLK_6, "Item Shortcut 6"},
- {"keyShortcut7", SDLK_7, "Item Shortcut 7"},
- {"keyShortcut8", SDLK_8, "Item Shortcut 8"},
- {"keyShortcut9", SDLK_9, "Item Shortcut 9"},
- {"keyWindowStatus", SDLK_F2, "Status Window"},
- {"keyWindowInventory", SDLK_F3, "Inventory Window"},
- {"keyWindowEquipment", SDLK_F4, "Equipment WIndow"},
- {"keyWindowSkill", SDLK_F5, "Skill Window"},
- {"keyWindowMinimap", SDLK_F6, "Minimap Window"},
- {"keyWindowChat", SDLK_F7, "Chat Window"},
- {"keyWindowShortcut", SDLK_F8, "Item Shortcut Window"},
- {"keyWindowSetup", SDLK_F9, "Setup Window"},
- {"keyWindowDebug", SDLK_F10, "Debug Window"}
+ {"keyMoveUp", SDLK_UP, _("Move Up")},
+ {"keyMoveDown", SDLK_DOWN, _("Move Down")},
+ {"keyMoveLeft", SDLK_LEFT, _("Move Left")},
+ {"keyMoveRight", SDLK_RIGHT, _("Move Right")},
+ {"keyAttack", SDLK_LCTRL, _("Attack")},
+ {"keySmilie", SDLK_LALT, _("Smilie")},
+ {"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")},
+ {"keyScreenshot", SDLK_p, _("Screenshot")},
+ {"keyTrade", SDLK_r, _("Enable/Disable Trading")},
+ {"keyPathfind", SDLK_f, _("Find Path to Mouse")},
+ {"keyShortcut1", SDLK_1, strprintf(_("Item Shortcut %d"), 1)},
+ {"keyShortcut2", SDLK_2, strprintf(_("Item Shortcut %d"), 2)},
+ {"keyShortcut3", SDLK_3, strprintf(_("Item Shortcut %d"), 3)},
+ {"keyShortcut4", SDLK_4, strprintf(_("Item Shortcut %d"), 4)},
+ {"keyShortcut5", SDLK_5, strprintf(_("Item Shortcut %d"), 5)},
+ {"keyShortcut6", SDLK_6, strprintf(_("Item Shortcut %d"), 6)},
+ {"keyShortcut7", SDLK_7, strprintf(_("Item Shortcut %d"), 7)},
+ {"keyShortcut8", SDLK_8, strprintf(_("Item Shortcut %d"), 8)},
+ {"keyShortcut9", SDLK_9, strprintf(_("Item Shortcut %d"), 9)},
+ {"keyShortcut10", SDLK_0, strprintf(_("Item Shortcut %d"), 10)},
+ {"keyShortcut11", SDLK_MINUS, strprintf(_("Item Shortcut %d"), 11)},
+ {"keyShortcut12", SDLK_EQUALS, strprintf(_("Item Shortcut %d"), 12)},
+ {"keyWindowHelp", SDLK_F1, _("Help Window")},
+ {"keyWindowStatus", SDLK_F2, _("Status Window")},
+ {"keyWindowInventory", SDLK_F3, _("Inventory Window")},
+ {"keyWindowEquipment", SDLK_F4, _("Equipment WIndow")},
+ {"keyWindowSkill", SDLK_F5, _("Skill Window")},
+ {"keyWindowMinimap", SDLK_F6, _("Minimap Window")},
+ {"keyWindowChat", SDLK_F7, _("Chat Window")},
+ {"keyWindowShortcut", SDLK_F8, _("Item Shortcut Window")},
+ {"keyWindowSetup", SDLK_F9, _("Setup Window")},
+ {"keyWindowDebug", SDLK_F10, _("Debug Window")},
+ {"keyWindowEmote", SDLK_F11, _("Emote Window")},
+ {"keyWindowEmoteBar", SDLK_F12, _("Emote Shortcut Window")},
+ {"keyEmoteShortcut1", SDLK_1, strprintf(_("Emote Shortcut %d"), 1)},
+ {"keyEmoteShortcut2", SDLK_2, strprintf(_("Emote Shortcut %d"), 2)},
+ {"keyEmoteShortcut3", SDLK_3, strprintf(_("Emote Shortcut %d"), 3)},
+ {"keyEmoteShortcut4", SDLK_4, strprintf(_("Emote Shortcut %d"), 4)},
+ {"keyEmoteShortcut5", SDLK_5, strprintf(_("Emote Shortcut %d"), 5)},
+ {"keyEmoteShortcut6", SDLK_6, strprintf(_("Emote Shortcut %d"), 6)},
+ {"keyEmoteShortcut7", SDLK_7, strprintf(_("Emote Shortcut %d"), 7)},
+ {"keyEmoteShortcut8", SDLK_8, strprintf(_("Emote Shortcut %d"), 8)},
+ {"keyEmoteShortcut9", SDLK_9, strprintf(_("Emote Shortcut %d"), 9)},
+ {"keyEmoteShortcut10", SDLK_0, strprintf(_("Emote Shortcut %d"), 10)},
+ {"keyEmoteShortcut11", SDLK_MINUS, strprintf(_("Emote Shortcut %d"), 11)},
+ {"keyEmoteShortcut12", SDLK_EQUALS, strprintf(_("Emote Shortcut %d"), 12)},
+ {"keyChat", SDLK_RETURN, _("Toggle Chat")},
+ {"keyChatScrollUp", SDLK_PAGEUP, _("Scroll Chat Up")},
+ {"keyChatScrollDown", SDLK_PAGEDOWN, _("Scroll Chat Down")},
+ {"keyOK", SDLK_RETURN, _("Select OK")},
+ {"keyQuit", SDLK_ESCAPE, _("Quit")}
};
void KeyboardConfig::init()
@@ -110,11 +141,20 @@ 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))) ||
+ ((i == KEY_TOGGLE_CHAT) && (j == KEY_OK))) &&
+ (mKey[i].value == mKey[j].value)
+ )
{
return true;
}
@@ -132,7 +172,7 @@ int KeyboardConfig::getKeyIndex(int keyValue) const
{
for (int i = 0; i < KEY_TOTAL; i++)
{
- if(keyValue == mKey[i].value)
+ if (keyValue == mKey[i].value)
{
return i;
}
@@ -140,6 +180,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..8949a48e 100644
--- a/src/keyboardconfig.h
+++ b/src/keyboardconfig.h
@@ -1,6 +1,6 @@
/*
- * The Mana World
- * Copyright (C) 2007 The Mana World Development Team
+ * Custom keyboard shortcuts configuration
+ * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au>
*
* This file is part of The Mana World.
*
@@ -22,11 +22,9 @@
#ifndef KEYBOARDCONFIG_H
#define KEYBOARDCONFIG_H
+#include <SDL_types.h>
#include <string>
-#include "gui/sdlinput.h"
-#include "gui/setup_keyboard.h"
-
/**
* Each key represents a key function. Such as 'Move up', 'Attack' etc.
*/
@@ -38,6 +36,8 @@ struct KeyFunction
int value; /** The actual value that is used. */
};
+class Setup_Keyboard;
+
class KeyboardConfig
{
public:
@@ -101,6 +101,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)
@@ -141,21 +146,26 @@ class KeyboardConfig
* The key assignment view gets arranged according to the order of
* these values.
*/
- enum KeyAction {
+ enum KeyAction
+ {
KEY_NO_VALUE = -1,
KEY_MOVE_UP,
KEY_MOVE_DOWN,
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_SCREENSHOT,
+ KEY_TRADE,
+ KEY_PATHFIND,
KEY_SHORTCUT_1,
KEY_SHORTCUT_2,
KEY_SHORTCUT_3,
@@ -165,6 +175,10 @@ class KeyboardConfig
KEY_SHORTCUT_7,
KEY_SHORTCUT_8,
KEY_SHORTCUT_9,
+ KEY_SHORTCUT_10,
+ KEY_SHORTCUT_11,
+ KEY_SHORTCUT_12,
+ KEY_WINDOW_HELP,
KEY_WINDOW_STATUS,
KEY_WINDOW_INVENTORY,
KEY_WINDOW_EQUIPMENT,
@@ -174,6 +188,25 @@ 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_TOGGLE_CHAT,
+ KEY_SCROLL_CHAT_UP,
+ KEY_SCROLL_CHAT_DOWN,
+ KEY_OK,
+ KEY_QUIT,
KEY_TOTAL
};
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 07044ce7..a02a8b1b 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -18,19 +18,23 @@
* 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 "graphics.h"
#include "inventory.h"
#include "item.h"
-#include "main.h"
+#include "localplayer.h"
+#include "map.h"
+#include "monster.h"
#include "particle.h"
+#include "simpleanimation.h"
#include "sound.h"
-#include "monster.h"
#include "statuseffect.h"
+#include "text.h"
#include "gui/gui.h"
#include "gui/ministatus.h"
@@ -38,10 +42,18 @@
#include "net/messageout.h"
#include "net/protocol.h"
+#include "resources/animation.h"
+#include "resources/image.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),
@@ -57,23 +69,56 @@ LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map):
ATK_BONUS(0), MATK_BONUS(0), DEF_BONUS(0), MDEF_BONUS(0), FLEE_BONUS(0),
mStatPoint(0), mSkillPoint(0),
mStatsPointsToAttribute(0),
+ mEquipment(new Equipment()),
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 +136,6 @@ void LocalPlayer::logic()
mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed;
if (mFrame >= frames) {
nextStep();
- attack();
}
break;
}
@@ -100,10 +144,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 +339,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 || target == mTarget)
+ {
+ target = NULL;
+ mKeepAttacking = false;
+ mTargetTime = -1;
+ }
+ if (target)
+ {
+ mTargetTime = tick_time;
}
if (mTarget && mTarget->getType() == Being::MONSTER)
{
@@ -384,25 +493,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,13 +527,19 @@ 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)
{
std::string soundFile = mEquippedWeapon->getSound(EQUIP_EVENT_STRIKE);
- if (soundFile != "") sound.playSfx(soundFile);
+ if (!soundFile.empty())
+ sound.playSfx(soundFile);
}
else {
sound.playSfx("sfx/fist-swish.ogg");
@@ -434,11 +549,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 +607,7 @@ bool LocalPlayer::withinAttackRange(Being *target)
void LocalPlayer::setGotoTarget(Being *target)
{
+ mLastTarget = -1;
setTarget(target);
mGoingToTarget = true;
setDestination(target->mX, target->mY);
@@ -527,3 +654,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..c128f4a4 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -22,6 +22,7 @@
#ifndef LOCALPLAYER_H
#define LOCALPLAYER_H
+#include <memory>
#include <vector>
#include "player.h"
@@ -29,10 +30,17 @@
// TODO move into some sane place...
#define MAX_SLOT 2
+#define INVENTORY_SIZE 102
+#define STORAGE_SIZE 301
+
+class Equipment;
class FloorItem;
+class ImageSet;
class Inventory;
class Item;
+class Map;
class Network;
+class SimpleAnimation;
/**
* The local player character.
@@ -40,7 +48,8 @@ class Network;
class LocalPlayer : public Player
{
public:
- enum Attribute {
+ enum Attribute
+ {
STR = 0, AGI, VIT, INT, DEX, LUK
};
@@ -54,7 +63,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 +80,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 +132,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 +188,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 +226,22 @@ 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];
+
+ const std::auto_ptr<Equipment> mEquipment;
+
protected:
virtual void
handleStatusEffect(StatusEffect *effect, int effectId);
@@ -211,15 +255,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/log.cpp b/src/log.cpp
index e50edeb2..b0024f80 100644
--- a/src/log.cpp
+++ b/src/log.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <cstdarg>
-#include <cstdlib>
#include <iostream>
#include <sstream>
diff --git a/src/log.h b/src/log.h
index fcd48757..b06bdc89 100644
--- a/src/log.h
+++ b/src/log.h
@@ -22,7 +22,6 @@
#ifndef _LOG_H
#define _LOG_H
-#include <iosfwd>
#include <fstream>
class ChatWindow;
diff --git a/src/main.cpp b/src/main.cpp
index 91ae87e9..54320433 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,48 +19,43 @@
* 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/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/button.h"
#include "gui/char_server.h"
#include "gui/char_select.h"
+#include "gui/color.h"
#include "gui/gui.h"
#include "gui/login.h"
#include "gui/ok_dialog.h"
@@ -68,7 +63,6 @@
#include "gui/register.h"
#include "gui/sdlinput.h"
#include "gui/setup.h"
-#include "gui/textfield.h"
#include "gui/updatewindow.h"
#include "net/charserverhandler.h"
@@ -77,17 +71,35 @@
#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"
#include "resources/npcdb.h"
#include "resources/resourcemanager.h"
-#include "utils/dtor.h"
#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 +135,7 @@ CharServerHandler charServerHandler;
LoginData loginData;
LockedArray<LocalPlayer*> charInfo(MAX_SLOT + 1);
+Color *textColor;
// This anonymous namespace hides whatever is inside from other modules.
namespace {
@@ -168,10 +181,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 +197,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 {
+ 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;
+ errorMessage = _("Invalid update host: ") + updateHost;
state = ERROR_STATE;
}
- } else {
+ }
+ else
+ {
logger->log("Warning: no protocol was specified for the update host");
- updatesDir = "updates/" + updateHost;
+ 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)) {
+ 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!";
+ homeDir.c_str(), updatesDir.c_str());
+ errorMessage = _("Error creating updates directory!");
state = ERROR_STATE;
+#endif
}
}
}
@@ -231,7 +277,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);
}
@@ -248,7 +294,7 @@ void init_engine(const Options &options)
// Initialize 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);
}
@@ -261,7 +307,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);
}
@@ -281,18 +327,18 @@ 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);
resman->addToSearchPath(path, true);
#else
- resman->addToSearchPath(TMW_DATADIR "data", true);
+ resman->addToSearchPath(PKG_DATADIR "data", true);
#endif
// Fill configuration with defaults
logger->log("Initializing configuration...");
- config.setValue("host", "server.themanaworld.org");
+ config.setValue("host", "www.themanaworld.org");
config.setValue("port", 6901);
config.setValue("hwaccel", 0);
#if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL
@@ -313,24 +359,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);
}
@@ -344,7 +390,7 @@ void init_engine(const Options &options)
SetClassLong(pInfo.window, GCL_HICON, (LONG) icon);
}
#else
- SDL_Surface *icon = IMG_Load(TMW_DATADIR "data/icons/tmw.png");
+ SDL_Surface *icon = IMG_Load(PKG_DATADIR "data/icons/tmw.png");
if (icon)
{
SDL_SetAlpha(icon, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
@@ -365,17 +411,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);
}
@@ -386,6 +432,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 */
@@ -417,6 +466,7 @@ void exit_engine()
{
// Before config.write() since it writes the shortcuts to the config
delete itemShortcut;
+ delete emoteShortcut;
config.write();
@@ -430,6 +480,8 @@ void exit_engine()
sound.close();
// Unload XML databases
+ ColorDB::unload();
+ EmoteDB::unload();
ItemDB::unload();
MonsterDB::unload();
NPCDB::unload();
@@ -441,28 +493,28 @@ 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
- << " -S --homedir : Directory to use as home directory" << 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
+ << _(" -S --homedir : Directory to use as home directory") << 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
}
@@ -471,17 +523,17 @@ void parseOptions(int argc, char *argv[], Options &options)
const char *optstring = "hvud:U:P:Dp:C:H:S:";
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' },
- { "updatehost", required_argument, 0, 'H' },
+ { "password", required_argument, 0, 'P' },
+ { "help", no_argument, 0, 'h' },
{ "homedir", required_argument, 0, 'S' },
+ { "updatehost", required_argument, 0, 'H' },
+ { "skipupdate", no_argument, 0, 'u' },
+ { "username", required_argument, 0, 'U' },
+ { "version", no_argument, 0, 'v' },
{ 0 }
};
@@ -493,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;
case 'S':
homeDir = optarg;
@@ -603,6 +655,13 @@ void accountLogin(Network *network, LoginData *loginData)
config.setValue("remember", loginData->remember);
}
+static void positionDialog(Window *dialog, int screenWidth, int screenHeight)
+{
+ dialog->setPosition(
+ (screenWidth - dialog->getWidth()) / 2,
+ (screenHeight - dialog->getHeight()) / 2);
+}
+
void charLogin(Network *network, LoginData *loginData)
{
logger->log("Trying to connect to char server...");
@@ -706,6 +765,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
+ textColor = new Color();
+
Game *game = NULL;
Window *currentDialog = NULL;
Image *login_wallpaper = NULL;
@@ -716,7 +778,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(),
@@ -738,12 +800,37 @@ 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";
+
+ if (!ResourceManager::getInstance()->exists(wallpaperName))
+ wallpaperName = "graphics/images/login_wallpaper.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
@@ -779,16 +866,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);
@@ -817,7 +894,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
@@ -856,9 +933,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;
@@ -870,33 +950,50 @@ 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.empty())
+ {
+ ((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))
@@ -908,6 +1005,7 @@ int main(int argc, char *argv[])
if (options.chooseDefault)
((CharSelectDialog*) currentDialog)->action(
gcn::ActionEvent(NULL, "ok"));
+
break;
case GAME_STATE:
@@ -945,13 +1043,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();
@@ -988,8 +1094,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 textColor;
#ifdef PACKAGE_VERSION
delete versionLabel;
#endif
diff --git a/src/main.h b/src/main.h
index 7a7be624..42696568 100644
--- a/src/main.h
+++ b/src/main.h
@@ -32,8 +32,8 @@
#define PACKAGE_VERSION "0.0.28.1"
#endif
-#ifndef TMW_DATADIR
-#define TMW_DATADIR ""
+#ifndef PKG_DATADIR
+#define PKG_DATADIR ""
#endif
/*
diff --git a/src/map.cpp b/src/map.cpp
index f0c84159..b5e815f3 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"
@@ -68,6 +68,7 @@ TileAnimation::TileAnimation(Animation *ani):
{
}
+
void TileAnimation::update()
{
//update animation
@@ -136,6 +137,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 +258,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 +550,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..3beab350 100644
--- a/src/map.h
+++ b/src/map.h
@@ -27,9 +27,9 @@
#include "position.h"
#include "properties.h"
-
#include "simpleanimation.h"
+class Animation;
class AmbientOverlay;
class Graphics;
class Image;
@@ -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..8f56560b 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -19,18 +19,16 @@
* 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"
-
-#include "utils/tostring.h"
+#include "resources/monsterinfo.h"
static const int NAME_X_OFFSET = 16;
static const int NAME_Y_OFFSET = 16;
@@ -44,6 +42,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 +60,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()
{
if (mText)
{
- player_node->setTarget(0);
+ delete mText;
+ player_node->setTarget(NULL);
}
}
@@ -99,9 +103,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 +121,34 @@ void Monster::setAction(Uint8 action)
case ATTACK:
currentAction = ACTION_ATTACK;
mSprites[BASE_SPRITE]->reset();
+
+ //attack particle effect
+ particleEffect = getInfo().getAttackParticleEffect();
+ if (!particleEffect.empty() && 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 +191,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..d3ba4b03 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -19,24 +19,22 @@
* 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 "../particle.h"
-#include "../sound.h"
-#include <iostream>
-#include "../player_relations.h"
#include "../npc.h"
+#include "../player_relations.h"
+#include "../sound.h"
const int EMOTION_TIME = 150; /**< Duration of emotion icon */
@@ -73,6 +71,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 +210,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 +238,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 +271,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 +443,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 +479,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 +506,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:
@@ -544,4 +541,3 @@ void BeingHandler::handleMessage(MessageIn *msg)
break;
}
}
-
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..67c79ec4 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"
@@ -36,9 +35,11 @@
#include "../gui/chat.h"
#include "../gui/sell.h"
+#include "../utils/gettext.h"
+
extern BuyDialog *buyDialog;
-extern SellDialog *sellDialog;
extern Window *buySellDialog;
+extern SellDialog *sellDialog;
BuySellHandler::BuySellHandler()
{
@@ -105,27 +106,27 @@ void BuySellHandler::handleMessage(MessageIn *msg)
}
}
else {
- chatWindow->chatLog("Nothing to sell", BY_SERVER);
+ chatWindow->chatLog(_("Nothing to sell"), BY_SERVER);
current_npc = 0;
}
break;
case SMSG_NPC_BUY_RESPONSE:
if (msg->readInt8() == 0) {
- chatWindow->chatLog("Thanks for buying", BY_SERVER);
+ chatWindow->chatLog(_("Thanks for buying"), BY_SERVER);
} else {
// Reset player money since buy dialog already assumed purchase
// would go fine
buyDialog->setMoney(player_node->mGp);
- chatWindow->chatLog("Unable to buy", BY_SERVER);
+ chatWindow->chatLog(_("Unable to buy"), BY_SERVER);
}
break;
case SMSG_NPC_SELL_RESPONSE:
if (msg->readInt8() == 0) {
- chatWindow->chatLog("Thanks for selling", BY_SERVER);
+ chatWindow->chatLog(_("Thanks for selling"), BY_SERVER);
} else {
- chatWindow->chatLog("Unable to sell", BY_SERVER);
+ chatWindow->chatLog(_("Unable to sell"), BY_SERVER);
}
break;
}
diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp
index f00615d7..932cf705 100644
--- a/src/net/charserverhandler.cpp
+++ b/src/net/charserverhandler.cpp
@@ -20,9 +20,7 @@
*/
#include "charserverhandler.h"
-
#include "messagein.h"
-#include "network.h"
#include "protocol.h"
#include "../game.h"
@@ -31,8 +29,11 @@
#include "../logindata.h"
#include "../main.h"
-#include "../gui/ok_dialog.h"
#include "../gui/char_select.h"
+#include "../gui/ok_dialog.h"
+
+#include "../utils/gettext.h"
+#include "../utils/tostring.h"
CharServerHandler::CharServerHandler():
mCharCreateDialog(0)
@@ -53,7 +54,7 @@ CharServerHandler::CharServerHandler():
void CharServerHandler::handleMessage(MessageIn *msg)
{
- int slot, code;
+ int slot, flags, code;
LocalPlayer *tempPlayer;
logger->log("CharServerHandler: Packet ID: %x, Length: %d",
@@ -66,30 +67,32 @@ void CharServerHandler::handleMessage(MessageIn *msg)
switch (code) {
case 0:
- errorMessage = "Authentication failed";
+ errorMessage = _("Authentication failed");
break;
case 1:
- errorMessage = "Map server(s) offline";
+ errorMessage = _("Map server(s) offline");
break;
case 2:
- errorMessage = "This account is already logged in";
+ errorMessage = _("This account is already logged in");
break;
case 3:
- errorMessage = "Speed hack detected";
+ errorMessage = _("Speed hack detected");
break;
case 8:
- errorMessage = "Duplicated login";
+ errorMessage = _("Duplicated login");
break;
default:
- errorMessage = "Unknown connection error";
+ errorMessage = _("Unknown connection error");
break;
}
state = ERROR_STATE;
break;
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);
+ msg->skip(16); // Unused
// Derive number of characters from message length
n_character = (msg->getLength() - 24) / 106;
@@ -100,7 +103,7 @@ void CharServerHandler::handleMessage(MessageIn *msg)
mCharInfo->select(slot);
mCharInfo->setEntry(tempPlayer);
logger->log("CharServer: Player: %s (%d)",
- tempPlayer->getName().c_str(), slot);
+ tempPlayer->getName().c_str(), slot);
}
state = CHAR_SELECT_STATE;
@@ -109,13 +112,13 @@ void CharServerHandler::handleMessage(MessageIn *msg)
case 0x006c:
switch (msg->readInt8()) {
case 0:
- errorMessage = "Access denied";
+ errorMessage = _("Access denied");
break;
case 1:
- errorMessage = "Cannot use this ID";
+ errorMessage = _("Cannot use this ID");
break;
default:
- errorMessage = "Unknown failure to select character";
+ errorMessage = _("Unknown failure to select character");
break;
}
mCharInfo->unlock();
@@ -137,8 +140,8 @@ void CharServerHandler::handleMessage(MessageIn *msg)
break;
case 0x006e:
- new OkDialog("Error", "Failed to create character. Most likely"
- " the name is already taken.");
+ new OkDialog(_("Error"), _("Failed to create character. Most likely"
+ " the name is already taken."));
if (mCharCreateDialog)
mCharCreateDialog->unlock();
@@ -149,12 +152,12 @@ void CharServerHandler::handleMessage(MessageIn *msg)
mCharInfo->setEntry(0);
mCharInfo->unlock();
n_character--;
- new OkDialog("Info", "Player deleted");
+ new OkDialog(_("Info"), _("Player deleted"));
break;
case 0x0070:
mCharInfo->unlock();
- new OkDialog("Error", "Failed to delete character.");
+ new OkDialog(_("Error"), _("Failed to delete character."));
break;
case 0x0071:
diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp
index d25d4bcd..25877907 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"
@@ -34,6 +33,7 @@
#include "../gui/chat.h"
+#include "../utils/gettext.h"
#include "../utils/tostring.h"
#include "../utils/trim.h"
@@ -73,10 +73,10 @@ void ChatHandler::handleMessage(MessageIn *msg)
//chatWindow->chatLog("Whisper sent", BY_SERVER);
break;
case 0x01:
- chatWindow->chatLog("Whisper could not be sent, user is offline", BY_SERVER);
+ chatWindow->chatLog(_("Whisper could not be sent, user is offline"), BY_SERVER);
break;
case 0x02:
- chatWindow->chatLog("Whisper could not be sent, ignored by user", BY_SERVER);
+ chatWindow->chatLog(_("Whisper could not be sent, ignored by user"), BY_SERVER);
break;
}
break;
diff --git a/src/net/equipmenthandler.cpp b/src/net/equipmenthandler.cpp
index e5bbf6fe..9a3c396a 100644
--- a/src/net/equipmenthandler.cpp
+++ b/src/net/equipmenthandler.cpp
@@ -20,11 +20,9 @@
*/
#include "equipmenthandler.h"
-
#include "messagein.h"
#include "protocol.h"
-#include "../beingmanager.h"
#include "../equipment.h"
#include "../inventory.h"
#include "../item.h"
@@ -33,6 +31,8 @@
#include "../gui/chat.h"
+#include "../utils/gettext.h"
+
EquipmentHandler::EquipmentHandler()
{
static const Uint16 _messages[] = {
@@ -98,7 +98,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
logger->log("Equipping: %i %i %i", index, equipPoint, type);
if (!type) {
- chatWindow->chatLog("Unable to equip.", BY_SERVER);
+ chatWindow->chatLog(_("Unable to equip."), BY_SERVER);
break;
}
@@ -107,7 +107,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 +118,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);
}
@@ -130,7 +136,7 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
type = msg->readInt8();
if (!type) {
- chatWindow->chatLog("Unable to unequip.", BY_SERVER);
+ chatWindow->chatLog(_("Unable to unequip."), BY_SERVER);
break;
}
@@ -152,24 +158,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 +179,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..46f03e28 100644
--- a/src/net/inventoryhandler.cpp
+++ b/src/net/inventoryhandler.cpp
@@ -19,22 +19,24 @@
* 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/gettext.h"
+#include "../utils/strprintf.h"
#include "../utils/tostring.h"
InventoryHandler::InventoryHandler()
@@ -45,6 +47,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 +61,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,21 +132,22 @@ 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);
+ chatWindow->chatLog(_("Unable to pick up item"), BY_SERVER);
} else {
const ItemInfo &itemInfo = ItemDB::get(itemId);
const std::string amountStr =
(amount > 1) ? toString(amount) : "a";
- chatWindow->chatLog("You picked up " + amountStr + " " +
- itemInfo.getName(), BY_SERVER);
+ chatWindow->chatLog(strprintf(_("You picked up %s %s"),
+ amountStr.c_str(), itemInfo.getName().c_str()), BY_SERVER);
if (Item *item = inventory->getItem(index)) {
item->setId(itemId);
@@ -141,11 +184,44 @@ void InventoryHandler::handleMessage(MessageIn *msg)
amount = msg->readInt16();
if (msg->readInt8() == 0) {
- chatWindow->chatLog("Failed to use item", BY_SERVER);
+ chatWindow->chatLog(_("Failed to use item"), BY_SERVER);
} else {
if (Item *item = inventory->getItem(index))
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 c9eec9f4..4fd0f373 100644
--- a/src/net/loginhandler.cpp
+++ b/src/net/loginhandler.cpp
@@ -20,9 +20,7 @@
*/
#include "loginhandler.h"
-
#include "messagein.h"
-#include "network.h"
#include "protocol.h"
#include "../log.h"
@@ -30,6 +28,10 @@
#include "../main.h"
#include "../serverinfo.h"
+#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
+#include "../utils/tostring.h"
+
extern SERVER_INFO **server_info;
LoginHandler::LoginHandler()
@@ -56,16 +58,16 @@ void LoginHandler::handleMessage(MessageIn *msg)
switch (code) {
case 0:
- errorMessage = "Authentication failed";
+ errorMessage = _("Authentication failed");
break;
case 1:
- errorMessage = "No servers available";
+ errorMessage = _("No servers available");
break;
case 2:
- errorMessage = "This account is already logged in";
+ errorMessage = _("This account is already logged in");
break;
default:
- errorMessage = "Unknown connection error";
+ errorMessage = _("Unknown connection error");
break;
}
state = ERROR_STATE;
@@ -78,7 +80,7 @@ void LoginHandler::handleMessage(MessageIn *msg)
mUpdateHost = msg->readString(len);
logger->log("Received update host \"%s\" from login server",
- mUpdateHost.c_str());
+ mUpdateHost.c_str());
break;
case 0x0069:
@@ -120,30 +122,34 @@ void LoginHandler::handleMessage(MessageIn *msg)
switch (code) {
case 0:
- errorMessage = "Unregistered ID";
+ errorMessage = _("Unregistered ID");
break;
case 1:
- errorMessage = "Wrong password";
+ errorMessage = _("Wrong password");
break;
case 2:
- errorMessage = "Account expired";
+ errorMessage = _("Account expired");
break;
case 3:
- errorMessage = "Rejected from server";
+ errorMessage = _("Rejected from server");
break;
case 4:
- errorMessage = "You have been permanently banned from the game. Please contact the GM Team";
+ errorMessage = _("You have been permanently banned from "
+ "the game. Please contact the GM Team.");
break;
case 6:
- errorMessage = "You have been temporarily banned from the game until "
- + msg->readString(20) + ".\n Please contact the GM team via the forums";
+ errorMessage = strprintf(_("You have been temporarily "
+ "banned from the game until "
+ "%s.\n Please contact the GM "
+ "team via the forums."),
+ msg->readString(20).c_str());
break;
case 9:
- errorMessage = "This user name is already taken";
+ errorMessage = _("This user name is already taken");
break;
default:
- errorMessage = "Unknown error";
+ errorMessage = _("Unknown error");
break;
}
state = ERROR_STATE;
diff --git a/src/net/loginhandler.h b/src/net/loginhandler.h
index a380c767..df86b634 100644
--- a/src/net/loginhandler.h
+++ b/src/net/loginhandler.h
@@ -22,9 +22,10 @@
#ifndef NET_LOGINHANDLER_H
#define NET_LOGINHANDLER_H
-#include "messagehandler.h"
#include <string>
+#include "messagehandler.h"
+
struct LoginData;
class LoginHandler : public MessageHandler
diff --git a/src/net/maploginhandler.cpp b/src/net/maploginhandler.cpp
index 68652c79..b5192bd7 100644
--- a/src/net/maploginhandler.cpp
+++ b/src/net/maploginhandler.cpp
@@ -20,7 +20,6 @@
*/
#include "maploginhandler.h"
-
#include "messagein.h"
#include "protocol.h"
@@ -28,6 +27,8 @@
#include "../log.h"
#include "../main.h"
+#include "../utils/gettext.h"
+
MapLoginHandler::MapLoginHandler()
{
static const Uint16 _messages[] = {
@@ -51,13 +52,13 @@ void MapLoginHandler::handleMessage(MessageIn *msg)
switch (code) {
case 0:
- errorMessage = "Authentication failed";
+ errorMessage = _("Authentication failed");
break;
case 2:
- errorMessage = "This account is already logged in";
+ errorMessage = _("This account is already logged in");
break;
default:
- errorMessage = "Unknown connection error";
+ errorMessage = _("Unknown connection error");
break;
}
state = ERROR_STATE;
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..059da779 100644
--- a/src/net/network.cpp
+++ b/src/net/network.cpp
@@ -19,14 +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>
+#include "../utils/tostring.h"
/** Warning: buffers and other variables are shared,
so there can be only one connection active at a time */
@@ -419,21 +419,7 @@ void Network::receive()
SDLNet_FreeSocketSet(set);
}
-char *iptostring(int address)
-{
- static char asciiIP[16];
-
- sprintf(asciiIP, "%i.%i.%i.%i",
- (unsigned char)(address),
- (unsigned char)(address >> 8),
- (unsigned char)(address >> 16),
- (unsigned char)(address >> 24));
-
- 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..02fe7538 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;
@@ -133,7 +115,4 @@ class Network
MessageHandlers mMessageHandlers;
};
-/** Convert an address from int format to string */
-char *iptostring(int address);
-
#endif
diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp
index b0314e47..ea03537f 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,17 +69,17 @@ 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;
+ current_npc = NULL;
break;
case SMSG_NPC_NEXT:
@@ -91,6 +92,7 @@ void NPCHandler::handleMessage(MessageIn *msg)
current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcIntegerDialog->setRange(0, 2147483647);
npcIntegerDialog->setVisible(true);
+ npcIntegerDialog->requestFocus();
break;
case SMSG_NPC_STR_INPUT:
@@ -99,6 +101,7 @@ void NPCHandler::handleMessage(MessageIn *msg)
current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcStringDialog->setValue("");
npcStringDialog->setVisible(true);
+ npcStringDialog->requestFocus();
break;
}
}
diff --git a/src/net/partyhandler.cpp b/src/net/partyhandler.cpp
new file mode 100644
index 00000000..fe7db55d
--- /dev/null
+++ b/src/net/partyhandler.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "../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)
+ {
+ 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..048da9b1
--- /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..cfdfbe63 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;
@@ -50,8 +51,9 @@ extern BuyDialog *buyDialog;
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. */
+// Max. distance we are willing to scroll after a teleport;
+// everything beyond will reset the port hard.
+static const int MAP_TELEPORT_SCROLL_DISTANCE = 8;
/**
* Listener used for handling the overweigth message.
@@ -110,10 +112,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 +135,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 +147,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;
}
@@ -153,7 +158,9 @@ void PlayerHandler::handleMessage(MessageIn *msg)
player_node->mX = x;
player_node->mY = y;
- logger->log("Adjust scrolling by %d:%d", (int)scrollOffsetX, (int)scrollOffsetY);
+ logger->log("Adjust scrolling by %d:%d",
+ (int)scrollOffsetX,
+ (int)scrollOffsetY);
viewport->scrollBy(scrollOffsetX, scrollOffsetY);
}
@@ -173,6 +180,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 +193,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 than "
+ "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 +211,57 @@ 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)
+ if (player_node->mHp == 0 && !deathNotice)
{
- 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."),
+ // NetHack reference:
+ _("Do you want your possessions identified?"),
+ // Secret of Mana reference:
+ _("Sadly, no trace of you was ever found..."),
+ // Final Fantasy VI reference:
+ _("Annihilated."),
+ // Earthbound reference:
+ _("Looks like you got your head handed to you."),
+ // Leisure Suit Larry 1 reference:
+ _("You screwed up again, dump your body down the tubes "
+ "and get you another one."),
+ // Monty Python references (Dead Parrot sketch mostly):
+ _("You're not dead yet. You're just resting."),
+ _("You are no more."),
+ _("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.")
+ };
+ std::string message(deadMsg[rand()%27]);
+
+ deathNotice = new OkDialog(_("Message"), message);
deathNotice->addActionListener(&deathListener);
player_node->setAction(Being::DEAD);
}
@@ -229,7 +280,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 +344,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,7 +403,7 @@ void PlayerHandler::handleMessage(MessageIn *msg)
switch (type) {
case 0:
- chatWindow->chatLog("Equip arrows first",
+ chatWindow->chatLog(_("Equip arrows first"),
BY_SERVER);
break;
default:
@@ -361,18 +412,5 @@ void PlayerHandler::handleMessage(MessageIn *msg)
}
}
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 3bdeb429..e9053451 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_CONNECTION_PROBLEM 0x0081
#define SMSG_UPDATE_HOST 0x0063 /**< Custom update host packet */
#define SMSG_PLAYER_UPDATE_1 0x01d8
@@ -67,6 +70,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
@@ -83,6 +87,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
@@ -91,7 +96,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
@@ -100,6 +125,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
@@ -118,6 +145,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..c5465835 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..dfbc7d16 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -19,15 +19,15 @@
* 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 +36,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 +54,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..e7e7b204 100644
--- a/src/openglgraphics.cpp
+++ b/src/openglgraphics.cpp
@@ -19,30 +19,23 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "main.h"
-
-#ifdef USE_OPENGL
-
-#ifndef GL_TEXTURE_RECTANGLE_ARB
-#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
-#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
-#endif
+#include <SDL.h>
+#include "log.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..45cbb4c9 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -22,13 +22,14 @@
#include <algorithm>
#include <cmath>
-#include "particle.h"
+#include <guichan/color.hpp>
#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 +252,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 +314,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..e79a46dd 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -25,8 +25,6 @@
#include <list>
#include <string>
-#include <guichan/color.hpp>
-
#include "guichanfwd.h"
#include "sprite.h"
#include "vector.h"
@@ -102,7 +100,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..63f89079 100644
--- a/src/particlecontainer.cpp
+++ b/src/particlecontainer.cpp
@@ -21,6 +21,7 @@
#include <cassert>
+#include "particle.h"
#include "particlecontainer.h"
@@ -44,7 +45,6 @@ void ParticleContainer::clear()
mNext->clear();
}
-
void ParticleContainer::moveTo(float x, float y)
{
if (mNext)
@@ -109,9 +109,6 @@ void ParticleList::moveTo(float x, float y)
}
}
-
-
-
// -- particle vector ----------------------------------------
ParticleVector::ParticleVector(ParticleContainer *parent, bool delParent):
diff --git a/src/particlecontainer.h b/src/particlecontainer.h
index 27e02f8b..26539dd7 100644
--- a/src/particlecontainer.h
+++ b/src/particlecontainer.h
@@ -25,8 +25,7 @@
#include <list>
#include <vector>
-#include "particle.h"
-
+class Particle;
/**
* Set of particle effects. May be stacked with other ParticleContainers. All
@@ -65,8 +64,6 @@ protected:
ParticleContainer *mNext; /**< Contained container, if any */
};
-
-
/**
* Linked list of particle effects.
*/
@@ -94,7 +91,6 @@ protected:
std::list<Particle *> mElements; /**< Contained particle effects */
};
-
/**
* Particle container with indexing facilities
*/
diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp
index 076bd740..25e6ade5 100644
--- a/src/particleemitter.cpp
+++ b/src/particleemitter.cpp
@@ -19,31 +19,29 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "particleemitter.h"
+#include <cmath>
#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 <cmath>
+#include "resources/resourcemanager.h"
#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)
{
mMap = map;
mParticleTarget = target;
- //initializing default values
+ // Initializing default values
mParticlePosX.set(0.0f);
mParticlePosY.set(0.0f);
mParticlePosZ.set(0.0f);
@@ -93,7 +91,7 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
{
std::string image = XML::getProperty(propertyNode, "value", "");
// Don't leak when multiple images are defined
- if (image != "" && !mParticleImage)
+ if (!image.empty() && !mParticleImage)
{
ResourceManager *resman = ResourceManager::getInstance();
mParticleImage = resman->getImage(image);
@@ -102,7 +100,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 +310,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..67b35ae2 100644
--- a/src/particleemitter.h
+++ b/src/particleemitter.h
@@ -26,10 +26,10 @@
#include "utils/xml.h"
-#include "resources/animation.h"
-
#include "particleemitterprop.h"
+#include "resources/animation.h"
+
class Image;
class Map;
class Particle;
@@ -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..e68ac222 100644
--- a/src/particleemitterprop.h
+++ b/src/particleemitterprop.h
@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <cstdlib>
#include <cmath>
/**
diff --git a/src/party.cpp b/src/party.cpp
new file mode 100644
index 00000000..589aa9b1
--- /dev/null
+++ b/src/party.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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 "being.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.empty())
+ {
+ 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.empty())
+ {
+ 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)
+ {
+ 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(const std::string &msg)
+{
+ if (msg.empty())
+ {
+ 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..98252c37
--- /dev/null
+++ b/src/party.h
@@ -0,0 +1,76 @@
+/*
+ * 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(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..a2a263b3 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -19,20 +19,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "player.h"
-
#include "animatedsprite.h"
#include "game.h"
-#include "graphics.h"
-#include "log.h"
+#include "player.h"
+#include "text.h"
+#include "resources/colordb.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 +40,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 +66,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 +140,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);
}
@@ -155,11 +169,12 @@ void Player::setSprite(int slot, int id, std::string color)
std::string filename = ItemDB::get(id).getSprite(mGender);
AnimatedSprite *equipmentSprite = NULL;
- if (filename != "")
+ if (!filename.empty())
{
- if (color!="") filename += "|" + color;
+ if (!color.empty())
+ filename += "|" + color;
equipmentSprite = AnimatedSprite::load(
- "graphics/sprites/" + filename);
+ "graphics/sprites/" + filename);
}
if (equipmentSprite)
@@ -187,4 +202,3 @@ void Player::updateCoords()
}
}
-
diff --git a/src/player.h b/src/player.h
index 7fe2a09c..f9911bb8 100644
--- a/src/player.h
+++ b/src/player.h
@@ -23,8 +23,8 @@
#define PLAYER_H
#include "being.h"
-#include "text.h"
+class FlashText;
class Graphics;
class Map;
@@ -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..c82876e1 100644
--- a/src/player_relations.cpp
+++ b/src/player_relations.cpp
@@ -19,12 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <algorithm>
+
+#include "being.h"
#include "beingmanager.h"
-#include "player_relations.h"
+#include "configuration.h"
#include "graphics.h"
-#include "gui/gui.h"
-
-#include <algorithm>
+#include "player.h"
+#include "player_relations.h"
#define PLAYER_IGNORE_STRATEGY_NOP "nop"
#define PLAYER_IGNORE_STRATEGY_EMOTE0 "emote0"
@@ -56,7 +58,7 @@ class PlayerConfSerialiser : public ConfigurationListManager<std::pair<std::stri
std::map<std::string, PlayerRelation *> *container)
{
std::string name = cobj->getValue(NAME, "");
- if (name == "")
+ if (name.empty())
return container;
if (!(*container)[name]) {
@@ -90,8 +92,7 @@ PlayerRelationsManager::PlayerRelationsManager() :
{
}
-void
-PlayerRelationsManager::clear()
+void PlayerRelationsManager::clear()
{
std::vector<std::string> *names = getPlayers();
for (std::vector<std::string>::const_iterator
@@ -104,8 +105,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 +115,7 @@ PlayerRelationsManager::getPlayerIgnoreStrategyIndex(const std::string &name)
return -1;
}
-void
-PlayerRelationsManager::load()
+void PlayerRelationsManager::load()
{
clear();
@@ -133,8 +132,7 @@ PlayerRelationsManager::load()
}
-void
-PlayerRelationsManager::init()
+void PlayerRelationsManager::init()
{
load();
@@ -142,8 +140,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 +157,7 @@ PlayerRelationsManager::store()
config.write();
}
-void
-PlayerRelationsManager::signalUpdate(const std::string &name)
+void PlayerRelationsManager::signalUpdate(const std::string &name)
{
store();
@@ -169,8 +165,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 +190,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 +216,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 +227,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 +240,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 +251,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 +262,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 +289,7 @@ public:
mShortName = PLAYER_IGNORE_STRATEGY_NOP;
}
- virtual void
- ignore(Player *player, unsigned int flags)
+ virtual void ignore(Player *player, unsigned int flags)
{
}
};
@@ -317,10 +303,9 @@ public:
mShortName = "dotdotdot";
}
- virtual void
- ignore(Player *player, unsigned int flags)
+ virtual void ignore(Player *player, unsigned int flags)
{
- player->setSpeech("...", 5);
+ player->setSpeech("...", 500);
}
};
@@ -334,8 +319,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 +335,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..1eb4ede6 100644
--- a/src/player_relations.h
+++ b/src/player_relations.h
@@ -22,13 +22,13 @@
#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>
+
+class Being;
+class Player;
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/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..54c319de 100644
--- a/src/resources/animation.cpp
+++ b/src/resources/animation.cpp
@@ -21,8 +21,6 @@
#include "animation.h"
-#include <algorithm>
-
#include "../utils/dtor.h"
Animation::Animation():
@@ -30,22 +28,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..719ecab1 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()
{
@@ -55,9 +55,9 @@ void BuddyList::loadFile()
char *buddy = new char[LEN_MAX_USERNAME];
inputStream.getline(buddy, LEN_MAX_USERNAME);
// Ugly ?
- if(strcmp(buddy,"")) mBuddylist.push_back(buddy);
+ if (strcmp(buddy, "")) mBuddylist.push_back(buddy);
delete [] buddy;
- } while(!inputStream.eof());
+ } while (!inputStream.eof());
// Read buddy and close file
inputStream.close();
@@ -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..f0758c25 100644
--- a/src/resources/buddylist.h
+++ b/src/resources/buddylist.h
@@ -27,7 +27,8 @@
#include <guichan/listmodel.hpp>
-class BuddyList : public gcn::ListModel {
+class BuddyList : public gcn::ListModel
+{
public:
/**
* Constructor
@@ -52,7 +53,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..3a8754ea
--- /dev/null
+++ b/src/resources/colordb.cpp
@@ -0,0 +1,122 @@
+/*
+ * Color database
+ * Copyright (C) 2008 Aethyra 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 <libxml/tree.h>
+
+#include "colordb.h"
+
+#include "../log.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..c581f653
--- /dev/null
+++ b/src/resources/colordb.h
@@ -0,0 +1,52 @@
+/*
+ * Color database
+ * Copyright (C) 2008 Aethyra 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
+ */
+
+#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.cpp b/src/resources/dye.cpp
index 1b34a403..22bd2411 100644
--- a/src/resources/dye.cpp
+++ b/src/resources/dye.cpp
@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
#include <sstream>
#include "dye.h"
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..77c3c2fb
--- /dev/null
+++ b/src/resources/emotedb.cpp
@@ -0,0 +1,140 @@
+/*
+ * Emote database
+ * Copyright (C) 2008 Aethyra 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 "emotedb.h"
+
+#include "../log.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..2cf3af62
--- /dev/null
+++ b/src/resources/emotedb.h
@@ -0,0 +1,60 @@
+/*
+ * Emote database
+ * Copyright (C) 2008 Aethyra 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
+ */
+
+#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..7a7e6ac8 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"
@@ -168,7 +167,8 @@ Image *Image::load(SDL_Surface *tmpImage)
tmpImage = SDL_CreateRGBSurface(SDL_SWSURFACE, realWidth, realHeight,
32, rmask, gmask, bmask, amask);
- if (!tmpImage) {
+ if (!tmpImage)
+ {
logger->log("Error, image convert failed: out of memory");
return NULL;
}
@@ -179,9 +179,8 @@ Image *Image::load(SDL_Surface *tmpImage)
glGenTextures(1, &texture);
glBindTexture(mTextureType, texture);
- if (SDL_MUSTLOCK(tmpImage)) {
+ if (SDL_MUSTLOCK(tmpImage))
SDL_LockSurface(tmpImage);
- }
glTexImage2D(
mTextureType, 0, 4,
@@ -256,14 +255,13 @@ Image *Image::load(SDL_Surface *tmpImage)
SDL_Surface *image;
// Convert the surface to the current display format
- if (hasAlpha) {
+ if (hasAlpha)
image = SDL_DisplayFormatAlpha(tmpImage);
- }
- else {
+ else
image = SDL_DisplayFormat(tmpImage);
- }
- if (!image) {
+ if (!image)
+ {
logger->log("Error: Image convert failed.");
return NULL;
}
@@ -275,14 +273,16 @@ void Image::unload()
{
mLoaded = false;
- if (mImage) {
+ if (mImage)
+ {
// Free the image surface.
SDL_FreeSurface(mImage);
mImage = NULL;
}
#ifdef USE_OPENGL
- if (mGLImage) {
+ if (mGLImage)
+ {
glDeleteTextures(1, &mGLImage);
mGLImage = 0;
}
@@ -293,10 +293,9 @@ Image *Image::getSubImage(int x, int y, int width, int height)
{
// Create a new clipped sub-image
#ifdef USE_OPENGL
- if (mUseOpenGL) {
+ if (mUseOpenGL)
return new SubImage(this, mGLImage, x, y, width, height,
mTexWidth, mTexHeight);
- }
#endif
return new SubImage(this, mImage, x, y, width, height);
@@ -304,13 +303,13 @@ Image *Image::getSubImage(int x, int y, int width, int height)
void Image::setAlpha(float a)
{
- if (mAlpha == a) {
+ if (mAlpha == a)
return;
- }
mAlpha = a;
- if (mImage) {
+ if (mImage)
+ {
// Set the alpha value this image is drawn at
SDL_SetAlpha(mImage, SDL_SRCALPHA, (int) (255 * mAlpha));
}
@@ -322,14 +321,12 @@ float Image::getAlpha()
}
#ifdef USE_OPENGL
-void
-Image::setLoadAsOpenGL(bool useOpenGL)
+void Image::setLoadAsOpenGL(bool useOpenGL)
{
Image::mUseOpenGL = useOpenGL;
}
-int
-Image::powerOfTwo(int input)
+int Image::powerOfTwo(int input)
{
int value;
if (mTextureType == GL_TEXTURE_2D)
@@ -354,7 +351,8 @@ Image::powerOfTwo(int input)
SubImage::SubImage(Image *parent, SDL_Surface *image,
int x, int y, int width, int height):
- Image(image), mParent(parent)
+ Image(image),
+ mParent(parent)
{
mParent->incRef();
@@ -369,7 +367,8 @@ SubImage::SubImage(Image *parent, SDL_Surface *image,
SubImage::SubImage(Image *parent, GLuint image,
int x, int y, int width, int height,
int texWidth, int texHeight):
- Image(image, width, height, texWidth, texHeight), mParent(parent)
+ Image(image, width, height, texWidth, texHeight),
+ mParent(parent)
{
mParent->incRef();
@@ -395,3 +394,4 @@ Image *SubImage::getSubImage(int x, int y, int w, int h)
{
return mParent->getSubImage(mBounds.x + x, mBounds.y + y, w, h);
}
+
diff --git a/src/resources/image.h b/src/resources/image.h
index 963fbb24..fe3081ac 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
@@ -39,6 +40,8 @@
#include "resource.h"
class Dye;
+class SDL_Rect;
+class SDL_Surface;
/**
* Defines a class for loading and storing images.
@@ -96,7 +99,6 @@ class Image : public Resource
virtual int getWidth() const
{ return mBounds.w; }
-
/**
* Returns the height of the image.
*/
@@ -114,7 +116,7 @@ class Image : public Resource
/**
* Sets the alpha value of this image.
*/
- void setAlpha(float alpha);
+ virtual void setAlpha(float alpha);
/**
* Returns the alpha value of this image.
@@ -129,7 +131,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..40d62797 100644
--- a/src/resources/imageloader.cpp
+++ b/src/resources/imageloader.cpp
@@ -20,13 +20,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..039d3afb 100644
--- a/src/resources/imagewriter.h
+++ b/src/resources/imagewriter.h
@@ -19,13 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <iosfwd>
-
struct SDL_Surface;
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..6fa010d4 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -20,22 +20,22 @@
*/
#include <cassert>
+
#include <libxml/tree.h>
#include "itemdb.h"
-#include "iteminfo.h"
-#include "resourcemanager.h"
-
#include "../log.h"
#include "../utils/dtor.h"
#include "../utils/gettext.h"
+#include "../utils/trim.h"
#include "../utils/xml.h"
namespace
{
ItemDB::ItemInfos mItemInfos;
+ ItemDB::NamedItemInfos mNamedItemInfos;
ItemInfo *mUnknown;
bool mLoaded = false;
}
@@ -52,17 +52,17 @@ void ItemDB::load()
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)
@@ -82,7 +82,7 @@ void ItemDB::load()
logger->log("ItemDB: Redefinition of item ID %d", id);
}
- int type = XML::getProperty(node, "type", 0);
+ std::string type = XML::getProperty(node, "type", "other");
int weight = XML::getProperty(node, "weight", 0);
int view = XML::getProperty(node, "view", 0);
@@ -95,6 +95,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 +118,27 @@ void ItemDB::load()
}
mItemInfos[id] = itemInfo;
+ if (!name.empty())
+ {
+ NamedItemInfoIterator itr = mNamedItemInfos.find(name);
+ if (itr == mNamedItemInfos.end())
+ {
+ std::string temp = name;
+ trim(temp);
+
+ 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,7 +148,7 @@ 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(slot, 0);
@@ -166,6 +188,23 @@ const ItemInfo& ItemDB::get(int id)
}
}
+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
+ {
+ return *(i->second);
+ }
+}
+
void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node)
{
std::string gender = XML::getProperty(node, "gender", "unisex");
@@ -175,7 +214,6 @@ void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node)
{
itemInfo->setSprite(filename, GENDER_MALE);
}
-
if (gender == "female" || gender == "unisex")
{
itemInfo->setSprite(filename, GENDER_FEMALE);
diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h
index 03fb1eed..08a7acd0 100644
--- a/src/resources/itemdb.h
+++ b/src/resources/itemdb.h
@@ -22,9 +22,11 @@
#ifndef ITEM_MANAGER_H
#define ITEM_MANAGER_H
+#include <map>
+
#include "iteminfo.h"
-#include <map>
+class ItemInfo;
/**
* The namespace that holds the item information.
@@ -42,10 +44,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..c03dec28 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -47,13 +47,19 @@ class ItemInfo
* Constructor.
*/
ItemInfo():
- mType(0),
+ mType(""),
mWeight(0),
mView(0),
mAttackType(ACTION_DEFAULT)
{
}
+ void setId(int id)
+ { mId = id; }
+
+ int getId() const
+ { return mId; }
+
void setName(const std::string &name)
{ mName = name; }
@@ -75,14 +81,12 @@ class ItemInfo
void setEffect(const std::string &effect)
{ mEffect = effect; }
- const std::string&
- getEffect() const { return mEffect; }
+ const std::string& getEffect() const { return mEffect; }
- void setType(short type)
+ void setType(const std::string& type)
{ mType = type; }
- short getType() const
- { return mType; }
+ const std::string& getType() const { return mType; }
void setWeight(short weight)
{ mWeight = weight; }
@@ -112,9 +116,10 @@ class ItemInfo
std::string mName;
std::string mDescription; /**< Short description. */
std::string mEffect; /**< Description of effects. */
- char mType; /**< Item type. */
+ std::string 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..3270c665 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -19,14 +19,14 @@
* 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 "animation.h"
#include "image.h"
+#include "mapreader.h"
+#include "resourcemanager.h"
#include "../log.h"
#include "../map.h"
@@ -205,14 +205,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 +233,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 +323,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 +367,7 @@ void MapReader::readLayer(xmlNodePtr node, Map *map)
while (*charStart) {
if (*charStart != ' ' && *charStart != '\t' &&
- *charStart != '\n')
+ *charStart != '\n')
{
*charIndex = *charStart;
charIndex++;
@@ -461,15 +458,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 +547,7 @@ Tileset *MapReader::readTileset(xmlNodePtr node,
}
}
+ delete doc;
+
return set;
}
diff --git a/src/resources/mapreader.h b/src/resources/mapreader.h
index 8cb2749d..0ed553c3 100644
--- a/src/resources/mapreader.h
+++ b/src/resources/mapreader.h
@@ -22,12 +22,10 @@
#ifndef MAPREADER_H
#define MAPREADER_H
-#include <iosfwd>
-
#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..15451c95 100644
--- a/src/resources/monsterdb.cpp
+++ b/src/resources/monsterdb.cpp
@@ -20,12 +20,12 @@
*/
#include "monsterdb.h"
-
-#include "resourcemanager.h"
+#include "monsterinfo.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...");
- 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,8 @@ 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);
}
@@ -92,7 +92,8 @@ MonsterDB::load()
{
if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite"))
{
- currentInfo->addSprite((const char*) spriteNode->xmlChildrenNode->content);
+ currentInfo->addSprite(
+ (const char*) spriteNode->xmlChildrenNode->content);
}
if (xmlStrEqual(spriteNode->name, BAD_CAST "sound"))
@@ -119,11 +120,20 @@ MonsterDB::load()
}
else
{
- logger->log("MonsterDB: Warning, sound effect %s for unknown event %s of monster %s",
- filename, event.c_str(), currentInfo->getName().c_str());
+ 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(
diff --git a/src/resources/monsterdb.h b/src/resources/monsterdb.h
index 8555670b..0a218661 100644
--- a/src/resources/monsterdb.h
+++ b/src/resources/monsterdb.h
@@ -24,18 +24,16 @@
#include <map>
-#include "monsterinfo.h"
+class MonsterInfo;
/**
* Monster information database.
*/
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..359791fd 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..ee65136a 100644
--- a/src/resources/npcdb.cpp
+++ b/src/resources/npcdb.cpp
@@ -21,11 +21,9 @@
#include "npcdb.h"
-#include "resourcemanager.h"
-
#include "../log.h"
-#include "../utils/dtor.h"
+#include "../utils/gettext.h"
#include "../utils/xml.h"
namespace
@@ -52,10 +50,10 @@ void NPCDB::load()
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"))
@@ -91,8 +89,7 @@ void NPCDB::load()
mLoaded = true;
}
-void
-NPCDB::unload()
+void NPCDB::unload()
{
for ( NPCInfosIterator i = mNPCInfos.begin();
i != mNPCInfos.end();
@@ -117,8 +114,7 @@ NPCDB::unload()
mLoaded = false;
}
-const NPCInfo&
-NPCDB::get(int id)
+const NPCInfo& NPCDB::get(int id)
{
NPCInfosIterator i = mNPCInfos.find(id);
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..7c5f989e 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.
@@ -64,8 +62,7 @@ class Resource
/**
* Destructor.
*/
- virtual
- ~Resource();
+ virtual ~Resource();
private:
std::string mIdPath; /**< Path identifying this resource. */
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index febcf0d0..fa8f4654 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,13 +153,13 @@ 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());
- for (char **i = list; *i != NULL; i++)
+ for (char **i = list; *i; i++)
{
size_t len = strlen(*i);
@@ -209,7 +207,7 @@ std::string ResourceManager::getPath(const std::string &file)
else
{
// if not found in search path return the default path
- path = std::string(TMW_DATADIR) + std::string("data") + "/" + file;
+ path = std::string(PKG_DATADIR) + std::string("data") + "/" + file;
}
return path;
@@ -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..c3c68d88 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;
@@ -100,7 +100,7 @@ class ResourceManager
/**
* Returns the real path to a file. Note that this method will always
* return a path, it does not check whether the file exists.
- *
+ *
* @param file The file to get the real path to.
* @return The real path.
*/
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..116df930 100644
--- a/src/resources/soundeffect.h
+++ b/src/resources/soundeffect.h
@@ -35,8 +35,7 @@ class SoundEffect : public Resource
/**
* Destructor.
*/
- virtual
- ~SoundEffect();
+ virtual ~SoundEffect();
/**
* Loads a sample from a buffer in memory.
@@ -58,8 +57,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..20c79e73 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"
@@ -322,7 +321,7 @@ SpriteDef::~SpriteDef()
SpriteAction SpriteDef::makeSpriteAction(const std::string &action)
{
- if (action == "" || action == "default") {
+ if (action.empty() || action == "default") {
return ACTION_DEFAULT;
}
if (action == "stand") {
@@ -374,7 +373,7 @@ SpriteAction SpriteDef::makeSpriteAction(const std::string &action)
SpriteDirection SpriteDef::makeSpriteDirection(const std::string& direction)
{
- if (direction == "" || direction == "default") {
+ if (direction.empty() || direction == "default") {
return DIRECTION_DEFAULT;
}
else if (direction == "up") {
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..48f2f6a5 100644
--- a/src/simpleanimation.cpp
+++ b/src/simpleanimation.cpp
@@ -19,15 +19,21 @@
* 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/animation.h"
#include "resources/image.h"
-#include "resources/resourcemanager.h"
#include "resources/imageset.h"
+#include "resources/resourcemanager.h"
+SimpleAnimation::SimpleAnimation(Animation *animation):
+ mAnimation(animation),
+ mAnimationTime(0),
+ mAnimationPhase(0),
+ mCurrentFrame(mAnimation->getFrame(0))
+{
+}
SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode):
mAnimationTime(0),
@@ -43,7 +49,7 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode):
// Get animation frames
for ( xmlNodePtr frameNode = animationNode->xmlChildrenNode;
- frameNode != NULL;
+ frameNode;
frameNode = frameNode->next)
{
int delay = XML::getProperty(frameNode, "delay", 0);
diff --git a/src/simpleanimation.h b/src/simpleanimation.h
index a7178145..16ac2906 100644
--- a/src/simpleanimation.h
+++ b/src/simpleanimation.h
@@ -22,12 +22,12 @@
#ifndef SIMPLEANIMAION_H
#define SIMPLEANIMAION_H
-#include "resources/animation.h"
-
#include "utils/xml.h"
+class Animation;
class Frame;
class Graphics;
+class Image;
/**
* This class is a leightweight alternative to the AnimatedSprite class.
@@ -39,12 +39,7 @@ class SimpleAnimation
/**
* Creates a simple animation with an already created animation.
*/
- SimpleAnimation(Animation *animation):
- mAnimation(animation),
- mAnimationTime(0),
- mAnimationPhase(0),
- mCurrentFrame(mAnimation->getFrame(0))
- {};
+ SimpleAnimation(Animation *animation);
/**
* Creates a simple animation that creates its animation from XML Data.
diff --git a/src/sound.cpp b/src/sound.cpp
index c69dc023..6e0b0da0 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"
@@ -128,7 +128,7 @@ void Sound::playMusic(const std::string &filename, int loop)
{
if (!mInstalled) return;
- if (mMusic != NULL) {
+ if (mMusic) {
stopMusic();
}
@@ -154,7 +154,7 @@ void Sound::stopMusic()
logger->log("Sound::stopMusic()");
- if (mMusic != NULL) {
+ if (mMusic) {
Mix_HaltMusic();
Mix_FreeMusic(mMusic);
mMusic = NULL;
@@ -165,7 +165,7 @@ void Sound::fadeInMusic(const std::string &path, int loop, int ms)
{
if (!mInstalled) return;
- if (mMusic != NULL) {
+ if (mMusic) {
stopMusic();
}
@@ -188,7 +188,7 @@ void Sound::fadeOutMusic(int ms)
logger->log("Sound::fadeOutMusic() Fading-out (%i ms)", ms);
- if (mMusic != NULL) {
+ if (mMusic) {
Mix_FadeOutMusic(ms);
Mix_FreeMusic(mMusic);
mMusic = NULL;
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/statuseffect.cpp b/src/statuseffect.cpp
index 8872fd7b..7a50e794 100644
--- a/src/statuseffect.cpp
+++ b/src/statuseffect.cpp
@@ -39,19 +39,19 @@ StatusEffect::~StatusEffect()
void StatusEffect::playSFX()
{
- if (mSFXEffect != "")
+ if (!mSFXEffect.empty())
sound.playSfx(mSFXEffect);
}
void StatusEffect::deliverMessage()
{
- if (mMessage != "")
+ if (!mMessage.empty())
chatWindow->chatLog(mMessage, BY_SERVER);
}
Particle *StatusEffect::getParticle()
{
- if (mParticleEffect == "")
+ if (mParticleEffect.empty())
return NULL;
else
return particleEngine->addEffect(mParticleEffect, 0, 0);
@@ -59,7 +59,7 @@ Particle *StatusEffect::getParticle()
AnimatedSprite *StatusEffect::getIcon()
{
- if (mIcon == "")
+ if (mIcon.empty())
return NULL;
else {
AnimatedSprite *sprite = AnimatedSprite::load(
@@ -74,7 +74,7 @@ AnimatedSprite *StatusEffect::getIcon()
SpriteAction StatusEffect::getAction()
{
- if (mAction == "")
+ if (mAction.empty())
return ACTION_INVALID;
else
return SpriteDef::makeSpriteAction(mAction);
diff --git a/src/text.cpp b/src/text.cpp
index 0e458c9f..c4559879 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -1,5 +1,6 @@
/*
- * The Mana World
+ * Support for non-overlapping floating text
+ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net>
* Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
@@ -21,8 +22,6 @@
#include "text.h"
-#include <cstring>
-
#include <guichan/font.hpp>
#include "configuration.h"
@@ -38,9 +37,9 @@ Image *Text::mBubbleArrow;
Text::Text(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- gcn::Color colour, bool isSpeech) :
+ gcn::Color color, bool isSpeech) :
mText(text),
- mColour(colour),
+ mColor(color),
mIsSpeech(isSpeech)
{
if (textManager == 0)
@@ -48,7 +47,7 @@ Text::Text(const std::string &text, int x, int y,
textManager = new TextManager;
ResourceManager *resman = ResourceManager::getInstance();
Image *sbImage = resman->getImage("graphics/gui/bubble.png|W:#"
- + config.getValue("speechBubbleColour", "000000"));
+ + config.getValue("speechBubblecolor", "000000"));
mBubble.grid[0] = sbImage->getSubImage(0, 0, 5, 5);
mBubble.grid[1] = sbImage->getSubImage(5, 0, 5, 5);
mBubble.grid[2] = sbImage->getSubImage(10, 0, 5, 5);
@@ -68,8 +67,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)
{
@@ -113,9 +112,9 @@ void Text::adviseXY(int x, int y)
textManager->moveText(this, x - mXOffset, y);
}
-void Text::draw(Graphics *graphics, int xOff, int yOff)
+void Text::draw(gcn::Graphics *graphics, int xOff, int yOff)
{
- graphics->setFont(gui->getFont());
+ graphics->setFont(boldFont);
if (mIsSpeech) {
static_cast<Graphics*>(graphics)->drawImageRect(
@@ -162,20 +161,20 @@ void Text::draw(Graphics *graphics, int xOff, int yOff)
gcn::Graphics::LEFT);
}
- graphics->setColor(mColour);
+ graphics->setColor(mColor);
graphics->drawText(mText, mX - xOff, mY - yOff,
gcn::Graphics::LEFT);
}
FlashText::FlashText(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- gcn::Color colour) :
- Text(text, x, y, alignment, colour),
+ gcn::Color color) :
+ Text(text, x, y, alignment, color),
mTime(0)
{
}
-void FlashText::draw(Graphics *graphics, int xOff, int yOff)
+void FlashText::draw(gcn::Graphics *graphics, int xOff, int yOff)
{
if (mTime)
{
diff --git a/src/text.h b/src/text.h
index a7eae152..6e121da7 100644
--- a/src/text.h
+++ b/src/text.h
@@ -1,5 +1,6 @@
/*
- * The Mana World
+ * Support for non-overlapping floating text
+ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net>
* Copyright (C) 2008 The Mana World Development Team
*
* This file is part of The Mana World.
@@ -22,9 +23,10 @@
#ifndef TEXT_H
#define TEXT_H
-#include "graphics.h"
+#include <guichan/color.hpp>
-#include <list>
+#include "graphics.h"
+#include "guichanfwd.h"
class TextManager;
@@ -38,7 +40,7 @@ class Text
*/
Text(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- gcn::Color colour, bool isSpeech = false);
+ gcn::Color color, bool isSpeech = false);
/**
* Destructor. The text is removed from the screen.
@@ -53,7 +55,7 @@ class Text
/**
* Draws the text.
*/
- virtual void draw(Graphics *graphics, int xOff, int yOff);
+ virtual void draw(gcn::Graphics *graphics, int xOff, int yOff);
private:
int mX; /**< Actual x-value of left of text written. */
@@ -63,7 +65,7 @@ class Text
int mXOffset; /**< The offset of mX from the desired x. */
static int mInstances; /**< Instances of text. */
std::string mText; /**< The text to display. */
- gcn::Color mColour; /**< The colour of the text. */
+ gcn::Color mColor; /**< The color of the text. */
bool mIsSpeech; /**< Is this text a speech bubble? */
protected:
@@ -76,7 +78,12 @@ class FlashText : public Text
public:
FlashText(const std::string &text, int x, int y,
gcn::Graphics::Alignment alignment,
- gcn::Color colour);
+ gcn::Color color);
+
+ /**
+ * Remove the text from the screen
+ */
+ virtual ~FlashText() {}
/**
* Flash the text for so many refreshes.
@@ -86,10 +93,10 @@ class FlashText : public Text
/**
* Draws the text.
*/
- virtual void draw(Graphics *graphics, int xOff, int yOff);
+ virtual void draw(gcn::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..6bc8f8b6 100644
--- a/src/textmanager.cpp
+++ b/src/textmanager.cpp
@@ -1,6 +1,6 @@
/*
- * The Mana World
- * Copyright (C) 2008 The Mana World Development Team
+ * Support for non-overlapping floating text
+ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net>
*
* This file is part of The Mana World.
*
@@ -61,7 +61,7 @@ TextManager::~TextManager()
{
}
-void TextManager::draw(Graphics *graphics, int xOff, int yOff)
+void TextManager::draw(gcn::Graphics *graphics, int xOff, int yOff)
{
for (TextList::iterator bPtr = mTextList.begin(), ePtr = mTextList.end();
bPtr != ePtr; ++bPtr)
@@ -91,21 +91,13 @@ void TextManager::place(const Text *textObj, const Text *omit,
int from = (*ptr)->mY - occupiedTop;
int to = from + (*ptr)->mHeight - 1;
if (to < 0 || from >= TEST) // out of range considered
- {
continue;
- }
if (from < 0)
- {
from = 0;
- }
if (to >= TEST)
- {
to = TEST - 1;
- }
for (int i = from; i <= to; ++i)
- {
occupied[i] = true;
- }
}
}
bool ok = true;
@@ -113,10 +105,10 @@ void TextManager::place(const Text *textObj, const Text *omit,
{
ok = ok && !occupied[i];
}
+
if (ok)
- {
return;
- }
+
// Have to move it up or down, so find nearest spaces either side
int consec = 0;
int upSlot = -1; // means not found
diff --git a/src/textmanager.h b/src/textmanager.h
index fd0006c9..ee8e1209 100644
--- a/src/textmanager.h
+++ b/src/textmanager.h
@@ -1,6 +1,6 @@
/*
- * The Mana World
- * Copyright (C) 2008 The Mana World Development Team
+ * Support for non-overlapping floating text
+ * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net>
*
* This file is part of The Mana World.
*
@@ -24,8 +24,9 @@
#include <list>
+#include "guichanfwd.h"
+
class Text;
-class Graphics;
class TextManager
{
@@ -58,7 +59,7 @@ class TextManager
/**
* Draw the text
*/
- void draw(Graphics *graphics, int xOff, int yOff);
+ void draw(gcn::Graphics *graphics, int xOff, int yOff);
private:
/**
diff --git a/src/textparticle.cpp b/src/textparticle.cpp
index 0367f109..f38c32ce 100644
--- a/src/textparticle.cpp
+++ b/src/textparticle.cpp
@@ -19,9 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "textparticle.h"
+#include <guichan/color.hpp>
#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..cdf99d8f 100644
--- a/src/textparticle.h
+++ b/src/textparticle.h
@@ -22,11 +22,8 @@
#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/tostring.h b/src/utils/tostring.h
index 5ac1d3aa..62eb44e4 100644
--- a/src/utils/tostring.h
+++ b/src/utils/tostring.h
@@ -32,4 +32,19 @@ std::string toString(const T &arg)
return ss.str();
}
+// TODO: Is there a good way to suppress warnings from classes which don't use
+// this function?
+inline char *iptostring(int address)
+{
+ static char asciiIP[16];
+
+ sprintf(asciiIP, "%i.%i.%i.%i",
+ (unsigned char)(address),
+ (unsigned char)(address >> 8),
+ (unsigned char)(address >> 16),
+ (unsigned char)(address >> 24));
+
+ return asciiIP;
+}
+
#endif
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