summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt21
-rw-r--r--src/Makefile.am64
-rw-r--r--src/aethyra.rc (renamed from src/tmw.rc)43
-rw-r--r--src/animatedsprite.cpp1
-rw-r--r--src/animationparticle.cpp1
-rw-r--r--src/being.cpp405
-rw-r--r--src/being.h151
-rw-r--r--src/beingmanager.cpp14
-rw-r--r--src/beingmanager.h39
-rw-r--r--src/configlistener.h1
-rw-r--r--src/configuration.cpp4
-rw-r--r--src/configuration.h6
-rw-r--r--src/effectmanager.cpp85
-rw-r--r--src/effectmanager.h (renamed from src/gui/buddywindow.h)49
-rw-r--r--src/engine.cpp24
-rw-r--r--src/equipment.cpp5
-rw-r--r--src/extensions.h34
-rw-r--r--src/floor_item.cpp1
-rw-r--r--src/flooritemmanager.cpp7
-rw-r--r--src/game.cpp571
-rw-r--r--src/game.h48
-rw-r--r--src/gui/browserbox.cpp72
-rw-r--r--src/gui/browserbox.h29
-rw-r--r--src/gui/button.h2
-rw-r--r--src/gui/buttonbox.cpp44
-rw-r--r--src/gui/buttonbox.h (renamed from src/gui/newskill.h)61
-rw-r--r--src/gui/buy.cpp6
-rw-r--r--src/gui/buy.h6
-rw-r--r--src/gui/buysell.cpp3
-rw-r--r--src/gui/buysell.h2
-rw-r--r--src/gui/char_select.cpp17
-rw-r--r--src/gui/char_select.h6
-rw-r--r--src/gui/char_server.cpp4
-rw-r--r--src/gui/chargedialog.cpp1
-rw-r--r--src/gui/chargedialog.h2
-rw-r--r--src/gui/chat.cpp504
-rw-r--r--src/gui/chat.h284
-rw-r--r--src/gui/chatinput.h4
-rw-r--r--src/gui/checkbox.h2
-rw-r--r--src/gui/colour.cpp137
-rw-r--r--src/gui/colour.h133
-rw-r--r--src/gui/confirm_dialog.cpp57
-rw-r--r--src/gui/confirm_dialog.h11
-rw-r--r--src/gui/connection.cpp3
-rw-r--r--src/gui/debugwindow.cpp5
-rw-r--r--src/gui/equipmentwindow.cpp9
-rw-r--r--src/gui/equipmentwindow.h3
-rw-r--r--src/gui/focushandler.cpp1
-rw-r--r--src/gui/gccontainer.h2
-rw-r--r--src/gui/gui.cpp56
-rw-r--r--src/gui/gui.h10
-rw-r--r--src/gui/hbox.h2
-rw-r--r--src/gui/help.cpp3
-rw-r--r--src/gui/help.h2
-rw-r--r--src/gui/inttextbox.cpp4
-rw-r--r--src/gui/inttextbox.h2
-rw-r--r--src/gui/inventorywindow.cpp136
-rw-r--r--src/gui/inventorywindow.h23
-rw-r--r--src/gui/item_amount.cpp3
-rw-r--r--src/gui/itemcontainer.cpp26
-rw-r--r--src/gui/itemcontainer.h15
-rw-r--r--src/gui/itempopup.cpp113
-rw-r--r--src/gui/itempopup.h51
-rw-r--r--src/gui/itemshortcutcontainer.cpp4
-rw-r--r--src/gui/itemshortcutcontainer.h2
-rw-r--r--src/gui/itemshortcutwindow.cpp3
-rw-r--r--src/gui/itemshortcutwindow.h2
-rw-r--r--src/gui/listbox.cpp4
-rw-r--r--src/gui/listbox.h2
-rw-r--r--src/gui/login.cpp265
-rw-r--r--src/gui/login.h58
-rw-r--r--src/gui/menuwindow.cpp17
-rw-r--r--src/gui/minimap.cpp32
-rw-r--r--src/gui/minimap.h8
-rw-r--r--src/gui/ministatus.cpp10
-rw-r--r--src/gui/npc_text.cpp12
-rw-r--r--src/gui/npc_text.h5
-rw-r--r--src/gui/npclistdialog.cpp5
-rw-r--r--src/gui/npclistdialog.h2
-rw-r--r--src/gui/ok_dialog.cpp58
-rw-r--r--src/gui/ok_dialog.h12
-rw-r--r--src/gui/passwordfield.h2
-rw-r--r--src/gui/playerbox.cpp2
-rw-r--r--src/gui/playerbox.h2
-rw-r--r--src/gui/popupmenu.cpp214
-rw-r--r--src/gui/popupmenu.h3
-rw-r--r--src/gui/progressbar.h3
-rw-r--r--src/gui/radiobutton.h3
-rw-r--r--src/gui/register.cpp125
-rw-r--r--src/gui/register.h23
-rw-r--r--src/gui/scrollarea.h2
-rw-r--r--src/gui/sell.cpp7
-rw-r--r--src/gui/setup.cpp27
-rw-r--r--src/gui/setup.h2
-rw-r--r--src/gui/setup_audio.cpp3
-rw-r--r--src/gui/setup_audio.h4
-rw-r--r--src/gui/setup_colours.cpp207
-rw-r--r--src/gui/setup_colours.h76
-rw-r--r--src/gui/setup_joystick.cpp4
-rw-r--r--src/gui/setup_joystick.h4
-rw-r--r--src/gui/setup_keyboard.cpp5
-rw-r--r--src/gui/setup_keyboard.h8
-rw-r--r--src/gui/setup_players.cpp8
-rw-r--r--src/gui/setup_players.h7
-rw-r--r--src/gui/setup_video.cpp67
-rw-r--r--src/gui/setup_video.h8
-rw-r--r--src/gui/shop.cpp4
-rw-r--r--src/gui/shop.h5
-rw-r--r--src/gui/shoplistbox.cpp8
-rw-r--r--src/gui/shoplistbox.h2
-rw-r--r--src/gui/skill.cpp10
-rw-r--r--src/gui/skill.h5
-rw-r--r--src/gui/slider.h3
-rw-r--r--src/gui/speechbubble.cpp93
-rw-r--r--src/gui/speechbubble.h45
-rw-r--r--src/gui/status.cpp4
-rw-r--r--src/gui/tabbedcontainer.cpp30
-rw-r--r--src/gui/tabbedcontainer.h13
-rw-r--r--src/gui/table.cpp7
-rw-r--r--src/gui/table.h1
-rw-r--r--src/gui/table_model.cpp4
-rw-r--r--src/gui/table_model.h4
-rw-r--r--src/gui/textbox.cpp41
-rw-r--r--src/gui/textbox.h15
-rw-r--r--src/gui/textfield.cpp70
-rw-r--r--src/gui/textfield.h49
-rw-r--r--src/gui/trade.cpp12
-rw-r--r--src/gui/updatewindow.cpp9
-rw-r--r--src/gui/updatewindow.h1
-rw-r--r--src/gui/vbox.h2
-rw-r--r--src/gui/viewport.cpp215
-rw-r--r--src/gui/viewport.h44
-rw-r--r--src/gui/widgets/dropdown.cpp167
-rw-r--r--src/gui/widgets/dropdown.h86
-rw-r--r--src/gui/widgets/resizegrip.cpp8
-rw-r--r--src/gui/widgets/resizegrip.h4
-rw-r--r--src/gui/window.cpp241
-rw-r--r--src/gui/window.h20
-rw-r--r--src/gui/windowcontainer.cpp4
-rw-r--r--src/gui/windowcontainer.h2
-rw-r--r--src/imageparticle.cpp3
-rw-r--r--src/inventory.cpp38
-rw-r--r--src/inventory.h8
-rw-r--r--src/itemshortcut.cpp3
-rw-r--r--src/joystick.cpp3
-rw-r--r--src/joystick.h4
-rw-r--r--src/keyboardconfig.cpp10
-rw-r--r--src/keyboardconfig.h6
-rw-r--r--src/localplayer.cpp200
-rw-r--r--src/localplayer.h44
-rw-r--r--src/main.cpp268
-rw-r--r--src/main.h4
-rw-r--r--src/map.cpp43
-rw-r--r--src/monster.cpp86
-rw-r--r--src/monster.h2
-rw-r--r--src/net/beinghandler.cpp104
-rw-r--r--src/net/beinghandler.h2
-rw-r--r--src/net/buysellhandler.cpp5
-rw-r--r--src/net/charserverhandler.cpp19
-rw-r--r--src/net/chathandler.cpp3
-rw-r--r--src/net/equipmenthandler.cpp44
-rw-r--r--src/net/inventoryhandler.cpp126
-rw-r--r--src/net/itemhandler.cpp1
-rw-r--r--src/net/loginhandler.cpp5
-rw-r--r--src/net/loginhandler.h2
-rw-r--r--src/net/maploginhandler.cpp1
-rw-r--r--src/net/messagehandler.cpp3
-rw-r--r--src/net/messagein.cpp5
-rw-r--r--src/net/messagein.h2
-rw-r--r--src/net/messageout.cpp5
-rw-r--r--src/net/network.cpp5
-rw-r--r--src/net/npchandler.cpp11
-rw-r--r--src/net/partyhandler.cpp124
-rw-r--r--src/net/partyhandler.h39
-rw-r--r--src/net/playerhandler.cpp79
-rw-r--r--src/net/protocol.h43
-rw-r--r--src/net/skillhandler.cpp3
-rw-r--r--src/net/tradehandler.cpp13
-rw-r--r--src/npc.cpp51
-rw-r--r--src/npc.h6
-rw-r--r--src/openglgraphics.cpp38
-rw-r--r--src/openglgraphics.h8
-rw-r--r--src/particle.cpp13
-rw-r--r--src/particle.h4
-rw-r--r--src/particleemitter.cpp35
-rw-r--r--src/particleemitter.h2
-rw-r--r--src/particleemitterprop.h2
-rw-r--r--src/party.cpp216
-rw-r--r--src/party.h73
-rw-r--r--src/player.cpp40
-rw-r--r--src/player.h1
-rw-r--r--src/player_relations.cpp7
-rw-r--r--src/player_relations.h11
-rw-r--r--src/properties.h2
-rw-r--r--src/recorder.cpp110
-rw-r--r--src/recorder.h48
-rw-r--r--src/resources/action.cpp7
-rw-r--r--src/resources/ambientoverlay.cpp1
-rw-r--r--src/resources/animation.cpp4
-rw-r--r--src/resources/buddylist.cpp4
-rw-r--r--src/resources/colordb.cpp126
-rw-r--r--src/resources/colordb.h52
-rw-r--r--src/resources/dye.h5
-rw-r--r--src/resources/image.cpp3
-rw-r--r--src/resources/image.h3
-rw-r--r--src/resources/imageloader.cpp4
-rw-r--r--src/resources/imageset.cpp10
-rw-r--r--src/resources/imageset.h1
-rw-r--r--src/resources/imagewriter.cpp6
-rw-r--r--src/resources/itemdb.cpp12
-rw-r--r--src/resources/itemdb.h4
-rw-r--r--src/resources/iteminfo.cpp3
-rw-r--r--src/resources/mapreader.cpp65
-rw-r--r--src/resources/mapreader.h2
-rw-r--r--src/resources/monsterdb.cpp12
-rw-r--r--src/resources/monsterinfo.cpp5
-rw-r--r--src/resources/monsterinfo.h11
-rw-r--r--src/resources/npcdb.cpp1
-rw-r--r--src/resources/npcdb.h2
-rw-r--r--src/resources/resource.cpp1
-rw-r--r--src/resources/resourcemanager.cpp16
-rw-r--r--src/resources/resourcemanager.h4
-rw-r--r--src/resources/spritedef.cpp3
-rw-r--r--src/resources/spritedef.h4
-rw-r--r--src/simpleanimation.cpp6
-rw-r--r--src/sound.cpp4
-rw-r--r--src/sound.h1
-rw-r--r--src/text.cpp43
-rw-r--r--src/text.h59
-rw-r--r--src/textmanager.cpp43
-rw-r--r--src/textmanager.h47
-rw-r--r--src/textparticle.cpp3
-rw-r--r--src/textparticle.h3
-rw-r--r--src/utils/base64.cpp2
-rw-r--r--src/utils/dtor.h8
-rw-r--r--src/utils/strprintf.cpp1
-rw-r--r--src/utils/xml.cpp2
-rw-r--r--src/utils/xml.h4
-rw-r--r--src/vector.cpp28
-rw-r--r--src/vector.h68
-rw-r--r--src/winver.h12
241 files changed, 6155 insertions, 2558 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 94ee854a..b54c7c6c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -8,7 +8,7 @@ FIND_PACKAGE(PhysFS REQUIRED)
FIND_PACKAGE(PNG REQUIRED)
SET(FLAGS "-DPACKAGE_VERSION=\\\"${VERSION}\\\"")
-SET(FLAGS "${FLAGS} -DTMW_DATADIR=\\\"${PKG_DATADIR}/\\\"")
+SET(FLAGS "${FLAGS} -DAETHYRA_DATADIR=\\\"${PKG_DATADIR}/\\\"")
SET(GUICHAN_COMPONENTS "SDL")
IF (WITH_OPENGL)
@@ -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/box.cpp
@@ -116,8 +118,6 @@ SET(SRCS
gui/minimap.h
gui/ministatus.cpp
gui/ministatus.h
- gui/newskill.cpp
- gui/newskill.h
gui/npclistdialog.cpp
gui/npclistdialog.h
gui/npc_text.cpp
@@ -161,6 +161,8 @@ SET(SRCS
gui/skill.h
gui/slider.cpp
gui/slider.h
+ gui/speechbubble.cpp
+ gui/speechbubble.h
gui/status.cpp
gui/status.h
gui/tabbedcontainer.cpp
@@ -229,6 +231,8 @@ SET(SRCS
resources/animation.h
resources/buddylist.cpp
resources/buddylist.h
+ resources/colordb.cpp
+ resources/colordb.h
resources/dye.cpp
resources/dye.h
resources/image.cpp
@@ -286,6 +290,7 @@ SET(SRCS
engine.h
equipment.cpp
equipment.h
+ extensions.h
floor_item.cpp
floor_item.h
flooritemmanager.cpp
@@ -345,11 +350,13 @@ SET(SRCS
textparticle.h
tileset.h
vector.h
+ effectmanager.cpp
+ effectmanager.h
)
-ADD_EXECUTABLE(tmw ${SRCS})
+ADD_EXECUTABLE(aethyra ${SRCS})
-TARGET_LINK_LIBRARIES(tmw
+TARGET_LINK_LIBRARIES(aethyra
${SDL_LIBRARY}
${SDLIMAGE_LIBRARY}
${SDLMIXER_LIBRARY}
@@ -362,6 +369,6 @@ TARGET_LINK_LIBRARIES(tmw
${OPENGL_LIBRARIES}
)
-INSTALL(TARGETS tmw RUNTIME DESTINATION ${PKG_BINDIR})
+INSTALL(TARGETS aethyra RUNTIME DESTINATION ${PKG_BINDIR})
-SET_TARGET_PROPERTIES(tmw PROPERTIES COMPILE_FLAGS "${FLAGS}")
+SET_TARGET_PROPERTIES(aethyra PROPERTIES COMPILE_FLAGS "${FLAGS}")
diff --git a/src/Makefile.am b/src/Makefile.am
index e9d69b5e..507db6f8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,30 +1,34 @@
-bin_PROGRAMS = tmw
-tmw_SOURCES = gui/widgets/resizegrip.cpp \
+bin_PROGRAMS = aethyra
+aethyra_SOURCES = gui/widgets/dropdown.cpp \
+ gui/widgets/dropdown.h \
+ gui/widgets/resizegrip.cpp \
gui/widgets/resizegrip.h \
- gui/box.h \
gui/box.cpp \
+ gui/box.h \
gui/browserbox.cpp \
gui/browserbox.h \
- gui/buddywindow.cpp \
- gui/buddywindow.h \
gui/button.cpp \
gui/button.h \
+ gui/buttonbox.cpp \
+ gui/buttonbox.h \
gui/buy.cpp \
gui/buy.h \
gui/buysell.cpp \
gui/buysell.h \
gui/chargedialog.cpp \
gui/chargedialog.h \
- gui/char_server.cpp \
- gui/char_server.h \
gui/char_select.cpp \
gui/char_select.h \
+ gui/char_server.cpp \
+ gui/char_server.h \
gui/chat.cpp \
gui/chat.h \
gui/chatinput.cpp \
gui/chatinput.h \
gui/checkbox.cpp \
gui/checkbox.h \
+ gui/colour.cpp \
+ gui/colour.h \
gui/confirm_dialog.cpp \
gui/confirm_dialog.h \
gui/connection.cpp \
@@ -39,8 +43,8 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \
gui/gccontainer.h \
gui/gui.cpp \
gui/gui.h \
- gui/hbox.h \
gui/hbox.cpp \
+ gui/hbox.h \
gui/help.cpp \
gui/help.h \
gui/inttextbox.h \
@@ -66,8 +70,6 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \
gui/minimap.h \
gui/ministatus.cpp \
gui/ministatus.h \
- gui/newskill.cpp \
- gui/newskill.h \
gui/npclistdialog.cpp \
gui/npclistdialog.h \
gui/npc_text.cpp \
@@ -90,10 +92,12 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \
gui/scrollarea.h \
gui/sell.cpp \
gui/sell.h \
- gui/setup_audio.cpp \
- gui/setup_audio.h \
gui/setup.cpp \
gui/setup.h \
+ gui/setup_audio.cpp \
+ gui/setup_audio.h \
+ gui/setup_colours.cpp \
+ gui/setup_colours.h \
gui/setup_joystick.cpp \
gui/setup_joystick.h \
gui/setup_keyboard.cpp \
@@ -111,14 +115,16 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \
gui/skill.h \
gui/slider.cpp \
gui/slider.h \
+ gui/speechbubble.cpp \
+ gui/speechbubble.h \
gui/status.cpp \
gui/status.h \
gui/tabbedcontainer.cpp \
gui/tabbedcontainer.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 \
@@ -163,6 +169,8 @@ tmw_SOURCES = gui/widgets/resizegrip.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 \
@@ -177,6 +185,10 @@ tmw_SOURCES = gui/widgets/resizegrip.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/image.cpp \
@@ -209,8 +221,6 @@ tmw_SOURCES = gui/widgets/resizegrip.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 \
@@ -233,10 +243,13 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \
configlistener.h \
configuration.cpp \
configuration.h \
+ effectmanager.cpp \
+ effectmanager.h \
engine.cpp \
engine.h \
equipment.cpp \
equipment.h \
+ extensions.h \
floor_item.cpp \
floor_item.h \
flooritemmanager.cpp \
@@ -276,16 +289,20 @@ tmw_SOURCES = gui/widgets/resizegrip.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 \
player_relations.h \
properties.h \
+ recorder.cpp \
+ recorder.h \
serverinfo.h \
shopitem.cpp \
shopitem.h \
@@ -301,15 +318,16 @@ tmw_SOURCES = gui/widgets/resizegrip.cpp \
textparticle.cpp \
textparticle.h \
tileset.h \
+ vector.cpp \
vector.h
# set the include path found by configure
INCLUDES = \
$(all_includes) \
- -DTMW_DATADIR=\""$(pkgdatadir)/"\"
+ -DAETHYRA_DATADIR=\""$(pkgdatadir)/"\"
# the library search path.
-tmw_LDFLAGS = $(all_libraries) $(LIBSDL_RPATH) `pkg-config --libs libxml-2.0`
-tmw_CXXFLAGS = -Wall $(LIBSDL_CFLAGS) `pkg-config --cflags libxml-2.0` $(CURL_CFLAGS)
-tmw_LDADD = $(LIBSDL_LIBS) -lguichan_sdl $(CURL_LIBS)
-tmw_TARGET = tmw
+aethyra_LDFLAGS = $(all_libraries) $(LIBSDL_RPATH) `pkg-config --libs libxml-2.0`
+aethyra_CXXFLAGS = -Wall $(LIBSDL_CFLAGS) `pkg-config --cflags libxml-2.0` $(CURL_CFLAGS)
+aethyra_LDADD = $(LIBSDL_LIBS) -lguichan_sdl $(CURL_LIBS)
+aethyra_TARGET = aethyra
diff --git a/src/tmw.rc b/src/aethyra.rc
index 9661ac6b..d2db954f 100644
--- a/src/tmw.rc
+++ b/src/aethyra.rc
@@ -1,23 +1,22 @@
-#include <windows.h> // include for version info constants
-
-#include "winver.h"
-
-A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "data/icons/tmw.ico"
-
-1 VERSIONINFO
-FILEVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD
-PRODUCTVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD
-FILETYPE VFT_APP {
- BLOCK "StringFileInfo" {
- BLOCK "040904E4" {
- VALUE "CompanyName", "The Mana World Development Team"
- VALUE "FileVersion", PACKAGE_VERSION
- VALUE "FileDescription", "The Mana World"
- VALUE "LegalCopyright", "2004-2006 (C)"
- VALUE "OriginalFilename", "tmw.exe"
- VALUE "ProductName", "The Mana World MMORPG"
- VALUE "ProductVersion", PACKAGE_VERSION
- }
- }
+#include <windows.h> // include for version info constants
+
+#include "winver.h"
+
+A ICON MOVEABLE PURE LOADONCALL DISCARDABLE "data/icons/aethyra.ico"
+
+1 VERSIONINFO
+FILEVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD
+PRODUCTVERSION VER_MAJOR,VER_MINOR,VER_RELEASE,VER_BUILD
+FILETYPE VFT_APP {
+ BLOCK "StringFileInfo" {
+ BLOCK "040904E4" {
+ VALUE "CompanyName", "Aethyra Development Team"
+ VALUE "FileVersion", PACKAGE_VERSION
+ VALUE "FileDescription", "Aethyra Experiment"
+ VALUE "LegalCopyright", "2008 (C)"
+ VALUE "OriginalFilename", "aethyra.exe"
+ VALUE "ProductName", "Aethyra MMORPG"
+ VALUE "ProductVersion", PACKAGE_VERSION
+ }
+ }
}
-
diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp
index 203a82af..ba71d0e0 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 eb260157..59eacb05 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 7c6d91e7..d98af29c 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -18,31 +18,36 @@
* 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 <algorithm>
#include <cassert>
+#include <cmath>
#include "animatedsprite.h"
+#include "being.h"
+#include "configuration.h"
#include "equipment.h"
#include "game.h"
#include "graphics.h"
+#include "localplayer.h"
#include "log.h"
#include "map.h"
#include "particle.h"
#include "sound.h"
-#include "localplayer.h"
#include "text.h"
-#include "resources/itemdb.h"
-#include "resources/resourcemanager.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/tostring.h"
+#include "utils/xml.h"
+
+#define BEING_EFFECTS_FILE "effects.xml"
#include "utils/xml.h"
@@ -50,6 +55,7 @@
#define HAIR_FILE "hair.xml"
int Being::instances = 0;
+int Being::mNumberOfHairstyles = 1;
ImageSet *Being::emotionSet = NULL;
static const int X_SPEECH_OFFSET = 18;
@@ -58,7 +64,7 @@ static const int Y_SPEECH_OFFSET = 60;
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),
@@ -67,6 +73,8 @@ Being::Being(int id, int job, Map *map):
mWalkSpeed(150),
mDirection(DOWN),
mMap(NULL),
+ mIsGM(false),
+ mParticleEffects(config.getValue("particleeffects", 1)),
mEquippedWeapon(NULL),
mHairStyle(1), mHairColor(0),
mGender(2),
@@ -80,21 +88,32 @@ 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!");
+
+ // Hairstyles are encoded as negative numbers. Count how far negative we can go.
+ int hairstyles = 1;
+ while (ItemDB::get(-hairstyles).getSprite(0) != "error.xml")
+ {
+ hairstyles++;
+ }
+ mNumberOfHairstyles = hairstyles;
}
instances++;
- mSpeech = 0;
+ mSpeech = "";
+ mText = 0;
}
Being::~Being()
{
- std::for_each(mSprites.begin(), mSprites.end(), make_dtor(mSprites));
+ delete_all(mSprites);
clearPath();
setMap(NULL);
@@ -107,11 +126,11 @@ Being::~Being()
emotionSet = NULL;
}
- delete mSpeech;
+ delete mSpeechBubble;
+ delete mText;
}
-void
-Being::setDestination(Uint16 destX, Uint16 destY)
+void Being::setDestination(Uint16 destX, Uint16 destY)
{
if (mMap)
{
@@ -119,14 +138,12 @@ Being::setDestination(Uint16 destX, Uint16 destY)
}
}
-void
-Being::clearPath()
+void Being::clearPath()
{
mPath.clear();
}
-void
-Being::setPath(const Path &path)
+void Being::setPath(const Path &path)
{
mPath = path;
@@ -137,35 +154,27 @@ Being::setPath(const Path &path)
}
}
-void
-Being::setHairStyle(int style, int color)
+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)
+void Being::setSprite(int slot, int id, std::string color)
{
assert(slot >= BASE_SPRITE && slot < VECTOREND_SPRITE);
mSpriteIDs[slot] = id;
mSpriteColors[slot] = color;
}
-void
-Being::setSpeech(const std::string &text, Uint32 time)
+void Being::setSpeech(const std::string &text, Uint32 time)
{
- // don't introduce a memory leak
- delete mSpeech;
+ mSpeech = text;
- mSpeech = new Text(text, mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET,
- gcn::Graphics::CENTER, speechFont,
- gcn::Color(255, 255, 255));
mSpeechTime = 500;
}
-void
-Being::takeDamage(int amount)
+void Being::takeDamage(int amount)
{
gcn::Font *font;
std::string damage = amount ? toString(amount) : "miss";
@@ -177,10 +186,6 @@ Being::takeDamage(int amount)
}
else
{
- // Hit particle effect
- controlParticle(particleEngine->addEffect(
- "graphics/particles/hit.particle.xml", 0, 0));
-
if (getType() == MONSTER)
{
font = hitBlueFont;
@@ -196,16 +201,34 @@ Being::takeDamage(int amount)
mPx + 16, mPy + 16);
}
-void
-Being::handleAttack(Being *victim, int damage)
+void Being::showCrit()
+{
+ gcn::Font *font;
+ std::string text = "crit!";
+
+ // Selecting the right color
+ if (getType() == MONSTER)
+ {
+ font = hitBlueFont;
+ }
+ else
+ {
+ font = hitRedFont;
+ }
+
+ // Show crit notice
+ particleEngine->addTextSplashEffect(text, 255, 255, 255, font,
+ mPx + 16, mPy + 16);
+}
+
+void Being::handleAttack(Being *victim, int damage)
{
setAction(Being::ATTACK);
mFrame = 0;
mWalkTime = tick_time;
}
-void
-Being::setMap(Map *map)
+void Being::setMap(Map *map)
{
// Remove sprite from potential previous map
if (mMap)
@@ -225,16 +248,15 @@ Being::setMap(Map *map)
mChildParticleEffects.clear();
}
-void
-Being::controlParticle(Particle *particle)
+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:
@@ -248,7 +270,8 @@ Being::setAction(Uint8 action)
{
currentAction = mEquippedWeapon->getAttackType();
}
- else {
+ else
+ {
currentAction = ACTION_ATTACK;
}
for (int i = 0; i < VECTOREND_SPRITE; i++)
@@ -285,10 +308,11 @@ Being::setAction(Uint8 action)
}
}
-
-void
-Being::setDirection(Uint8 direction)
+void Being::setDirection(Uint8 direction)
{
+ if (mDirection == direction)
+ return;
+
mDirection = direction;
SpriteDirection dir = getSpriteDirection();
@@ -299,8 +323,7 @@ Being::setDirection(Uint8 direction)
}
}
-SpriteDirection
-Being::getSpriteDirection() const
+SpriteDirection Being::getSpriteDirection() const
{
SpriteDirection dir;
@@ -316,15 +339,15 @@ Being::getSpriteDirection() const
{
dir = DIRECTION_RIGHT;
}
- else {
- dir = DIRECTION_LEFT;
+ else
+ {
+ dir = DIRECTION_LEFT;
}
-
+
return dir;
}
-void
-Being::nextStep()
+void Being::nextStep()
{
if (mPath.empty())
{
@@ -359,32 +382,31 @@ Being::nextStep()
mWalkTime += mWalkSpeed / 10;
}
-void
-Being::logic()
+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--;
@@ -406,8 +428,7 @@ Being::logic()
mChildParticleEffects.setPositions((float)mPx + 16.0f, (float)mPy + 32.0f);
}
-void
-Being::draw(Graphics *graphics, int offsetX, int offsetY) const
+void Being::draw(Graphics *graphics, int offsetX, int offsetY) const
{
int px = mPx + offsetX;
int py = mPy + offsetY;
@@ -421,8 +442,7 @@ Being::draw(Graphics *graphics, int offsetX, int offsetY) const
}
}
-void
-Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
+void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
{
if (!mEmotion)
return;
@@ -435,17 +455,56 @@ Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY)
graphics->drawImage(emotionSet->get(emotionIndex), px, py);
}
-Being::Type
-Being::getType() const
+void Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY)
+{
+ int px = mPx + offsetX;
+ int py = mPy + offsetY;
+
+ // Draw speech above this being
+ if (mSpeechTime > 0 && config.getValue("speechbubble", 1))
+ {
+ if (mText)
+ {
+ delete mText;
+ mText = 0;
+ }
+
+ mSpeechBubble->setCaption(mName);
+ mSpeechBubble->setWindowName(mName);
+ // 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, speechFont,
+ gcn::Color(255, 255, 255));
+ }
+ else if (mSpeechTime == 0)
+ {
+ mSpeechBubble->setVisible(false);
+ }
+}
+
+Being::Type Being::getType() const
{
return UNKNOWN;
}
-int
-Being::getOffset(char pos, char neg) const
+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;
}
@@ -453,220 +512,42 @@ 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
+int Being::getWidth() const
{
if (mSprites[BASE_SPRITE])
{
return mSprites[BASE_SPRITE]->getWidth();
}
- else {
+ else
+ {
return 0;
}
}
-int
-Being::getHeight() const
+int Being::getHeight() const
{
if (mSprites[BASE_SPRITE])
{
return mSprites[BASE_SPRITE]->getHeight();
}
- else {
- return 0;
- }
-}
-
-
-struct EffectDescription {
- std::string mGFXEffect;
- std::string mSFXEffect;
-};
-
-static EffectDescription *default_effect = NULL;
-static std::map<int, EffectDescription *> effects;
-static bool effects_initialized = false;
-
-static EffectDescription *
-getEffectDescription(xmlNodePtr node, int *id)
-{
- EffectDescription *ed = new EffectDescription;
-
- *id = atoi(XML::getProperty(node, "id", "-1").c_str());
- ed->mSFXEffect = XML::getProperty(node, "audio", "");
- ed->mGFXEffect = XML::getProperty(node, "particle", "");
-
- return ed;
-}
-
-static EffectDescription *
-getEffectDescription(int effectId)
-{
- if (!effects_initialized)
+ else
{
- XML::Document doc(BEING_EFFECTS_FILE);
- xmlNodePtr root = doc.rootNode();
-
- if (!root || !xmlStrEqual(root->name, BAD_CAST "being-effects"))
- {
- logger->log("Error loading being effects file: "
- BEING_EFFECTS_FILE);
- return NULL;
- }
-
- for_each_xml_child_node(node, root)
- {
- int id;
-
- if (xmlStrEqual(node->name, BAD_CAST "effect"))
- {
- EffectDescription *EffectDescription =
- getEffectDescription(node, &id);
- effects[id] = EffectDescription;
- } else if (xmlStrEqual(node->name, BAD_CAST "default"))
- {
- EffectDescription *EffectDescription =
- getEffectDescription(node, &id);
-
- if (default_effect)
- delete default_effect;
-
- default_effect = EffectDescription;
- }
- }
-
- effects_initialized = true;
- } // done initializing
-
- EffectDescription *ed = effects[effectId];
-
- if (!ed)
- return default_effect;
- else
- return ed;
-}
-
-void
-Being::internalTriggerEffect(int effectId, bool sfx, bool gfx)
-{
- logger->log("Special effect #%d on %s", effectId,
- getId() == player_node->getId() ? "self" : "other");
-
- EffectDescription *ed = getEffectDescription(effectId);
-
- if (!ed) {
- logger->log("Unknown special effect and no default recorded");
- return;
- }
-
- if (gfx && ed->mGFXEffect != "") {
- Particle *selfFX;
-
- selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0);
- controlParticle(selfFX);
- }
-
- if (sfx && ed->mSFXEffect != "") {
- sound.playSfx(ed->mSFXEffect);
+ return 0;
}
}
-
-
-
-static int hairStylesNr;
-static int hairColorsNr;
-static std::vector<std::string> hairColors;
-
-static void
-initializeHair(void);
-
-int
-Being::getHairStylesNr(void)
-{
- initializeHair();
- return hairStylesNr;
-}
-
-int
-Being::getHairColorsNr(void)
-{
- initializeHair();
- return hairColorsNr;
-}
-
-std::string
-Being::getHairColor(int index)
-{
- initializeHair();
- if (index < 0 || index >= hairColorsNr)
- return "#000000";
-
- return hairColors[index];
-}
-
-static bool hairInitialized = false;
-
-static void
-initializeHair(void)
-{
- if (hairInitialized)
- return;
-
- // Hairstyles are encoded as negative numbers. Count how far negative we can go.
- int hairstylesCtr = -1;
- while (ItemDB::get(hairstylesCtr).getSprite(0) != "error.xml")
- --hairstylesCtr;
-
- hairStylesNr = -hairstylesCtr; // done.
- if (hairStylesNr == 0)
- hairStylesNr = 1; // No hair style -> no hair
-
- hairColorsNr = 0;
-
- XML::Document doc(HAIR_FILE);
- xmlNodePtr root = doc.rootNode();
-
- if (!root || !xmlStrEqual(root->name, BAD_CAST "colors"))
- {
- logger->log("Error loading being hair configuration file");
- } else {
- for_each_xml_child_node(node, root)
- {
- if (xmlStrEqual(node->name, BAD_CAST "color"))
- {
- int index = atoi(XML::getProperty(node, "id", "-1").c_str());
- std::string value = XML::getProperty(node, "value", "");
-
- if (index >= 0 && value != "") {
- if (index >= hairColorsNr) {
- hairColorsNr = index + 1;
- hairColors.resize(hairColorsNr, "#000000");
- }
- hairColors[index] = value;
- }
- }
- }
- } // done initializing
-
- if (hairColorsNr == 0) { // No colours -> black only
- hairColorsNr = 1;
- hairColors.resize(hairColorsNr, "#000000");
- }
-
- hairInitialized = 1;
-}
diff --git a/src/being.h b/src/being.h
index 15e1e6f9..7202701a 100644
--- a/src/being.h
+++ b/src/being.h
@@ -24,14 +24,20 @@
#include <list>
#include <memory>
-#include <string>
#include <SDL_types.h>
+#include <string>
+#include <vector>
#include <bitset>
-#include "sprite.h"
-#include "map.h"
#include "animatedsprite.h"
+#include "effectmanager.h"
+#include "map.h"
#include "particlecontainer.h"
+#include "sprite.h"
+
+#include "gui/speechbubble.h"
+
+#include "resources/colordb.h"
#define FIRST_IGNORE_EMOTE 14
#define STATUS_EFFECTS 32
@@ -42,8 +48,8 @@ class ItemInfo;
class Item;
class Map;
class Graphics;
-class ImageSet;
class Particle;
+class SpeechBubble;
class Text;
/**
@@ -113,20 +119,17 @@ class Being : public Sprite
/**
* Directions, to be used as bitmask values
*/
- static const char DOWN = 1;
- static const char LEFT = 2;
- static const char UP = 4;
- static const char RIGHT = 8;
+ enum { DOWN = 1, LEFT = 2, UP = 4, RIGHT = 8 };
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.
@@ -162,8 +165,12 @@ class Being : public Sprite
*
* @param amount The amount of damage.
*/
- virtual void
- takeDamage(int amount);
+ 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.
@@ -171,22 +178,19 @@ class Being : public Sprite
* @param victim The attacked being.
* @param damage The amount of damage dealt (0 means miss).
*/
- virtual void
- handleAttack(Being *victim, int damage);
+ virtual void handleAttack(Being *victim, int damage);
/**
* Returns the name of the being.
*/
- const std::string&
- getName() const { return mName; }
+ const std::string& getName() const { return mName; }
/**
* Sets the name for the being.
*
* @param name The name that should appear.
*/
- virtual void
- setName(const std::string &name) { mName = name; }
+ virtual void setName(const std::string &name) { mName = name; }
/**
* Gets the hair color for this being.
@@ -201,46 +205,51 @@ 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);
+ virtual void setHairStyle(int style, int color);
/**
* Sets visible equipments for this being.
*/
- virtual void
- setSprite(int slot, int id, std::string color = "");
+ virtual void setSprite(int slot, int id, std::string color = "");
/**
* Sets the gender of this being.
*/
- virtual void
- setGender(int gender) { mGender = gender; }
+ virtual void setGender(int gender) { mGender = gender; }
/**
* Gets the gender of this being.
*/
- int
- getGender() const { return mGender; }
+ int getGender() const { return mGender; }
/**
* Makes this being take the next step of his path.
*/
- virtual void
- nextStep();
+ virtual void nextStep();
+
+ virtual void setGM() { mIsGM = true; }
/**
* Performs being logic.
*/
- virtual void
- logic();
+ virtual void logic();
+
+ /**
+ * Draws the speech text above the being.
+ */
+ void drawSpeech(Graphics *graphics, int offsetX, int offsetY);
/**
* Draws the emotion picture above the being.
*/
- void
- drawEmotion(Graphics *graphics, int offsetX, int offsetY);
+ void drawEmotion(Graphics *graphics, int offsetX, int offsetY);
/**
* Returns the type of the being.
@@ -250,26 +259,22 @@ class Being : public Sprite
/**
* Gets the walk speed.
*/
- Uint16
- getWalkSpeed() const { return mWalkSpeed; }
+ Uint16 getWalkSpeed() const { return mWalkSpeed; }
/**
* Sets the walk speed.
*/
- void
- setWalkSpeed(Uint16 speed) { mWalkSpeed = speed; }
+ void setWalkSpeed(Uint16 speed) { mWalkSpeed = speed; }
/**
* Gets the sprite id.
*/
- Uint32
- getId() const { return mId; }
+ Uint32 getId() const { return mId; }
/**
* Sets the sprite id.
*/
- void
- setId(Uint32 id) { mId = id; }
+ void setId(Uint32 id) { mId = id; }
/**
* Sets the map the being is on
@@ -279,8 +284,7 @@ class Being : public Sprite
/**
* Sets the current action.
*/
- virtual void
- setAction(Uint8 action);
+ virtual void setAction(Action action);
/**
* Returns the current direction.
@@ -293,50 +297,53 @@ 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)
*/
- virtual void
- draw(Graphics *graphics, int offsetX, int offsetY) const;
+ virtual void draw(Graphics *graphics, int offsetX, int offsetY) const;
/**
* Returns the pixel X coordinate.
*/
- int
- getPixelX() const { return mPx; }
+ int getPixelX() const { return mPx; }
/**
* Returns the pixel Y coordinate.
*
* @see Sprite::getPixelY()
*/
- int
- getPixelY() const { return mPy; }
+ int getPixelY() const { return mPy; }
/**
* Get the current X pixel offset.
*/
- int
- getXOffset() const { return getOffset(LEFT, RIGHT); }
+ int getXOffset() const { return getOffset(LEFT, RIGHT); }
/**
* Get the current Y pixel offset.
*/
- int
- getYOffset() const { return getOffset(UP, DOWN); }
+ int getYOffset() const { return getOffset(UP, DOWN); }
/**
* Returns the horizontal size of the current base sprite of the being
*/
- virtual int
- getWidth() const;
+ virtual int getWidth() const;
/**
* Returns the vertical size of the current base sprite of the being
*/
- virtual int
- getHeight() const;
+ virtual int getHeight() const;
/**
* Returns the required size of a target cursor for this being.
@@ -355,19 +362,11 @@ class Being : public Sprite
mEmotionTime = emote_time;
}
- /**
- * Triggers a visual effect, such as `level up'
- *
- * Only draws the visual effect, does not play sound effects
- *
- * \param effectId ID of the effect to trigger
- */
- virtual void
- triggerEffect(int effectId) { internalTriggerEffect(effectId, false, true); }
+ // Target cursor being used by the being
+ Image *mTargetCursor;
const std::auto_ptr<Equipment> mEquipment;
-
static int getHairColorsNr(void);
static int getHairStylesNr(void);
@@ -386,19 +385,13 @@ 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
* \param sfx Whether to trigger sound effects
* \param gfx Whether to trigger graphical effects
*/
- void
- internalTriggerEffect(int effectId, bool sfx, bool gfx);
+ void internalTriggerEffect(int effectId, bool sfx, bool gfx);
Uint32 mId; /**< Unique sprite id */
Uint16 mWalkSpeed; /**< Walking speed */
@@ -406,14 +399,19 @@ 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 */
typedef std::bitset<STATUS_EFFECTS> StatusEffects;
/** 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;
Uint8 mGender;
Uint32 mSpeechTime;
@@ -435,6 +433,9 @@ class Being : public Sprite
*/
int getOffset(char pos, char neg) const;
+ // Speech Bubble components
+ SpeechBubble *mSpeechBubble;
+
static int instances; /**< Number of Being instances */
static ImageSet *emotionSet; /**< Emoticons used by beings */
};
diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp
index 51d45213..ada1ddfa 100644
--- a/src/beingmanager.cpp
+++ b/src/beingmanager.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
+#include <cassert>
#include "beingmanager.h"
-
#include "localplayer.h"
#include "monster.h"
#include "npc.h"
@@ -157,8 +156,6 @@ Being* BeingManager::findBeingByName(std::string name, Being::Type type)
return NULL;
}
-
-
Beings& BeingManager::getAll()
{
return mBeings;
@@ -191,7 +188,7 @@ void BeingManager::clear()
mBeings.remove(player_node);
}
- for_each(mBeings.begin(), mBeings.end(), make_dtor(mBeings));
+ delete_all(mBeings);
mBeings.clear();
if (player_node)
@@ -206,9 +203,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 7a840030..0179bed8 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 b740720f..9fbc4544 100644
--- a/src/configlistener.h
+++ b/src/configlistener.h
@@ -24,7 +24,6 @@
#include <iosfwd>
-
/**
* The listener interface for receiving notifications about changes to
* configuration options.
diff --git a/src/configuration.cpp b/src/configuration.cpp
index e2deae31..8e80de18 100644
--- a/src/configuration.cpp
+++ b/src/configuration.cpp
@@ -19,12 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
-#include "configuration.h"
-
#include <libxml/xmlwriter.h>
#include "configlistener.h"
+#include "configuration.h"
#include "log.h"
#include "utils/tostring.h"
diff --git a/src/configuration.h b/src/configuration.h
index 3751d429..197e1a41 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -22,11 +22,11 @@
#ifndef _TMW_CONFIGURATION_H
#define _TMW_CONFIGURATION_H
-#include <map>
-#include <list>
-#include <string>
#include <cassert>
#include <libxml/xmlwriter.h>
+#include <list>
+#include <map>
+#include <string>
class ConfigListener;
class ConfigurationObject;
diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp
new file mode 100644
index 00000000..4b835355
--- /dev/null
+++ b/src/effectmanager.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "effectmanager.h"
+
+#include "particle.h"
+#include "log.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, int x, int y)
+{
+ bool rValue = false;
+ for (std::list<EffectDescription>::iterator i = mEffects.begin(); i != mEffects.end(); ++i)
+ {
+ if ((*i).id == id)
+ {
+ printf("Found effect, playing it");
+ rValue = true;
+ if((*i).GFX != "")
+ particleEngine->addEffect((*i).GFX, x, y);
+ if((*i).SFX != "")
+ sound.playSfx((*i).SFX);
+ break;
+ }
+ }
+ return rValue;
+}
+
diff --git a/src/gui/buddywindow.h b/src/effectmanager.h
index 6b07f470..b5451f27 100644
--- a/src/gui/buddywindow.h
+++ b/src/effectmanager.h
@@ -17,40 +17,41 @@
* 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 _TMW_BUDDYWINDOW_H
-#define _TMW_BUDDYWINDOW_H
+#ifndef _EFFECT_MANAGER_H
+#define _EFFECT_MANAGER_H
-#include <guichan/actionlistener.hpp>
+#include <string>
+#include <list>
-#include "window.h"
+class EffectManager
+{
-#include "../guichanfwd.h"
+ public:
+ struct EffectDescription {
+ int id;
+ std::string GFX;
+ std::string SFX;
+ };
-class BuddyList;
+
+ EffectManager();
+
+ ~EffectManager();
-/**
- * Window showing buddy list.
- *
- * \ingroup Interface
- */
-class BuddyWindow : public Window, public gcn::ActionListener
-{
- public:
/**
- * Constructor.
+ * Triggers a effect with the id, at x,y
+ * returns true if ID exists
*/
- BuddyWindow();
+ bool trigger(int id, int x = 0, int y = 0);
- /**
- * Performs action.
- */
- void action(const gcn::ActionEvent &event);
+ private:
+ std::list<EffectDescription> mEffects;
- private:
- BuddyList *mBuddyList;
- gcn::ListBox *mListbox;
};
-#endif /* _TMW_BUDDYWINDOW_H */
+extern EffectManager *effectManager;
+
+#endif // _EFFECT_MANAGER_H
diff --git a/src/engine.cpp b/src/engine.cpp
index 2edc6550..74e11336 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "engine.h"
-
#include <list>
#include "being.h"
#include "beingmanager.h"
#include "configuration.h"
+#include "engine.h"
#include "flooritemmanager.h"
#include "game.h"
#include "graphics.h"
@@ -93,6 +92,27 @@ void Engine::changeMap(const std::string &mapPath)
if (newMap->hasProperty("minimap"))
{
mapImage = resman->getImage(newMap->getProperty("minimap"));
+
+ // Set the title for the Minimap
+ if (newMap->hasProperty("mapname"))
+ {
+ minimap->setCaption(newMap->getProperty("mapname"));
+ }
+ 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);
+ }
}
if (newMap->hasProperty("name"))
{
diff --git a/src/equipment.cpp b/src/equipment.cpp
index 0bdd1c70..f1d1d4f2 100644
--- a/src/equipment.cpp
+++ b/src/equipment.cpp
@@ -19,13 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <algorithm>
+
#include "equipment.h"
#include "item.h"
#include "inventory.h"
#include "localplayer.h"
-#include <algorithm>
-
Equipment::Equipment():
mArrows(0)
{
@@ -40,3 +40,4 @@ Equipment::setEquipment(int index, int inventoryIndex)
if (item)
item->setEquipped(true);
}
+
diff --git a/src/extensions.h b/src/extensions.h
new file mode 100644
index 00000000..5b95afc8
--- /dev/null
+++ b/src/extensions.h
@@ -0,0 +1,34 @@
+/*
+ * Aethyra
+ * Copyright 2008 Lloyd Bryant <sanga@aethyra.com>
+ *
+ * This file is part of the Aethyra project.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _EXTENSIONS_
+#define _EXTENSIONS_
+
+struct EXTENSIONS
+{
+ bool aethyra_inventory;
+ bool aethyra_spells;
+ bool aethyra_misc;
+};
+
+extern struct EXTENSIONS extensions;
+#endif
diff --git a/src/floor_item.cpp b/src/floor_item.cpp
index 7ad3c0c0..0b114e14 100644
--- a/src/floor_item.cpp
+++ b/src/floor_item.cpp
@@ -20,7 +20,6 @@
*/
#include "floor_item.h"
-
#include "map.h"
FloorItem::FloorItem(unsigned int id,
diff --git a/src/flooritemmanager.cpp b/src/flooritemmanager.cpp
index 006d62c1..7445b1e9 100644
--- a/src/flooritemmanager.cpp
+++ b/src/flooritemmanager.cpp
@@ -19,11 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
-
-#include "flooritemmanager.h"
-
#include "floor_item.h"
+#include "flooritemmanager.h"
#include "utils/dtor.h"
@@ -48,7 +45,7 @@ void FloorItemManager::destroy(FloorItem *item)
void FloorItemManager::clear()
{
- for_each(mFloorItems.begin(), mFloorItems.end(), make_dtor(mFloorItems));
+ delete_all(mFloorItems);
mFloorItems.clear();
}
diff --git a/src/game.cpp b/src/game.cpp
index 9fa0129e..93bec013 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -26,11 +26,12 @@
#include <sstream>
#include <string>
-#include <guichan/sdl/sdlinput.hpp>
#include <guichan/exception.hpp>
+#include <guichan/sdl/sdlinput.hpp>
#include "beingmanager.h"
#include "configuration.h"
+#include "effectmanager.h"
#include "engine.h"
#include "flooritemmanager.h"
#include "graphics.h"
@@ -74,9 +75,11 @@
#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"
@@ -93,6 +96,7 @@ std::string map_path;
bool done = false;
volatile int tick_time;
volatile int fps = 0, frame = 0;
+
Engine *engine = NULL;
Joystick *joystick = NULL;
@@ -112,7 +116,6 @@ InventoryWindow *inventoryWindow;
NpcListDialog *npcListDialog;
NpcTextDialog *npcTextDialog;
SkillDialog *skillDialog;
-//NewSkillDialog *newSkillWindow;
Setup* setupWindow;
Minimap *minimap;
EquipmentWindow *equipmentWindow;
@@ -126,11 +129,12 @@ ItemShortcutWindow *itemShortcutWindow;
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 +167,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;
}
}
@@ -193,7 +200,6 @@ void createGuiWindows(Network *network)
npcTextDialog = new NpcTextDialog();
npcListDialog = new NpcListDialog();
skillDialog = new SkillDialog();
- //newSkillWindow = new NewSkillDialog();
setupWindow = new Setup();
minimap = new Minimap();
equipmentWindow = new EquipmentWindow(player_node->mEquipment.get());
@@ -215,8 +221,7 @@ void createGuiWindows(Network *network)
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);
tradeWindow->setVisible(false);
@@ -251,7 +256,6 @@ void destroyGuiWindows()
delete minimap;
delete equipmentWindow;
//delete chargeDialog;
- //delete newSkillWindow;
delete tradeWindow;
//delete buddyWindow;
delete helpWindow;
@@ -277,6 +281,8 @@ Game::Game(Network *network):
beingManager = new BeingManager(network);
floorItemManager = new FloorItemManager();
+ effectManager = new EffectManager();
+
particleEngine = new Particle(NULL);
particleEngine->setupEngine();
@@ -311,17 +317,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.
+ * 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 real fix is to make sure we are not throwing away messages in the
- * network buffer due to not having registered the handlers above straight
- * after receiving a login success from the map server.
- *
- * The response from eAthena on this packet is ignored by the client.
+ * Note: This only affects the latest eAthena version. This
+ * packet is handled by the older version, but its response
+ * is ignored by the client
*/
MessageOut msg(mNetwork);
msg.writeInt16(CMSG_CLIENT_PING);
@@ -356,17 +358,17 @@ bool saveScreenshot(SDL_Surface *screenshot)
bool found = false;
do {
- screenshotCount++;
- filename.str("");
+ screenshotCount++;
+ filename.str("");
#if (defined __USE_UNIX98 || defined __FreeBSD__)
- filename << PHYSFS_getUserDir() << ".tmw/";
+ filename << PHYSFS_getUserDir() << ".aethyra/";
#elif defined __APPLE__
- filename << PHYSFS_getUserDir() << "Desktop/";
+ filename << PHYSFS_getUserDir() << "Desktop/";
#endif
- filename << "TMW_Screenshot_" << screenshotCount << ".png";
- testExists.open(filename.str().c_str(), std::ios::in);
- found = !testExists.is_open();
- testExists.close();
+ filename << "Ae_Screenshot_" << screenshotCount << ".png";
+ testExists.open(filename.str().c_str(), std::ios::in);
+ found = !testExists.is_open();
+ testExists.close();
} while (!found);
if (ImageWriter::writePNG(screenshot, filename.str()))
@@ -403,61 +405,61 @@ void Game::logic()
while (!done)
{
- // Handle all necessary game logic
- while (get_elapsed_time(gameTime) > 0)
- {
- handleInput();
- engine->logic();
- gameTime++;
- }
+ // Handle all necessary game logic
+ while (get_elapsed_time(gameTime) > 0)
+ {
+ handleInput();
+ engine->logic();
+ gameTime++;
+ }
- // This is done because at some point tick_time will wrap.
- gameTime = tick_time;
+ // This is done because at some point tick_time will wrap.
+ gameTime = tick_time;
- // Update the screen when application is active, delay otherwise.
- if (SDL_GetAppState() & SDL_APPACTIVE)
+ // Update the screen when application is active, delay otherwise.
+ if (SDL_GetAppState() & SDL_APPACTIVE)
+ {
+ // 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)
{
- // 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)
- {
- frame++;
- gui->draw();
- graphics->updateScreen();
- mDrawTime += mMinFrameTime;
-
- // Make sure to wrap mDrawTime, since tick_time will wrap.
- if (mDrawTime > MAX_TIME * 10)
- mDrawTime -= MAX_TIME * 10;
- }
- else
- {
- SDL_Delay(10);
- }
+ frame++;
+ gui->draw();
+ graphics->updateScreen();
+ mDrawTime += mMinFrameTime;
+
+ // Make sure to wrap mDrawTime, since tick_time will wrap.
+ if (mDrawTime > MAX_TIME * 10)
+ mDrawTime -= MAX_TIME * 10;
}
else
{
SDL_Delay(10);
- mDrawTime = tick_time * 10;
}
+ }
+ else
+ {
+ SDL_Delay(10);
+ mDrawTime = tick_time * 10;
+ }
- // Handle network stuff
- mNetwork->flush();
- mNetwork->dispatchMessages();
+ // Handle network stuff
+ mNetwork->flush();
+ mNetwork->dispatchMessages();
- if (!mNetwork->isConnected())
+ if (!mNetwork->isConnected())
+ {
+ if (!disconnectedDialog)
{
- if (!disconnectedDialog)
- {
- disconnectedDialog = new
- OkDialog("Network Error",
- "The connection to the server was lost, the program will now quit");
- disconnectedDialog->addActionListener(&exitListener);
- disconnectedDialog->requestMoveToTop();
- }
+ disconnectedDialog = new
+ OkDialog("Network Error",
+ "The connection to the server was lost, the program will now quit");
+ disconnectedDialog->addActionListener(&exitListener);
+ disconnectedDialog->requestMoveToTop();
}
}
+ }
}
void Game::handleInput()
@@ -478,7 +480,7 @@ void Game::handleInput()
{
gcn::Window *requestedWindow = NULL;
- if (setupWindow->isVisible() &&
+ if (setupWindow->isVisible() &&
keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE)
{
keyboard.setNewKey((int) event.key.keysym.sym);
@@ -534,194 +536,202 @@ void Game::handleInput()
}
used = true;
break;
- }
}
+ }
- // Smilie
- if (keyboard.isKeyActive(keyboard.KEY_SMILIE))
+ // Smilie
+ if (keyboard.isKeyActive(keyboard.KEY_SMILIE))
+ {
+ // Emotions
+ Uint8 emotion;
+ switch (event.key.keysym.sym)
{
- // 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;
+ }
+
+ if (emotion)
+ {
+ player_node->emote(emotion);
+ used = true;
+ }
+ }
+ switch (event.key.keysym.sym)
+ {
+ case SDLK_PAGEUP:
+ if (chatWindow->isVisible())
{
- 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;
+ chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL);
+ used = true;
}
+ break;
- if (emotion)
+ case SDLK_PAGEDOWN:
+ if (chatWindow->isVisible())
{
- player_node->emote(emotion);
+ chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL);
used = true;
return;
}
- }
- switch (event.key.keysym.sym)
- {
- case SDLK_PAGEUP:
- if (chatWindow->isVisible())
- {
- chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL);
- used = true;
- }
- break;
+ break;
- case SDLK_PAGEDOWN:
- if (chatWindow->isVisible())
- {
- chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL);
- used = true;
- }
+ case SDLK_F1:
+ // In-game Help
+ if (helpWindow->isVisible())
+ {
+ helpWindow->setVisible(false);
+ }
+ else
+ {
+ helpWindow->loadHelp("index");
+ helpWindow->requestMoveToTop();
+ }
+ used = true;
+ break;
+
+ case SDLK_F2: requestedWindow = statusWindow; break;
+ case SDLK_F3: requestedWindow = inventoryWindow; break;
+ case SDLK_F4: requestedWindow = equipmentWindow; break;
+ case SDLK_F5: requestedWindow = skillDialog; break;
+ case SDLK_F6: requestedWindow = minimap; break;
+ case SDLK_F7: requestedWindow = chatWindow; break;
+ case SDLK_F8: requestedWindow = itemShortcutWindow; break;
+ case SDLK_F9: requestedWindow = setupWindow; break;
+ case SDLK_F10: requestedWindow = debugWindow; break;
+
+ case SDLK_RETURN:
+ // Input chat window
+ if (chatWindow->isInputFocused() ||
+ deathNotice != NULL ||
+ weightNotice != NULL)
+ {
break;
+ }
- case SDLK_F1:
- // In-game Help
- if (helpWindow->isVisible())
- {
- helpWindow->setVisible(false);
- }
- else
- {
- helpWindow->loadHelp("index");
- helpWindow->requestMoveToTop();
- }
+ // 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"));
+ }
+ // Proceed to the next dialog option, or close the window
+ else if (npcTextDialog->isVisible())
+ {
+ npcTextDialog->action(gcn::ActionEvent(NULL, "ok"));
+ }
+ // Choose the currently highlighted dialogue option
+ else if (npcListDialog->isVisible())
+ {
+ npcListDialog->action(gcn::ActionEvent(NULL, "ok"));
+ }
+ // Else, open the chat edit box
+ else
+ {
+ chatWindow->requestChatFocus();
used = true;
- break;
-
- case SDLK_F2: requestedWindow = statusWindow; break;
- case SDLK_F3: requestedWindow = inventoryWindow; break;
- case SDLK_F4: requestedWindow = equipmentWindow; break;
- case SDLK_F5: requestedWindow = skillDialog; break;
- case SDLK_F6: requestedWindow = minimap; break;
- case SDLK_F7: requestedWindow = chatWindow; break;
- case SDLK_F8: requestedWindow = itemShortcutWindow; break;
- case SDLK_F9: requestedWindow = setupWindow; break;
- case SDLK_F10: requestedWindow = debugWindow; break;
- //case SDLK_F11: requestedWindow = newSkillWindow; break;
-
- case SDLK_RETURN:
- // Input chat window
- if (chatWindow->isInputFocused() ||
- deathNotice != NULL ||
- weightNotice != NULL)
- {
- break;
- }
+ }
+ break;
+ // Quitting confirmation dialog
+ case SDLK_ESCAPE:
+ if (!exitConfirm) {
+ exitConfirm = new ConfirmDialog(
+ "Quit", "Are you sure you want to quit?");
+ exitConfirm->addActionListener(&exitListener);
+ exitConfirm->requestMoveToTop();
+ }
+ else
+ {
+ exitConfirm->action(gcn::ActionEvent(NULL, "no"));
+ }
+ 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->addActionListener(&exitListener);
- exitConfirm->requestMoveToTop();
- }
- else
- {
- exitConfirm->action(gcn::ActionEvent(NULL, "no"));
- }
- break;
+ default:
+ break;
+ }
+ if (keyboard.isEnabled() && !chatWindow->isInputFocused())
+ {
+ const int tKey = keyboard.getKeyIndex(event.key.keysym.sym);
- default:
- break;
- }
- if (keyboard.isEnabled() && !chatWindow->isInputFocused())
+ // Do not activate shortcuts if tradewindow is visible
+ if (!tradeWindow->isVisible())
{
- 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++)
{
- // Checks if any item shortcut is pressed.
- for (int i = KeyboardConfig::KEY_SHORTCUT_0;
- i <= KeyboardConfig::KEY_SHORTCUT_9;
- i++)
- {
- if (tKey == i && !used) {
- itemShortcut->useItem(
- i - KeyboardConfig::KEY_SHORTCUT_0);
- break;
- }
+ if (tKey == i && !used) {
+ itemShortcut->useItem(i - KeyboardConfig::KEY_SHORTCUT_0);
+ break;
}
}
- switch (tKey) {
- case KeyboardConfig::KEY_PICKUP:
+ }
+ switch (tKey) {
+ case KeyboardConfig::KEY_PICKUP:
+ {
+ FloorItem *item = floorItemManager->findByCoordinates(
+ player_node->mX, player_node->mY);
+
+ // If none below the player, try the tile in front
+ // of the player
+ if (!item) {
+ Uint16 x = player_node->mX;
+ Uint16 y = player_node->mY;
+ switch (player_node->getSpriteDirection())
{
- FloorItem *item = floorItemManager->findByCoordinates(
- player_node->mX, player_node->mY);
-
- // If none below the player, try the tile in front of
- // the player
- if (!item) {
- Uint16 x = player_node->mX;
- Uint16 y = player_node->mY;
- if (player_node->getDirection() & Being::UP)
- y--;
- if (player_node->getDirection() & Being::DOWN)
- y++;
- if (player_node->getDirection() & Being::LEFT)
- x--;
- if (player_node->getDirection() & Being::RIGHT)
- x++;
-
- item = floorItemManager->findByCoordinates(x, y);
- }
+ case DIRECTION_UP : --y; break;
+ case DIRECTION_DOWN : ++y; break;
+ case DIRECTION_LEFT : --x; break;
+ case DIRECTION_RIGHT: ++x; break;
+ default: break;
+ }
+ item = floorItemManager->findByCoordinates(x, y);
+ }
- if (item)
- player_node->pickUp(item);
+ if (item)
+ player_node->pickUp(item);
- used = true;
- }
- break;
- case KeyboardConfig::KEY_SIT:
- // Player sit action
- player_node->toggleSit();
- used = true;
- break;
- case KeyboardConfig::KEY_HIDE_WINDOWS:
- // Hide certain windows
- if (!chatWindow->isInputFocused())
- {
- statusWindow->setVisible(false);
- inventoryWindow->setVisible(false);
- skillDialog->setVisible(false);
- setupWindow->setVisible(false);
- equipmentWindow->setVisible(false);
- helpWindow->setVisible(false);
- debugWindow->setVisible(false);
- }
- break;
+ used = true;
+ }
+ break;
+ case KeyboardConfig::KEY_SIT:
+ // Player sit action
+ player_node->toggleSit();
+ used = true;
+ break;
+ case KeyboardConfig::KEY_HIDE_WINDOWS:
+ // Hide certain windows
+ if (!chatWindow->isInputFocused())
+ {
+ statusWindow->setVisible(false);
+ inventoryWindow->setVisible(false);
+ skillDialog->setVisible(false);
+ setupWindow->setVisible(false);
+ equipmentWindow->setVisible(false);
+ helpWindow->setVisible(false);
+ debugWindow->setVisible(false);
+ }
+ break;
}
}
@@ -756,7 +766,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.
if (!keyboard.isEnabled())
@@ -782,7 +791,7 @@ void Game::handleInput()
direction |= Being::UP;
}
else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN) ||
- (joystick && joystick->isDown()))
+ (joystick && joystick->isDown()))
{
direction |= Being::DOWN;
}
@@ -802,60 +811,88 @@ 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 '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);
+
+ player_node->setTarget(target);
}
- // Target the nearest monster
- if (keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST)
- || (joystick && joystick->buttonPressed(3)))
+ // 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::MONSTER);
+ Being *target = beingManager->findNearestLivingBeing(x, y, 20, Being::NPC);
- if (target)
+ 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 24e29b7d..1cc18cae 100644
--- a/src/game.h
+++ b/src/game.h
@@ -40,35 +40,35 @@ extern volatile int tick_time;
class Game : public ConfigListener
{
public:
- Game(Network *network);
- ~Game();
+ Game(Network *network);
+ ~Game();
- void logic();
+ void logic();
- void handleInput();
+ void handleInput();
- void optionChanged(const std::string &name);
+ void optionChanged(const std::string &name);
private:
- Network *mNetwork;
-
- /** Used to determine whether to draw the next frame. */
- int mDrawTime;
-
- /** The minimum frame time (used for frame limiting). */
- int mMinFrameTime;
-
- typedef const std::auto_ptr<MessageHandler> MessageHandlerPtr;
- MessageHandlerPtr mBeingHandler;
- MessageHandlerPtr mBuySellHandler;
- MessageHandlerPtr mChatHandler;
- MessageHandlerPtr mEquipmentHandler;
- MessageHandlerPtr mInventoryHandler;
- MessageHandlerPtr mItemHandler;
- MessageHandlerPtr mNpcHandler;
- MessageHandlerPtr mPlayerHandler;
- MessageHandlerPtr mSkillHandler;
- MessageHandlerPtr mTradeHandler;
+ Network *mNetwork;
+
+ /** Used to determine whether to draw the next frame. */
+ int mDrawTime;
+
+ /** The minimum frame time (used for frame limiting). */
+ int mMinFrameTime;
+
+ typedef const std::auto_ptr<MessageHandler> MessageHandlerPtr;
+ MessageHandlerPtr mBeingHandler;
+ MessageHandlerPtr mBuySellHandler;
+ MessageHandlerPtr mChatHandler;
+ MessageHandlerPtr mEquipmentHandler;
+ MessageHandlerPtr mInventoryHandler;
+ MessageHandlerPtr mItemHandler;
+ MessageHandlerPtr mNpcHandler;
+ MessageHandlerPtr mPlayerHandler;
+ MessageHandlerPtr mSkillHandler;
+ MessageHandlerPtr mTradeHandler;
};
/**
diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp
index 1c549949..430a2aa2 100644
--- a/src/gui/browserbox.cpp
+++ b/src/gui/browserbox.cpp
@@ -26,6 +26,7 @@
#include <guichan/mouseinput.hpp>
#include "browserbox.h"
+#include "colour.h"
#include "linkhandler.h"
#ifdef USE_OPENGL
@@ -133,12 +134,12 @@ void BrowserBox::addRow(const std::string &row)
mLinks.push_back(bLink);
- newRow += "##L" + bLink.caption;
+ newRow += "##<" + bLink.caption;
tmp.erase(0, idx3 + 2);
if(tmp != "")
{
- newRow += "##P";
+ newRow += "##>";
}
idx1 = tmp.find("@@");
}
@@ -288,7 +289,8 @@ BrowserBox::draw(gcn::Graphics *graphics)
if ((mHighMode & UNDERLINE))
{
- graphics->setColor(gcn::Color(LINK));
+ bool valid;
+ graphics->setColor(gcn::Color(textColour->getColour('<', valid)));
graphics->drawLine(
mLinks[mSelectedLink].x1,
mLinks[mSelectedLink].y2,
@@ -315,58 +317,26 @@ BrowserBox::draw(gcn::Graphics *graphics)
if ( (mUseLinksAndUserColors && (j + 3) <= row.size()) ||
(!mUseLinksAndUserColors && (j == 0)) )
{
- // Check for color change in format "##x", x = [L,P,0..9]
+ // Check for color change in format "##x"
if ((row.at(j) == '#') && (row.at(j + 1) == '#'))
{
- switch (row.at(j + 2))
+ char c = row.at(j + 2);
+ if (c == '>')
{
- case 'L': // Link color
- prevColor = selColor;
- selColor = LINK;
- break;
- case 'P': // Previous color
- selColor = prevColor;
- break;
- case '1':
- prevColor = selColor;
- selColor = RED;
- break;
- case '2':
- prevColor = selColor;
- selColor = GREEN;
- break;
- case '3':
- prevColor = selColor;
- selColor = BLUE;
- break;
- case '4':
- prevColor = selColor;
- selColor = ORANGE;
- break;
- case '5':
- prevColor = selColor;
- selColor = YELLOW;
- break;
- case '6':
- prevColor = selColor;
- selColor = PINK;
- break;
- case '7':
- prevColor = selColor;
- selColor = PURPLE;
- break;
- case '8':
- prevColor = selColor;
- selColor = GRAY;
- break;
- case '9':
- prevColor = selColor;
- selColor = BROWN;
- break;
- case '0':
- default:
+ selColor = prevColor;
+ }
+ else
+ {
+ bool valid;
+ int rgb = textColour->getColour(c, valid);
+ if (c == '<')
+ {
prevColor = selColor;
- selColor = BLACK;
+ }
+ if (valid)
+ {
+ selColor = rgb;
+ }
}
j += 3;
diff --git a/src/gui/browserbox.h b/src/gui/browserbox.h
index 39ecbda8..267e0fea 100644
--- a/src/gui/browserbox.h
+++ b/src/gui/browserbox.h
@@ -25,8 +25,8 @@
#include <iosfwd>
#include <vector>
-#include <guichan/widget.hpp>
#include <guichan/mouselistener.hpp>
+#include <guichan/widget.hpp>
#include "../guichanfwd.h"
#include "../main.h"
@@ -111,30 +111,13 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener
};
/**
- * BrowserBox colors.
- *
- * NOTES (by Javila):
- * - color values is "0x" prefix followed by HTML color style.
- * - we can add up to 10 different colors: [0..9].
- * - we need a link and a highlighted link colors.
- * - not all colors will be fine with all backgrounds due transparent
- * windows and widgets. So, I think it's better keep BrowserBox
- * opaque (white background) by default.
+ * Some colours used in the browser box
*/
+
enum {
- BLACK = 0x000000, /**< Color 0 */
- RED = 0xff0000, /**< Color 1 */
- GREEN = 0x1fa052, /**< Color 2 */
- BLUE = 0x0000ff, /**< Color 3 */
- ORANGE = 0xe0980e, /**< Color 4 */
- YELLOW = 0xf1dc27, /**< Color 5 */
- PINK = 0xff00d8, /**< Color 6 */
- PURPLE = 0x8415e2, /**< Color 7 */
- GRAY = 0x919191, /**< Color 8 */
- BROWN = 0x8e4c17, /**< Color 9 */
- BGCOLOR = 0xffffff, /**< Bg color for opacity */
- LINK = 0xe50d0d, /**< Color L */
- HIGHLIGHT = 0xcacaca /**< Bg color for highlighted link */
+ BLACK = 0x000000,
+ BGCOLOR = 0xffffff,
+ HIGHLIGHT = 0xcacaca
};
/**
diff --git a/src/gui/button.h b/src/gui/button.h
index f451416c..eecd0dc0 100644
--- a/src/gui/button.h
+++ b/src/gui/button.h
@@ -26,6 +26,8 @@
#include <guichan/widgets/button.hpp>
+#include "../guichanfwd.h"
+
class ImageRect;
/**
diff --git a/src/gui/buttonbox.cpp b/src/gui/buttonbox.cpp
new file mode 100644
index 00000000..903d971d
--- /dev/null
+++ b/src/gui/buttonbox.cpp
@@ -0,0 +1,44 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "button.h"
+#include "buttonbox.h"
+
+ButtonBox::ButtonBox(const std::string &title, const std::string &buttonTxt,
+ ButtonBoxListener *listener) :
+ Window(title),
+ mListener(listener)
+{
+ Button *button = new Button(buttonTxt, "activate", this);
+ setContentSize(button->getWidth() + 10,
+ button->getHeight() + 10);
+ button->setPosition(5, 5);
+ add(button);
+}
+
+void
+ButtonBox::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "activate")
+ {
+ mListener->buttonBoxRespond();
+ }
+}
diff --git a/src/gui/newskill.h b/src/gui/buttonbox.h
index 49476e5e..edde4aa4 100644
--- a/src/gui/newskill.h
+++ b/src/gui/buttonbox.h
@@ -19,8 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef _TMW_NSKILL_H
-#define _TMW_NSKILL_H
+#ifndef _TMW_BUTTONBOX_H
+#define _TMW_BUTTONBOX_H
+
+#include <string>
#include <guichan/actionlistener.hpp>
@@ -28,42 +30,41 @@
#include "../guichanfwd.h"
-class ProgressBar;
-
-#define N_SKILL 100 // skill count constant
-#define N_SKILL_CAT 9 // skill category count
-#define N_SKILL_CAT_SIZE 10 // skill category maximum size
+class ButtonBoxListener
+{
+ public:
-struct nSkill {
- short level;
- short exp;
+ /*
+ * function that ButtonBox calls when the button has been pressed
+ */
+ virtual void buttonBoxRespond() = 0;
};
-/**
- * Dialog showing the skills in the planned skill model.
- *
- * \ingroup Interface
- */
-class NewSkillDialog : public Window, public gcn::ActionListener
+class ButtonBox : public Window, public gcn::ActionListener
{
public:
- /**
- * Constructor.
- */
- NewSkillDialog();
- // action listener
- void action(const gcn::ActionEvent &event);
+ /*
+ * Constructor
+ *
+ * @param title is the text that appears at the top of the box
+ * @param buttonTxt is the text that appears on the button
+ * @param listener points to the class that should respond to the
+ * button press
+ */
+ ButtonBox(const std::string &title, const std::string &buttonTxt,
+ ButtonBoxListener *listener);
+
+ /*
+ * called when the button is pressed
+ *
+ * @param event is the event that is generated
+ */
+ void
+ action(const gcn::ActionEvent &event);
private:
- void resetNSD(); // updates the values in the dialog box
- // members
- int startPoint; // starting point of skill listing
- ProgressBar *mSkillbar[N_SKILL_CAT_SIZE];
- gcn::Label *mSkillLabel[N_SKILL_CAT_SIZE];
- gcn::Label *mSkillLevel[N_SKILL_CAT_SIZE];
- nSkill mPlayerSkill[N_SKILL]; // pointer to an array of skill values
+ ButtonBoxListener *mListener;
};
-
#endif
diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp
index 714f52db..597a7cad 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"
@@ -157,9 +156,6 @@ void BuyDialog::action(const gcn::ActionEvent &event)
mSlider->setValue(mAmountItems);
updateButtonsAndLabels();
}
- // TODO: Actually we'd have a bug elsewhere if this check for the number
- // of items to be bought ever fails, Bertram removed the assertions, is
- // there a better way to ensure this fails in an _obivous_ way in C++?
else if (event.getId() == "buy" && mAmountItems > 0 &&
mAmountItems <= mMaxItems)
{
diff --git a/src/gui/buy.h b/src/gui/buy.h
index 0915385a..3b94bbaa 100644
--- a/src/gui/buy.h
+++ b/src/gui/buy.h
@@ -117,9 +117,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 42380882..57c95841 100644
--- a/src/gui/buysell.cpp
+++ b/src/gui/buysell.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "buysell.h"
-
#include "button.h"
+#include "buysell.h"
#include "../npc.h"
diff --git a/src/gui/buysell.h b/src/gui/buysell.h
index 2391ed1c..d73205b6 100644
--- a/src/gui/buysell.h
+++ b/src/gui/buysell.h
@@ -26,6 +26,8 @@
#include "window.h"
+#include "../guichanfwd.h"
+
/**
* A dialog to choose between buying or selling at a shop.
*
diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp
index d951f12e..53cc1e8d 100644
--- a/src/gui/char_select.cpp
+++ b/src/gui/char_select.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "char_select.h"
-
#include <string>
#include <guichan/widgets/label.hpp>
#include "button.h"
+#include "char_select.h"
#include "confirm_dialog.h"
#include "ok_dialog.h"
#include "playerbox.h"
@@ -254,7 +253,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:");
@@ -320,6 +322,7 @@ CharCreateDialog::~CharCreateDialog()
void
CharCreateDialog::action(const gcn::ActionEvent &event)
{
+ int numberOfColors = ColorDB::size();
if (event.getId() == "create") {
if (getName().length() >= 4) {
// Attempt to create the character
@@ -335,16 +338,16 @@ CharCreateDialog::action(const gcn::ActionEvent &event)
scheduleDelete();
}
else if (event.getId() == "nextcolor") {
- mPlayer->setHairStyle(-1, mPlayer->getHairColor() + 1);
+ mPlayer->setHairStyle(mPlayer->getHairStyle(), (mPlayer->getHairColor() + 1) % numberOfColors);
}
else if (event.getId() == "prevcolor") {
- mPlayer->setHairStyle(-1, mPlayer->getHairColor() + Being::getHairColorsNr() - 1);
+ mPlayer->setHairStyle(mPlayer->getHairStyle(), (mPlayer->getHairColor() + numberOfColors - 1) % numberOfColors);
}
else if (event.getId() == "nextstyle") {
- mPlayer->setHairStyle(mPlayer->getHairStyle() + 1, -1);
+ mPlayer->setHairStyle(mPlayer->getHairStyle() + 1, mPlayer->getHairColor());
}
else if (event.getId() == "prevstyle") {
- mPlayer->setHairStyle(mPlayer->getHairStyle() + Being::getHairStylesNr() - 1, -1);
+ mPlayer->setHairStyle(mPlayer->getHairStyle() + mPlayer->getNumOfHairstyles() - 1, mPlayer->getHairColor());
}
}
diff --git a/src/gui/char_select.h b/src/gui/char_select.h
index 0890bea9..63630736 100644
--- a/src/gui/char_select.h
+++ b/src/gui/char_select.h
@@ -22,16 +22,16 @@
#ifndef _CHAR_SELECT_H
#define _CHAR_SELECT_H
+#include <guichan/actionlistener.hpp>
+
#include "window.h"
#include "../guichanfwd.h"
#include "../lockedarray.h"
-#include <guichan/actionlistener.hpp>
-
-class Player;
class LocalPlayer;
class Network;
+class Player;
class PlayerBox;
/**
diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp
index ce068ad1..054aff84 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"
@@ -106,7 +105,6 @@ ServerSelectDialog::action(const gcn::ActionEvent &event)
mLoginData->hostname = iptostring(si->address);
mLoginData->port = si->port;
mLoginData->updateHost = si->updateHost;
-
state = mNextState;
}
else if (event.getId() == "cancel") {
diff --git a/src/gui/chargedialog.cpp b/src/gui/chargedialog.cpp
index 1c9edf45..1733c7eb 100644
--- a/src/gui/chargedialog.cpp
+++ b/src/gui/chargedialog.cpp
@@ -24,7 +24,6 @@
*/
#include "chargedialog.h"
-
#include "progressbar.h"
#include "../localplayer.h"
diff --git a/src/gui/chargedialog.h b/src/gui/chargedialog.h
index 9517ef6a..53998ab8 100644
--- a/src/gui/chargedialog.h
+++ b/src/gui/chargedialog.h
@@ -24,6 +24,8 @@
#include "window.h"
+#include "../guichanfwd.h"
+
class ProgressBar;
#define CHARGE_TIME 1000 // time in milliseconds it takes to charge up an attack
diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp
index 1e22772b..3f12c462 100644
--- a/src/gui/chat.cpp
+++ b/src/gui/chat.cpp
@@ -20,31 +20,32 @@
*/
#include <algorithm>
-#include <sstream>
+#include <fstream>
#include <guichan/focushandler.hpp>
#include <guichan/key.hpp>
-#include "chat.h"
-
#include "browserbox.h"
+#include "chat.h"
#include "chatinput.h"
#include "scrollarea.h"
#include "windowcontainer.h"
+#include "../beingmanager.h"
#include "../configuration.h"
+#include "../extensions.h"
#include "../game.h"
#include "../localplayer.h"
+#include "../party.h"
+#include "../recorder.h"
#include "../net/messageout.h"
#include "../net/protocol.h"
#include "../utils/trim.h"
-ChatWindow::ChatWindow(Network *network):
- Window(""),
- mNetwork(network),
- mTmpVisible(false)
+ChatWindow::ChatWindow(Network * network):
+Window(""), mNetwork(network), mTmpVisible(false)
{
setWindowName("Chat");
@@ -61,10 +62,10 @@ ChatWindow::ChatWindow(Network *network):
mTextOutput->disableLinksAndUserColors();
mTextOutput->setMaxRow((int) config.getValue("ChatLogLength", 0));
mScrollArea = new ScrollArea(mTextOutput);
- mScrollArea->setPosition(
- mScrollArea->getFrameSize(), mScrollArea->getFrameSize());
- mScrollArea->setScrollPolicy(
- gcn::ScrollArea::SHOW_NEVER, gcn::ScrollArea::SHOW_ALWAYS);
+ mScrollArea->setPosition(mScrollArea->getFrameSize(),
+ mScrollArea->getFrameSize());
+ mScrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER,
+ gcn::ScrollArea::SHOW_ALWAYS);
mScrollArea->setOpaque(false);
add(mScrollArea);
@@ -73,10 +74,26 @@ ChatWindow::ChatWindow(Network *network):
// Add key listener to chat input to be able to respond to up/down
mChatInput->addKeyListener(this);
mCurHist = mHistory.end();
+
+ // Read the party prefix
+ std::string partyPrefix = config.getValue("PartyPrefix", "$");
+ mPartyPrefix = (partyPrefix == "" ? '$' : partyPrefix.at(0));
+ mReturnToggles = config.getValue("ReturnToggles", "0") == "1";
+ mRecorder = new Recorder(this);
+ mParty = new Party(this, mNetwork);
+}
+
+ChatWindow::~ChatWindow()
+{
+ char partyPrefix[2] = ".";
+ *partyPrefix = mPartyPrefix;
+ config.setValue("PartyPrefix", partyPrefix);
+ config.setValue("ReturnToggles", mReturnToggles ? "1" : "0");
+ delete mRecorder;
}
void
-ChatWindow::logic()
+ ChatWindow::logic()
{
// todo: only do this when the size changes (updateWidgets?)
@@ -84,28 +101,26 @@ ChatWindow::logic()
mChatInput->setPosition(mChatInput->getFrameSize(),
area.height - mChatInput->getHeight() -
- mChatInput->getFrameSize());
+ mChatInput->getFrameSize());
mChatInput->setWidth(area.width - 2 * mChatInput->getFrameSize());
mScrollArea->setWidth(area.width - 2 * mScrollArea->getFrameSize());
mScrollArea->setHeight(area.height - 2 * mScrollArea->getFrameSize() -
- mChatInput->getHeight() - 5);
+ mChatInput->getHeight() - 5);
mScrollArea->logic();
}
-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;
// Fix the owner of welcome message.
- if (line.substr(0, 7) == "Welcome")
- {
+ if (line.substr(0, 7) == "Welcome") {
own = BY_SERVER;
}
@@ -115,37 +130,41 @@ ChatWindow::chatLog(std::string line, int own)
tmp.text = line.substr(pos + 3);
}
- std::string lineColor = "##0"; // Equiv. to BrowserBox::BLACK
+ std::string lineColor = "##C";
switch (own) {
case BY_GM:
tmp.nick += std::string("Global announcement: ");
- lineColor = "##1"; // Equiv. to BrowserBox::RED
+ lineColor = "##G";
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.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 += CAT_WHISPER;
- 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;
}
@@ -155,41 +174,37 @@ ChatWindow::chatLog(std::string line, int own)
// 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());
- }
- else
- {
+ mScrollArea->setVerticalScrollAmount(mScrollArea->
+ getVerticalMaxScroll());
+ } else {
mTextOutput->addRow(line);
}
+
+ mRecorder->record(line.substr(3));
}
-void
-ChatWindow::chatLog(CHATSKILL act)
+void ChatWindow::chatLog(CHATSKILL act)
{
chatLog(const_msg(act), BY_SERVER);
}
-void
-ChatWindow::action(const gcn::ActionEvent &event)
+void ChatWindow::action(const gcn::ActionEvent & event)
{
- if (event.getId() == "chatinput")
- {
+ if (event.getId() == "chatinput") {
std::string message = mChatInput->getText();
if (!message.empty()) {
@@ -197,7 +212,6 @@ ChatWindow::action(const gcn::ActionEvent &event)
if (mHistory.empty() || message != mHistory.back()) {
mHistory.push_back(message);
}
-
// Reset history iterator
mCurHist = mHistory.end();
@@ -207,24 +221,23 @@ ChatWindow::action(const gcn::ActionEvent &event)
// Clear the text from the chat input
mChatInput->setText("");
}
-
- // 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 (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);
+ }
}
}
}
-void
-ChatWindow::requestChatFocus()
+void ChatWindow::requestChatFocus()
{
// Make sure chatWindow is visible
- if (!isVisible())
- {
+ if (!isVisible()) {
setVisible(true);
/*
@@ -234,57 +247,38 @@ ChatWindow::requestChatFocus()
*/
mTmpVisible = true;
}
-
// Give focus to the chat input
mChatInput->setVisible(true);
mChatInput->requestFocus();
}
-bool
-ChatWindow::isInputFocused()
+bool ChatWindow::isInputFocused()
{
return mChatInput->isFocused();
}
-void
-ChatWindow::whisper(const std::string &nick, std::string msg, int prefixlen)
-{
- 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) {
- recvnick = msg.substr(1, pos - 1);
- msg.erase(0, pos + 2);
- }
- }
- else
- {
- const std::string::size_type pos = msg.find(" ");
- if (pos != std::string::npos) {
- recvnick = msg.substr(0, pos);
- msg.erase(0, pos + 1);
- }
- }
-
- MessageOut outMsg(mNetwork);
- outMsg.writeInt16(CMSG_CHAT_WHISPER);
- outMsg.writeInt16(msg.length() + 28);
- outMsg.writeString(recvnick, 24);
- outMsg.writeString(msg, msg.length());
-
- chatLog("Whispering to " + recvnick + " : " + msg, BY_PLAYER);
-}
-
-void
-ChatWindow::chatSend(const std::string &nick, std::string msg)
+void ChatWindow::chatSend(const std::string &nick, std::string msg)
{
/* Some messages are managed client side, while others
* require server handling by proper packet. Probably
* those if elses should be replaced by protocol calls */
+ // Send party message
+ if (msg.at(0) == mPartyPrefix) {
+ msg.erase(0, 1);
+ std::size_t length = msg.length() + 1;
+
+ if (length == 0) {
+ chatLog("Trying to send a blank party message.", BY_SERVER);
+ return;
+ }
+ MessageOut outMsg(mNetwork);
+
+ outMsg.writeInt16(CMSG_PARTY_MESSAGE);
+ outMsg.writeInt16(length + 4);
+ outMsg.writeString(msg, length);
+ return;
+ }
// Prepare ordinary message
if (msg.substr(0, 1) != "/") {
msg = nick + " : " + msg;
@@ -294,18 +288,31 @@ 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());
+ return;
}
- else if (msg.substr(0, IS_HELP_LENGTH) == IS_HELP)
+ else if (command == "help")
{
- msg.erase(0, IS_HELP_LENGTH + 1);
+ msg.erase(0, 6);
trim(msg);
std::size_t space = msg.find(" ");
std::string msg1;
@@ -325,112 +332,233 @@ ChatWindow::chatSend(const std::string &nick, std::string msg)
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)
- {
+ if (command == "who") {
MessageOut outMsg(mNetwork);
outMsg.writeInt16(0x00c1);
+ return;
}
- else if (msg.substr(0, IS_CLEAR_LENGTH) == IS_CLEAR)
- {
+ if (command == "clear") {
mTextOutput->clearRows();
+ return;
}
- 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);
+ if (command == "whisper" || command == "msg" || command == "w") {
+ std::string recvnick = "";
+
+ if (msg.substr(0, 1) == "\"") {
+ const std::string::size_type pos = msg.find('"', 1);
+ if (pos != std::string::npos) {
+ recvnick = msg.substr(1, pos - 1);
+ msg.erase(0, pos + 2);
+ }
+ } else {
+ const std::string::size_type pos = msg.find(" ");
+ if (pos != std::string::npos) {
+ recvnick = msg.substr(0, pos);
+ msg.erase(0, pos + 1);
+ }
+ }
+
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_CHAT_WHISPER);
+ outMsg.writeInt16(msg.length() + 28);
+ outMsg.writeString(recvnick, 24);
+ outMsg.writeString(msg, msg.length());
+
+ chatLog("Whispering to " + recvnick + " : " + msg, BY_PLAYER);
+ return;
+ }
+ if (command == "record") {
+ mRecorder->respond(msg);
+ return;
+ }
+ if (command == "toggle") {
+ if (msg == "") {
+ chatLog(mReturnToggles ? "Return toggles chat."
+ : "Message closes chat.", BY_SERVER);
+ return;
+ }
+ msg = msg.substr(0, 1);
+ if (msg == "1" || msg == "y" || msg == "t" || msg == "Y" || msg == "T") {
+ chatLog("Return now toggles chat.", BY_SERVER);
+ mReturnToggles = true;
+ return;
+ }
+ if (msg == "0" || msg == "n" || msg == "f" || msg == "N" || msg == "F") {
+ chatLog("Message now closes chat.", BY_SERVER);
+ mReturnToggles = false;
+ return;
+ }
+ chatLog("Options to /toggle are \"yes\", \"no\", \"true\", \"false\", "
+ "\"1\", \"0\".", BY_SERVER);
+ return;
}
+ if (command == "party") {
+ if (msg == "") {
+ chatLog("Unknown party command... Type \"/help\" party for more "
+ "information.", BY_SERVER);
+ return;
+ }
+ const std::string::size_type space = msg.find(" ");
+ std::string rest = (space == std::string::npos ? ""
+ : msg.substr(space + 1, msg.length()));
+ if (rest != "") {
+ msg = msg.substr(0, space);
+ while (msg != "" && msg[0] == ' ') {
+ msg = msg.substr(1, msg.length());
+ }
+ }
+ party(msg, rest);
+ return;
+ }
+ if (command == "cast") {
+ /*
+ * This will eventually be replaced by a GUI, so
+ * we don't need to get too sophisticated
+ */
+ if (extensions.aethyra_spells) {
+ MessageOut outMsg(mNetwork);
+ if (msg == "heal") {
+ outMsg.writeInt16(0x03f3);
+ outMsg.writeInt16(0x01);
+ outMsg.writeInt32(0);
+ outMsg.writeInt8(0);
+ outMsg.writeInt8(0);
+ outMsg.writeString("", 24);
+ } else if (msg == "gather") {
+ outMsg.writeInt16(0x03f3);
+ outMsg.writeInt16(0x02);
+ outMsg.writeInt32(0);
+ outMsg.writeInt8(0);
+ outMsg.writeInt8(0);
+ outMsg.writeString("", 24);
+ } else {
+ chatLog("No such spell!", BY_SERVER);
+ }
+ } else {
+ chatLog("The current server doesn't support spells", BY_SERVER);
+ }
+ return;
+ }
+ if (command == "present") {
+ Beings & beings = beingManager->getAll();
+ std::string response = "";
+ for (BeingIterator bi = beings.begin(), be = beings.end();
+ bi != be; ++bi) {
+ if ((*bi)->getType() == Being::PLAYER) {
+ if (response != "") {
+ response += ", ";
+ }
+ response += (*bi)->getName();
+ }
+ }
+ if (mRecorder->isRecording()) {
+ // Get the current system time
+ time_t t;
+ time(&t);
+
+ // Format the time string properly
+ std::stringstream timeStr;
+ timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "")
+ << (int) (((t / 60) / 60) % 24)
+ << ":" << (((t / 60) % 60 < 10) ? "0" : "")
+ << (int) ((t / 60) % 60)
+ << "] ";
+
+
+ mRecorder->record(timeStr.str() + "Present: " + response + ".");
+ chatLog("Attendance written to record log.", BY_SERVER, true);
+ } else {
+ chatLog("Present: " + response, BY_SERVER);
+ }
+ return;
+ }
+ chatLog("Unknown command", BY_SERVER);
}
-std::string
-ChatWindow::const_msg(CHATSKILL act)
+std::string ChatWindow::const_msg(CHATSKILL act)
{
std::string msg;
if (act.success == SKILL_FAILED && act.skill == SKILL_BASIC) {
switch (act.bskill) {
- case BSKILL_TRADE :
+ case BSKILL_TRADE:
msg = "Trade failed!";
break;
- case BSKILL_EMOTE :
+ case BSKILL_EMOTE:
msg = "Emote failed!";
break;
- case BSKILL_SIT :
+ case BSKILL_SIT:
msg = "Sit failed!";
break;
- case BSKILL_CREATECHAT :
+ case BSKILL_CREATECHAT:
msg = "Chat creating failed!";
break;
- case BSKILL_JOINPARTY :
+ case BSKILL_JOINPARTY:
msg = "Could not join party!";
break;
- case BSKILL_SHOUT :
+ case BSKILL_SHOUT:
msg = "Cannot shout!";
break;
}
switch (act.reason) {
- case RFAIL_SKILLDEP :
- msg += " You have not yet reached a high enough lvl!";
+ case RFAIL_SKILLDEP:
+ msg += " You have not yet reached a high enough level!";
break;
- case RFAIL_INSUFHP :
+ case RFAIL_INSUFHP:
msg += " Insufficient HP!";
break;
- case RFAIL_INSUFSP :
+ case RFAIL_INSUFSP:
msg += " Insufficient SP!";
break;
- case RFAIL_NOMEMO :
+ case RFAIL_NOMEMO:
msg += " You have no memos!";
break;
- case RFAIL_SKILLDELAY :
+ case RFAIL_SKILLDELAY:
msg += " You cannot do that right now!";
break;
- case RFAIL_ZENY :
+ case RFAIL_ZENY:
msg += " Seems you need more Zeny... ;-)";
break;
- case RFAIL_WEAPON :
+ case RFAIL_WEAPON:
msg += " You cannot use this skill with that kind of weapon!";
break;
- case RFAIL_REDGEM :
+ case RFAIL_REDGEM:
msg += " You need another red gem!";
break;
- case RFAIL_BLUEGEM :
+ case RFAIL_BLUEGEM:
msg += " You need another blue gem!";
break;
- case RFAIL_OVERWEIGHT :
+ case RFAIL_OVERWEIGHT:
msg += " You're carrying to much to do this!";
break;
- default :
+ default:
msg += " Huh? What's that?";
break;
}
} else {
- switch(act.skill) {
- case SKILL_WARP :
+ switch (act.skill) {
+ case SKILL_WARP:
msg = "Warp failed...";
break;
- case SKILL_STEAL :
+ case SKILL_STEAL:
msg = "Could not steal anything...";
break;
- case SKILL_ENVENOM :
+ case SKILL_ENVENOM:
msg = "Poison had no effect...";
break;
}
}
-
return msg;
}
-void
-ChatWindow::scroll(int amount)
+void ChatWindow::scroll(int amount)
{
if (!isVisible())
return;
@@ -442,25 +570,20 @@ ChatWindow::scroll(int amount)
mTextOutput->showPart(scr);
}
-void
-ChatWindow::keyPressed(gcn::KeyEvent &event)
+void ChatWindow::keyPressed(gcn::KeyEvent & event)
{
if (event.getKey().getValue() == gcn::Key::DOWN &&
- mCurHist != mHistory.end())
- {
+ mCurHist != mHistory.end()) {
// Move forward through the history
HistoryIterator prevHist = mCurHist++;
if (mCurHist != mHistory.end()) {
mChatInput->setText(*mCurHist);
mChatInput->setCaretPosition(mChatInput->getText().length());
- }
- else {
+ } else {
mCurHist = prevHist;
}
- }
- else if (event.getKey().getValue() == gcn::Key::UP &&
- mCurHist != mHistory.begin() && mHistory.size() > 0)
- {
+ } else if (event.getKey().getValue() == gcn::Key::UP &&
+ mCurHist != mHistory.begin() && mHistory.size() > 0) {
// Move backward through the history
mCurHist--;
mChatInput->setText(*mCurHist);
@@ -468,15 +591,13 @@ ChatWindow::keyPressed(gcn::KeyEvent &event)
}
}
-void
-ChatWindow::setInputText(std::string input_str)
+void ChatWindow::setInputText(std::string input_str)
{
- mChatInput->setText(input_str + " ");
- requestChatFocus();
+ mChatInput->setText(input_str + " ");
+ requestChatFocus();
}
-void
-ChatWindow::setVisible(bool isVisible)
+void ChatWindow::setVisible(bool isVisible)
{
Window::setVisible(isVisible);
@@ -488,18 +609,46 @@ ChatWindow::setVisible(bool isVisible)
mTmpVisible = false;
}
-void ChatWindow::help(const std::string &msg1, const std::string &msg2)
+void ChatWindow::party(const std::string & command, const std::string & rest)
+{
+ if (command == "prefix") {
+ if (rest == "") {
+ char temp[2] = ".";
+ *temp = mPartyPrefix;
+ chatLog("The current party prefix is " + std::string(temp),
+ BY_SERVER);
+ return;
+ }
+ 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);
+ }
+ }
+ return;
+ }
+ mParty->respond(command, rest);
+}
+
+void ChatWindow::help(const std::string & msg1, const std::string & msg2)
{
chatLog("-- Help --", BY_SERVER);
- if (msg1 == "")
- {
+ if (msg1 == "") {
chatLog("/announce: Global announcement (GM only)", BY_SERVER);
chatLog("/clear: Clears this window", BY_SERVER);
chatLog("/help: Display this help.", BY_SERVER);
+ mParty->help();
+ chatLog("/present: Get list of players present", BY_SERVER);
+ mRecorder->help();
+ chatLog("/toggle: Determine whether <return> toggles the chat log.",
+ BY_SERVER);
chatLog("/where: Display map name", BY_SERVER);
chatLog("/whisper <nick> <message>: Sends a private <message>"
" to <nick>", BY_SERVER);
- chatLog("/w <nick> <message>: Short form for /whisper", BY_SERVER);
chatLog("/who: Display number of online users", BY_SERVER);
chatLog("For more information, type /help <command>", BY_SERVER);
return;
@@ -528,6 +677,37 @@ void ChatWindow::help(const std::string &msg1, const std::string &msg2)
chatLog("This command displays help on <command>.", BY_SERVER);
return;
}
+ if (msg1 == "party")
+ {
+ mParty->help(msg2);
+ return;
+ }
+ 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);
+ return;
+ }
+ if (msg1 == "record")
+ {
+ mRecorder->help(msg2);
+ return;
+ }
+ 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);
+ return;
+ }
if (msg1 == "where")
{
chatLog("Command: /where", BY_SERVER);
@@ -535,11 +715,9 @@ void ChatWindow::help(const std::string &msg1, const std::string &msg2)
BY_SERVER);
return;
}
- if (msg1 == "whisper" || msg1 == "w")
- {
+ if (msg1 == "whisper" || msg1 == "msg" || msg1 == "w") {
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("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;
diff --git a/src/gui/chat.h b/src/gui/chat.h
index 76a8146c..437dc115 100644
--- a/src/gui/chat.h
+++ b/src/gui/chat.h
@@ -22,6 +22,7 @@
#ifndef _TMW_CHAT_H
#define _TMW_CHAT_H
+#include <fstream>
#include <list>
#include <string>
@@ -34,32 +35,20 @@
class BrowserBox;
class Network;
+class Recorder;
+class Party;
class ScrollArea;
#define BY_GM 0 // those should be self-explanatory =)
#define BY_PLAYER 1
#define BY_OTHER 2
#define BY_SERVER 3
+#define BY_PARTY 4
-#define ACT_WHISPER 4 // getting whispered at
-#define ACT_IS 5 // equivalent to "/me" on IRC
-
-#define BY_LOGGER 6
-
-#define IS_ANNOUNCE "/announce "
-#define IS_ANNOUNCE_LENGTH 10
-#define IS_HELP "/help"
-#define IS_HELP_LENGTH 5
-#define IS_WHERE "/where"
-#define IS_WHERE_LENGTH 6
-#define IS_WHO "/who"
-#define IS_WHO_LENGTH 4
-#define IS_CLEAR "/clear"
-#define IS_CLEAR_LENGTH 6
-#define IS_WHISPER "/whisper"
-#define IS_WHISPER_LENGTH 8
-#define IS_SHORT_WHISPER "/w"
-#define IS_SHORT_WHISPER_LENGTH 2
+#define ACT_WHISPER 5 // getting whispered at
+#define ACT_IS 6 // equivalent to "/me" on IRC
+
+#define BY_LOGGER 7
/**
* gets in between usernick and message text depending on
@@ -118,133 +107,150 @@ struct CHATSKILL
* \ingroup Interface
*/
class ChatWindow : public Window, public gcn::ActionListener,
- public gcn::KeyListener
+ public gcn::KeyListener
{
public:
- /**
- * Constructor.
- */
- ChatWindow(Network *network);
-
- /**
- * Logic (updates components' size)
- */
- void logic();
-
- /*
- * 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);
-
- /*
- * Calls original chat_log() after processing the packet.
- */
- void chatLog(CHATSKILL);
-
- /**
- * Performs action.
- */
- void action(const gcn::ActionEvent &event);
-
- /**
- * Request focus for typing chat message.
- */
- void requestChatFocus();
-
- /**
- * Checks whether ChatWindow is Focused or not.
- */
- bool isInputFocused();
-
- /**
- * Determines whether to send a command or an ordinary message, then
- * contructs packets & sends them.
- *
- * @param nick The character's name to display in front.
- * @param msg The message text which is to be send.
- *
- * NOTE:
- * The nickname is required by the server, if not specified
- * the message may not be sent unless a command was intended
- * which requires another packet to be constructed! you can
- * achieve this by putting a slash ("/") infront of the
- * message followed by the command name and the message.
- * of course all slash-commands need implemented handler-
- * routines. ;-)
- * remember, a line starting with "@" is not a command that needs
- * to be parsed rather is sent using the normal chat-packet.
- *
- * EXAMPLE:
- * // for an global announcement /- command
- * chatlog.chat_send("", "/announce Hello to all logged in users!");
- * // for simple message by a user /- message
- * chatlog.chat_send("Zaeiru", "Hello to all users on the screen!");
- */
- void
- chatSend(const std::string &nick, std::string msg);
-
- /** Called when key is pressed */
- void
- keyPressed(gcn::KeyEvent &event);
-
- /** Called to set current text */
- void
- setInputText(std::string input_str);
-
- /** Override to reset mTmpVisible */
- void
- setVisible(bool visible);
+ /**
+ * Constructor.
+ */
+ ChatWindow(Network *network);
+
+ /**
+ * Destructor: used to write back values to the config file
+ */
+ ~ChatWindow();
+
+ /**
+ * Logic (updates components' size)
+ */
+ void logic();
+
+ /**
+ * 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, bool ignoreRecord = false);
+
+ /**
+ * Calls original chat_log() after processing the packet.
+ */
+ void chatLog(CHATSKILL);
+
+ /**
+ * Performs action.
+ */
+ void action(const gcn::ActionEvent &event);
+
+ /**
+ * Request focus for typing chat message.
+ */
+ void requestChatFocus();
+
+ /**
+ * Checks whether ChatWindow is Focused or not.
+ */
+ bool isInputFocused();
+
+ /**
+ * Determines whether to send a command or an ordinary message, then
+ * contructs packets & sends them.
+ *
+ * @param nick The character's name to display in front.
+ * @param msg The message text which is to be send.
+ *
+ * NOTE:
+ * The nickname is required by the server, if not specified
+ * the message may not be sent unless a command was intended
+ * which requires another packet to be constructed! you can
+ * achieve this by putting a slash ("/") infront of the
+ * message followed by the command name and the message.
+ * of course all slash-commands need implemented handler-
+ * routines. ;-)
+ * remember, a line starting with "@" is not a command that needs
+ * to be parsed rather is sent using the normal chat-packet.
+ *
+ * EXAMPLE:
+ * // for an global announcement /- command
+ * chatlog.chat_send("", "/announce Hello to all logged in users!");
+ * // for simple message by a user /- message
+ * chatlog.chat_send("Zaeiru", "Hello to all users on the screen!");
+ */
+ void
+ chatSend(const std::string &nick, std::string msg);
+
+ /** Called when key is pressed */
+ void
+ keyPressed(gcn::KeyEvent &event);
+
+ /** Called to set current text */
+ void
+ setInputText(std::string input_str);
+
+ /** Override to reset mTmpVisible */
+ void
+ setVisible(bool visible);
/**
- * Scrolls the chat window
- *
- * @param amount direction and amount to scroll. Negative numbers scroll
- * up, positive numbers scroll down. The absolute amount indicates the
- * amount of 1/8ths of chat window real estate that should be scrolled.
- */
- void
- scroll(int amount);
-
- /**
- * help implements the /help command
- *
- * @param msg1 is the command that the player needs help on
- * @param msg2 is the sub-command relating to the command
- */
- void
- help(const std::string &msg1, const std::string &msg2);
+ * Scrolls the chat window
+ *
+ * @param amount direction and amount to scroll. Negative numbers scroll
+ * up, positive numbers scroll down. The absolute amount indicates the
+ * amount of 1/8ths of chat window real estate that should be scrolled.
+ */
+ 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
+ * @param msg2 is the sub-command relating to the command
+ */
+ 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);
-
- /** One item in the chat log */
- struct CHATLOG
- {
- std::string nick;
- std::string text;
- int own;
- };
-
- /** Constructs failed messages for actions */
- std::string const_msg(CHATSKILL);
-
- gcn::TextField *mChatInput; /**< Input box for typing chat messages */
- BrowserBox *mTextOutput; /**< Text box for displaying chat history */
- ScrollArea *mScrollArea; /**< Scroll area around text output */
-
- typedef std::list<std::string> History;
- typedef History::iterator HistoryIterator;
- History mHistory; /**< Command history */
- HistoryIterator mCurHist; /**< History iterator */
-};
+ Network *mNetwork;
+ bool mTmpVisible;
+
+ /** One item in the chat log */
+ struct CHATLOG
+ {
+ std::string nick;
+ std::string text;
+ int own;
+ };
+
+ /** Constructs failed messages for actions */
+ std::string const_msg(CHATSKILL);
+
+ gcn::TextField *mChatInput; /**< Input box for typing chat messages */
+ BrowserBox *mTextOutput; /**< Text box for displaying chat history */
+ ScrollArea *mScrollArea; /**< Scroll area around text output */
+
+ 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 e04dfa6e..44e22956 100644
--- a/src/gui/chatinput.h
+++ b/src/gui/chatinput.h
@@ -22,9 +22,11 @@
#ifndef _TMW_CHATINPUT_H
#define _TMW_CHATINPUT_H
+#include <guichan/focuslistener.hpp>
+
#include "textfield.h"
-#include <guichan/focuslistener.hpp>
+#include "../guichanfwd.h"
/**
* The chat input hides when it loses focus. It is also invisible by default.
diff --git a/src/gui/checkbox.h b/src/gui/checkbox.h
index 839ca97e..f6d8f2e5 100644
--- a/src/gui/checkbox.h
+++ b/src/gui/checkbox.h
@@ -26,6 +26,8 @@
#include <guichan/widgets/checkbox.hpp>
+#include "../guichanfwd.h"
+
class Image;
/**
diff --git a/src/gui/colour.cpp b/src/gui/colour.cpp
new file mode 100644
index 00000000..4c3782a4
--- /dev/null
+++ b/src/gui/colour.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <cstdio>
+
+#include "colour.h"
+
+#include "../configuration.h"
+
+Colour::Colour()
+{
+ addColour('C', 0x000000, "Chat");
+ addColour('G', 0xff0000, "GM");
+ addColour('Y', 0x1fa052, "Player");
+ addColour('W', 0x0000ff, "Whisper");
+ addColour('I', 0xf1dc27, "Is");
+ addColour('P', 0xff00d8, "Party");
+ addColour('S', 0x8415e2, "Server");
+ addColour('L', 0x919191, "Logger");
+ addColour('<', 0xe50d0d, "Hyperlink");
+ commit();
+}
+
+Colour::~Colour()
+{
+ for (ColVector::iterator col = mColVector.begin(),
+ colEnd = mColVector.end();
+ col != colEnd;
+ ++col)
+ {
+ char buffer[20];
+ std::sprintf(buffer, "0x%06x", col->rgb);
+ config.setValue("Colour" + col->text, buffer);
+ }
+}
+
+void Colour::setColour(const char c, const int rgb)
+{
+ for (ColVector::iterator col = mColVector.begin(),
+ colEnd = mColVector.end();
+ col != colEnd;
+ ++col)
+ {
+ if (col->ch == c)
+ {
+ col->rgb = rgb;
+ return;
+ }
+ }
+}
+
+int Colour::getColour(const char c, bool &valid) const
+{
+ for (ColVector::const_iterator col = mColVector.begin(),
+ colEnd = mColVector.end();
+ col != colEnd;
+ ++col)
+ {
+ if (col->ch == c)
+ {
+ valid = true;
+ return col->rgb;
+ }
+ }
+ valid = false;
+ return 0x000000;
+}
+
+std::string Colour::getElementAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return mColVector[i].text;
+}
+
+void Colour::addColour(const char c, const int rgb, const std::string &text)
+{
+ int trueRgb = config.getValue("Colour" + text, rgb);
+ mColVector.push_back(ColourElem(c, trueRgb, text));
+}
+
+int Colour::getColourAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return 0;
+ }
+ return mColVector[i].rgb;
+}
+
+void Colour::setColourAt(int i, int rgb)
+{
+ if (i >= 0 && i < getNumberOfElements())
+ {
+ mColVector[i].rgb = rgb;
+ }
+}
+
+void Colour::commit()
+{
+ for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
+ i != iEnd;
+ ++i)
+ {
+ i->committedRgb = i->rgb;
+ }
+}
+
+void Colour::rollback()
+{
+ for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end();
+ i != iEnd;
+ ++i)
+ {
+ i->rgb = i->committedRgb;
+ }
+}
diff --git a/src/gui/colour.h b/src/gui/colour.h
new file mode 100644
index 00000000..1e8ba3db
--- /dev/null
+++ b/src/gui/colour.h
@@ -0,0 +1,133 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef _COLOUR_H
+#define _COLOUR_H
+
+#include <cstdio>
+#include <string>
+#include <vector>
+
+#include <guichan/listmodel.hpp>
+
+#include "../guichanfwd.h"
+
+class Colour : public gcn::ListModel
+{
+ public:
+ /**
+ * Constructor
+ */
+ Colour();
+
+ /**
+ * Destructor
+ */
+ ~Colour();
+
+ /**
+ * Define the colour replacement for a character
+ *
+ * @param c charater to be replaced
+ * @param rgb colour to replace character
+ */
+ void setColour(const char c, const int rgb);
+
+ /**
+ * Define the colour replacement for a character
+ *
+ * @param c character to be replaced
+ * @param r red component
+ * @param g green component
+ * @param b blue component
+ */
+ void setColour(const char c, const int r, const int g, const int b)
+ {
+ setColour(c, (r << 16) | (g << 8) | b);
+ }
+
+ /**
+ * Return the colour associated with a character, if exists
+ *
+ * @param c character requested
+ * @param valid indicate whether character is known
+ */
+ int getColour(const char c, bool &valid) const;
+
+ /**
+ * Return the number of colours known
+ */
+ int getNumberOfElements() {return mColVector.size(); }
+
+ /**
+ * Return the name of the ith colour
+ *
+ * @param i index of colour interested in
+ */
+ std::string getElementAt(int i);
+
+ /**
+ * Get the colour for the element at index i in the current colour
+ * model
+ */
+ int getColourAt(int i);
+
+ /**
+ * Set the colour for the element at index i
+ */
+ void setColourAt(int i, int rgb);
+
+ /**
+ * Commit the colours
+ */
+ void commit();
+
+ /**
+ * Rollback the colours
+ */
+ void rollback();
+
+ private:
+ struct ColourElem
+ {
+ ColourElem(const char c, const int rgb, const std::string &text) :
+ ch(c), rgb(rgb), text(text) {}
+ char ch;
+ int rgb;
+ int committedRgb;
+ std::string text;
+ };
+ typedef std::vector<ColourElem> ColVector;
+ ColVector mColVector;
+
+ /**
+ * Initialise colour
+ *
+ * @param c character that needs initialising
+ * @param rgb default colour if not found in config
+ * @param text identifier of colour
+ */
+ void addColour(const char c, const int rgb, const std::string &text);
+};
+
+extern Colour *textColour;
+
+#endif
diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp
index 9ef94f62..732f5769 100644
--- a/src/gui/confirm_dialog.cpp
+++ b/src/gui/confirm_dialog.cpp
@@ -19,39 +19,59 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "confirm_dialog.h"
-
-#include <guichan/widgets/label.hpp>
-
-#include "button.h"
+#include <guichan/font.hpp>
+#include "confirm_dialog.h"
ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg,
Window *parent):
Window(title, true, parent)
{
- gcn::Label *textLabel = new gcn::Label(msg);
+ mTextBox = new TextBox();
+ mTextBox->setEditable(false);
+ mTextBox->setOpaque(false);
+
+ mTextArea = new ScrollArea(mTextBox);
gcn::Button *yesButton = new Button("Yes", "yes", this);
gcn::Button *noButton = new Button("No", "no", this);
- int w = textLabel->getWidth() + 20;
+ mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextArea->setOpaque(false);
+
+ mTextBox->setMinWidth(260);
+ mTextBox->setTextWrapped(msg);
+
+ int numRows = mTextBox->getNumberOfRows();
+ int width = getFont()->getWidth(title);
int inWidth = yesButton->getWidth() + noButton->getWidth() + 5;
- int h = textLabel->getHeight() + 25 + yesButton->getHeight();
- if (w < inWidth + 10) {
- w = inWidth + 10;
+ if (numRows > 1)
+ {
+ // 15 == height of each line of text (based on font heights)
+ // 14 == row top + bottom graphic pixel heights
+ setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + noButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5,
+ 3 + (numRows * 14)));
+ }
+ else
+ {
+ if (width < getFont()->getWidth(msg))
+ width = getFont()->getWidth(msg);
+ if (width < inWidth)
+ width = inWidth;
+ setContentSize(width + 15, 30 + noButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17));
}
- setContentSize(w, h);
- textLabel->setPosition(10, 10);
yesButton->setPosition(
- (w - inWidth) / 2,
- h - 5 - noButton->getHeight());
+ (mTextBox->getMinWidth() - inWidth) / 2,
+ (numRows * 14) + noButton->getHeight() - 8);
noButton->setPosition(
yesButton->getX() + yesButton->getWidth() + 5,
- h - 5 - noButton->getHeight());
+ (numRows * 14) + noButton->getHeight() - 8);
- add(textLabel);
+ add(mTextArea);
add(yesButton);
add(noButton);
@@ -63,6 +83,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 c9bfca02..109dcea0 100644
--- a/src/gui/confirm_dialog.h
+++ b/src/gui/confirm_dialog.h
@@ -24,8 +24,12 @@
#include <guichan/actionlistener.hpp>
+#include "button.h"
+#include "scrollarea.h"
+#include "textbox.h"
#include "window.h"
+#include "../guichanfwd.h"
/**
* An option dialog.
@@ -42,10 +46,17 @@ class ConfirmDialog : public Window, public gcn::ActionListener {
ConfirmDialog(const std::string &title, const std::string &msg,
Window *parent = NULL);
+ unsigned int getNumRows();
+
/**
* Called when receiving actions from the widgets.
*/
void action(const gcn::ActionEvent &event);
+
+ private:
+ TextBox *mTextBox;
+ ScrollArea *mTextArea;
+ gcn::Button *okButton;
};
#endif
diff --git a/src/gui/connection.cpp b/src/gui/connection.cpp
index 8ad3b436..1204b203 100644
--- a/src/gui/connection.cpp
+++ b/src/gui/connection.cpp
@@ -19,13 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "connection.h"
-
#include <guichan/actionlistener.hpp>
#include <guichan/widgets/label.hpp>
#include "button.h"
+#include "connection.h"
#include "progressbar.h"
#include "../main.h"
diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp
index f6e9414e..7fc63096 100644
--- a/src/gui/debugwindow.cpp
+++ b/src/gui/debugwindow.cpp
@@ -19,18 +19,17 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "debugwindow.h"
-
#include <SDL_mouse.h>
#include <guichan/widgets/label.hpp>
#include "button.h"
+#include "debugwindow.h"
#include "gui.h"
#include "viewport.h"
-#include "../game.h"
#include "../engine.h"
+#include "../game.h"
#include "../particle.h"
#include "../map.h"
diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp
index e0246787..7e1ef315 100644
--- a/src/gui/equipmentwindow.cpp
+++ b/src/gui/equipmentwindow.cpp
@@ -25,7 +25,9 @@
#include "../inventory.h"
#include "../localplayer.h"
#include "../graphics.h"
+#include "../inventory.h"
#include "../item.h"
+#include "../localplayer.h"
#include "../log.h"
#include "../resources/iteminfo.h"
@@ -40,7 +42,7 @@ EquipmentWindow::EquipmentWindow(Equipment *equipment):
setCloseButton(true);
setDefaultSize(5, 230, 200, 120);
loadWindowState();
- mInventory = player_node->getInventory();
+ mInventory = player_node->getInventory();
}
EquipmentWindow::~EquipmentWindow()
@@ -75,14 +77,15 @@ void EquipmentWindow::draw(gcn::Graphics *graphics)
graphics->drawRectangle(gcn::Rectangle(160, 25, 32, 32));
- if (!(item = mInventory->getItem(mEquipment->getArrows())))
+ if (!(item = mInventory->getItem(mEquipment->getArrows())))
return;
image = item->getImage();
+
if (image)
{
static_cast<Graphics*>(graphics)->drawImage(image, 160, 25);
}
graphics->drawText(toString(item->getQuantity()), 170, 62,
- gcn::Graphics::CENTER);
+ gcn::Graphics::CENTER);
}
diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h
index 42aa7701..b669f5b1 100644
--- a/src/gui/equipmentwindow.h
+++ b/src/gui/equipmentwindow.h
@@ -25,6 +25,9 @@
#include "window.h"
#include "../inventory.h"
+#include "../guichanfwd.h"
+#include "../inventory.h"
+
class Equipment;
/**
diff --git a/src/gui/focushandler.cpp b/src/gui/focushandler.cpp
index 1bda568e..f9ea8b7d 100644
--- a/src/gui/focushandler.cpp
+++ b/src/gui/focushandler.cpp
@@ -21,7 +21,6 @@
#include "focushandler.h"
-
void FocusHandler::requestModalFocus(gcn::Widget *widget)
{
/* If there is another widget with modal focus, remove its modal focus
diff --git a/src/gui/gccontainer.h b/src/gui/gccontainer.h
index cc7c9336..2af7f6ad 100644
--- a/src/gui/gccontainer.h
+++ b/src/gui/gccontainer.h
@@ -26,6 +26,8 @@
#include <guichan/widgets/container.hpp>
+#include "../guichanfwd.h"
+
/**
* A garbage collecting container. Childs added to this container are
* automatically deleted when the container is deleted.
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index 96415298..70f82d9d 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -19,8 +19,6 @@
* 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>
@@ -29,6 +27,7 @@
#include <guichan/sdl/sdlinput.hpp>
#include "focushandler.h"
+#include "gui.h"
#include "viewport.h"
#include "window.h"
#include "windowcontainer.h"
@@ -40,8 +39,8 @@
#include "../resources/image.h"
#include "../resources/imageset.h"
-#include "../resources/resourcemanager.h"
#include "../resources/imageloader.h"
+#include "../resources/resourcemanager.h"
// Guichan stuff
Gui *gui;
@@ -55,6 +54,13 @@ gcn::Font *hitYellowFont;
// Font used to display speech and player names
gcn::Font *speechFont;
+// Font for displaying NPC names
+gcn::Font *npcNameFont;
+// Font for displaying mob names
+gcn::Font *mobNameFont;
+// Font for displaying GM names
+gcn::Font *gmNameFont;
+
class GuiConfigListener : public ConfigListener
{
public:
@@ -139,14 +145,54 @@ Gui::Gui(Graphics *graphics):
logger->error("Unable to load rpgfont_wider.png!");
}
+ // Set npc name font
+ try {
+ npcNameFont = new gcn::ImageFont("graphics/gui/rpgfont_wider-blue.png",
+ " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789.,!?-+/():;%&`'*#=[]\"<>{}^~|_@$\\"
+ "áÁéÉíÍóÓúÚç륣¢¡¿àãõêñÑöüäÖÜÄßøèÈåÅ"
+ );
+ }
+ catch (gcn::Exception e)
+ {
+ logger->error("Unable to load rpgfont_wider-blue.png!");
+ }
+
+ // Set monster name font
+ try {
+ mobNameFont = new gcn::ImageFont("graphics/gui/rpgfont_wider-orange.png",
+ " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789.,!?-+/():;%&`'*#=[]\"<>{}^~|_@$\\"
+ "áÁéÉíÍóÓúÚç륣¢¡¿àãõêñÑöüäÖÜÄßøèÈåÅ"
+ );
+ }
+ catch (gcn::Exception e)
+ {
+ logger->error("Unable to load rpgfont_wider-orange.png!");
+ }
+
+ // Set GM name font
+ try {
+ gmNameFont = new gcn::ImageFont("graphics/gui/rpgfont_wider-green.png",
+ " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789.,!?-+/():;%&`'*#=[]\"<>{}^~|_@$\\"
+ "áÁéÉíÍóÓúÚç륣¢¡¿àãõêñÑöüäÖÜÄßøèÈåÅ"
+ );
+ }
+ catch (gcn::Exception e)
+ {
+ logger->error("Unable to load rpgfont_wider-green.png!");
+ }
+
+
gcn::Widget::setGlobalFont(mGuiFont);
// Load hits' colourful fonts
try {
hitRedFont = new gcn::ImageFont("graphics/gui/hits_red.png",
- "0123456789");
+ "0123456789crit! ");
hitBlueFont = new gcn::ImageFont("graphics/gui/hits_blue.png",
- "0123456789");
+ "0123456789crit! ");
hitYellowFont = new gcn::ImageFont("graphics/gui/hits_yellow.png",
"0123456789misxp ");
}
diff --git a/src/gui/gui.h b/src/gui/gui.h
index 15d5d99c..f56b1dbf 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 Viewport;
@@ -128,4 +128,12 @@ extern gcn::Font *hitYellowFont;
*/
extern gcn::Font *speechFont;
+/**
+ * being name fonts
+ */
+extern gcn::Font *npcNameFont;
+extern gcn::Font *mobNameFont;
+extern gcn::Font *gmNameFont;
+
+
#endif
diff --git a/src/gui/hbox.h b/src/gui/hbox.h
index 4b241383..da70a53c 100644
--- a/src/gui/hbox.h
+++ b/src/gui/hbox.h
@@ -24,6 +24,8 @@
#include "box.h"
+#include "../guichanfwd.h"
+
class HBox : public Box
{
public:
diff --git a/src/gui/help.cpp b/src/gui/help.cpp
index 290679b9..19413a08 100644
--- a/src/gui/help.cpp
+++ b/src/gui/help.cpp
@@ -19,10 +19,9 @@
* 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 "../resources/resourcemanager.h"
diff --git a/src/gui/help.h b/src/gui/help.h
index 053df723..bd200ccf 100644
--- a/src/gui/help.h
+++ b/src/gui/help.h
@@ -24,8 +24,8 @@
#include <guichan/actionlistener.hpp>
-#include "window.h"
#include "linkhandler.h"
+#include "window.h"
#include "../guichanfwd.h"
diff --git a/src/gui/inttextbox.cpp b/src/gui/inttextbox.cpp
index 4825fbf5..858a3fcb 100644
--- a/src/gui/inttextbox.cpp
+++ b/src/gui/inttextbox.cpp
@@ -19,10 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "inttextbox.h"
-
#include <guichan/key.hpp>
+#include "inttextbox.h"
+
#include "../utils/tostring.h"
IntTextBox::IntTextBox(int i):
diff --git a/src/gui/inttextbox.h b/src/gui/inttextbox.h
index 8fc8e404..922ef4c5 100644
--- a/src/gui/inttextbox.h
+++ b/src/gui/inttextbox.h
@@ -24,6 +24,8 @@
#include "textbox.h"
+#include "../guichanfwd.h"
+
/**
* TextBox which only accepts numbers as input.
*/
diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp
index f38c118e..424fca59 100644
--- a/src/gui/inventorywindow.cpp
+++ b/src/gui/inventorywindow.cpp
@@ -19,15 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "inventorywindow.h"
-
#include <string>
#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 "scrollarea.h"
@@ -48,29 +46,38 @@ InventoryWindow::InventoryWindow():
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, 172);
mUseButton = new Button("Use", "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:");
+ mTotalWeight = toString(player_node->mTotalWeight);
+ mMaxWeight = toString(player_node->mMaxWeight);
+
+ mItemName = "Name:";
+ mItemNameLabel = new TextBox();
+ mItemDescription = "Description:";
+ mItemDescriptionLabel = new TextBox();
+ mItemEffect = "Effect:";
+ mItemEffectLabel = new TextBox();
+ mWeight = "Total Weight: " + mTotalWeight + " g - " +
+ "Maximum Weight: " + mMaxWeight + " g";
+ mWeightLabel = new TextBox();
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);
+ mSlots = "Slots: " +
+ toString(player_node->getInventory()->getNumberOfSlotsUsed()) +
+ "/" + toString(player_node->getInventory()->getInventorySize());
+ mSlotsLabel = new TextBox();
+ mItemEffectLabel = new TextBox();
+
+ draw();
add(mUseButton);
add(mDropButton);
@@ -79,7 +86,7 @@ InventoryWindow::InventoryWindow():
add(mItemDescriptionLabel);
add(mItemEffectLabel);
add(mWeightLabel);
- add(mInvenSlotLabel);
+ add(mSlotsLabel);
mUseButton->setSize(60, mUseButton->getHeight());
@@ -94,16 +101,22 @@ void InventoryWindow::logic()
// redesign of InventoryWindow and ItemContainer probably.
updateButtons();
- // Update weight information
- mWeightLabel->setCaption(
- "Weight: " + toString(player_node->mTotalWeight) +
- "/" + toString(player_node->mMaxWeight));
-
- // Update number of items in inventory
- mInvenSlotLabel->setCaption(
- "Slots used: "
- + toString(player_node->getInventory()->getNumberOfSlotsUsed())
- + "/" + toString(player_node->getInventory()->getInventorySize()));
+ if ((mMaxWeight != toString(player_node->mMaxWeight)) ||
+ mTotalWeight != toString(player_node->mTotalWeight))
+ {
+ mTotalWeight = toString(player_node->mTotalWeight);
+ mMaxWeight = toString(player_node->mMaxWeight);
+
+ // Adjust widgets
+ mWeight = "Total Weight: " + mTotalWeight + " g - " +
+ "Maximum Weight: " + mMaxWeight + " g";
+
+ mSlots = "Slots: " +
+ toString(player_node->getInventory()->getNumberOfSlotsUsed()) +
+ "/" + toString(player_node->getInventory()->getInventorySize());
+
+ draw();
+ }
}
void InventoryWindow::action(const gcn::ActionEvent &event)
@@ -145,21 +158,25 @@ void InventoryWindow::valueChanged(const gcn::SelectionEvent &event)
// Update name, effect and description
if (!item)
{
- mItemNameLabel->setCaption("Name:");
- mItemEffectLabel->setCaption("Effect:");
- mItemDescriptionLabel->setCaption("Description:");
+ mItemName = "Name:";
+ mItemNameLabel->setTextWrapped(mItemName);
+ mItemEffect = "Effect:";
+ mItemEffectLabel->setTextWrapped(mItemEffect);
+ mItemDescription = "Description:";
+ mItemDescriptionLabel->setTextWrapped(mItemDescription);
}
else
{
const ItemInfo& itemInfo = item->getInfo();
- std::string SomeText;
- SomeText = "Name: " + itemInfo.getName();
- mItemNameLabel->setCaption(SomeText);
- SomeText = "Effect: " + itemInfo.getEffect();
- mItemEffectLabel->setCaption(SomeText);
- SomeText = "Description: " + itemInfo.getDescription();
- mItemDescriptionLabel->setCaption(SomeText);
+ mItemName = "Name: " + itemInfo.getName();
+ mItemNameLabel->setTextWrapped(mItemName);
+ mItemEffect = "Effect: " + itemInfo.getEffect();
+ mItemEffectLabel->setTextWrapped(mItemEffect);
+ mItemDescription = "Description: " + itemInfo.getDescription();
+ mItemDescriptionLabel->setTextWrapped(mItemDescription);
}
+
+ draw();
}
void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
@@ -181,37 +198,60 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event)
}
}
-void InventoryWindow::widgetResized(const gcn::Event &event)
+void InventoryWindow::draw()
{
- Window::widgetResized(event);
-
const gcn::Rectangle &area = getChildrenArea();
const int width = area.width;
const int height = area.height;
- // Adjust widgets
+ // Update weight information
+ mWeightLabel->setTextWrapped(mWeight);
+ mWeightLabel->setMinWidth(width - 16);
+
mUseButton->setPosition(8, height - 8 - mUseButton->getHeight());
mDropButton->setPosition(8 + mUseButton->getWidth() + 5,
mUseButton->getY());
+ mItemNameLabel->setMinWidth(width - 16);
+ mItemNameLabel->setTextWrapped(mItemName);
mItemNameLabel->setDimension(gcn::Rectangle(8,
- mUseButton->getY() - 5 - mItemNameLabel->getHeight(),
+ mUseButton->getY() - 5 - (mItemNameLabel->getNumberOfRows()*15),
width - 16,
- mItemNameLabel->getHeight()));
+ (mItemNameLabel->getNumberOfRows()*15)));
+ mItemEffectLabel->setMinWidth(width - 16);
+ mItemEffectLabel->setTextWrapped(mItemEffect);
mItemEffectLabel->setDimension(gcn::Rectangle(8,
- mItemNameLabel->getY() - 5 - mItemEffectLabel->getHeight(),
+ mItemNameLabel->getY() - 5 - (mItemEffectLabel->getNumberOfRows()*15),
width - 16,
- mItemEffectLabel->getHeight()));
+ (mItemEffectLabel->getNumberOfRows()*15)));
+ mItemDescriptionLabel->setMinWidth(width - 16);
+ mItemDescriptionLabel->setTextWrapped(mItemDescription);
mItemDescriptionLabel->setDimension(gcn::Rectangle(8,
- mItemEffectLabel->getY() - 5 - mItemDescriptionLabel->getHeight(),
+ mItemEffectLabel->getY() - 5 - (mItemDescriptionLabel->getNumberOfRows()*15),
width - 16,
- mItemDescriptionLabel->getHeight()));
+ (mItemDescriptionLabel->getNumberOfRows()*15)));
+ mSlotsLabel->setMinWidth(width - 16);
+ mSlotsLabel->setTextWrapped(mSlots);
+ mSlotsLabel->setDimension(gcn::Rectangle(8,
+ mItemDescriptionLabel->getY() - 5 - (mSlotsLabel->getNumberOfRows()*15),
+ width - 16,
+ (mSlotsLabel->getNumberOfRows()*15)));
mInvenScroll->setSize(width - 16,
- mItemDescriptionLabel->getY() - mWeightLabel->getHeight() - 18);
+ mSlotsLabel->getY() - (mWeightLabel->getNumberOfRows()*15) - 18);
+ mInvenScroll->setPosition(8, (mWeightLabel->getNumberOfRows()*15) + 10);
+
+ setMinHeight(130 + (mSlotsLabel->getNumberOfRows()*15) +
+ (mWeightLabel->getNumberOfRows()*15) +
+ (mItemDescriptionLabel->getNumberOfRows()*15) +
+ (mItemEffectLabel->getNumberOfRows()*15) +
+ (mItemNameLabel->getNumberOfRows()*15));
+}
- mWeightLabel->setWidth(width - 16);
- mInvenSlotLabel->setWidth(width - 16);
+void InventoryWindow::widgetResized(const gcn::Event &event)
+{
+ Window::widgetResized(event);
+ draw();
}
void InventoryWindow::updateButtons()
diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h
index b1e3ede3..2e589471 100644
--- a/src/gui/inventorywindow.h
+++ b/src/gui/inventorywindow.h
@@ -25,6 +25,7 @@
#include <guichan/actionlistener.hpp>
#include <guichan/selectionlistener.hpp>
+#include "textbox.h"
#include "window.h"
#include "../guichanfwd.h"
@@ -69,6 +70,11 @@ class InventoryWindow : public Window, gcn::ActionListener,
void mouseClicked(gcn::MouseEvent &event);
/**
+ * Updates window drawing.
+ */
+ void draw();
+
+ /**
* Called whenever the widget changes size.
*/
void widgetResized(const gcn::Event &event);
@@ -78,13 +84,20 @@ class InventoryWindow : public Window, gcn::ActionListener,
ItemContainer *mItems;
+ std::string mItemName;
+ std::string mItemDescription;
+ std::string mItemEffect;
+ std::string mWeight;
+ std::string mTotalWeight;
+ std::string mMaxWeight;
+ std::string mSlots;
gcn::Button *mUseButton, *mDropButton;
gcn::ScrollArea *mInvenScroll;
- gcn::Label *mItemNameLabel;
- gcn::Label *mItemDescriptionLabel;
- gcn::Label *mItemEffectLabel;
- gcn::Label *mWeightLabel;
- gcn::Label *mInvenSlotLabel;
+ TextBox *mItemNameLabel;
+ TextBox *mItemDescriptionLabel;
+ TextBox *mItemEffectLabel;
+ TextBox *mWeightLabel;
+ TextBox *mSlotsLabel;
};
extern InventoryWindow *inventoryWindow;
diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp
index 2e8941e8..4ce8ac6c 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 "inttextbox.h"
+#include "item_amount.h"
#include "slider.h"
#include "trade.h"
diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp
index 9115b1fb..9e17f3da 100644
--- a/src/gui/itemcontainer.cpp
+++ b/src/gui/itemcontainer.cpp
@@ -28,6 +28,7 @@
#include "../inventory.h"
#include "../item.h"
#include "../itemshortcut.h"
+#include "../localplayer.h"
#include "../log.h"
#include "../resources/image.h"
@@ -41,10 +42,11 @@ 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)
{
ResourceManager *resman = ResourceManager::getInstance();
@@ -86,10 +88,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);
@@ -178,18 +181,19 @@ 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;
-
if (mSelectedItemIndex != newSelectedItemIndex)
{
mSelectedItemIndex = newSelectedItemIndex;
@@ -224,7 +228,7 @@ void ItemContainer::mousePressed(gcn::MouseEvent &event)
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);
diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h
index 34545df8..8927b001 100644
--- a/src/gui/itemcontainer.h
+++ b/src/gui/itemcontainer.h
@@ -22,11 +22,13 @@
#ifndef _TMW_ITEMCONTAINER_H__
#define _TMW_ITEMCONTAINER_H__
+#include <list>
+
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
#include <guichan/widgetlistener.hpp>
-#include <list>
+#include "../guichanfwd.h"
class Image;
class Inventory;
@@ -41,14 +43,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.
@@ -105,6 +108,7 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener,
private:
/**
+
* Sets the currently selected item. Invalid (e.g., negative) indices set `no item'.
*/
void setSelectedItemIndex(int index);
@@ -127,9 +131,10 @@ class ItemContainer : public gcn::Widget, public gcn::MouseListener,
Inventory *mInventory;
Image *mSelImg;
int mSelectedItemIndex;
- int mLastSelectedItemId; // last selected item ID. If we lose the item, find again by ID.
+ int mLastSelectedItemId; // last selected item ID. If we lose the item, find again by ID.
int mMaxItems;
+ int mOffset;
std::list<gcn::SelectionListener*> mListeners;
diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp
new file mode 100644
index 00000000..055cbe44
--- /dev/null
+++ b/src/gui/itempopup.cpp
@@ -0,0 +1,113 @@
+/*
+ * The Legend of Mazzeroth
+ * Copyright (C) 2008, The Legend of Mazzeroth Development Team
+ *
+ * This file is part of The Legend of Mazzeroth based on original code
+ * from The Mana World.
+ *
+ * The Legend of Mazzeroth is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Legend of Mazzeroth is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Legend of Mazzeroth; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/widgets/label.hpp>
+
+#include "gui.h"
+#include "itempopup.h"
+
+#include "widgets/layout.h"
+
+#include "../resources/image.h"
+#include "../resources/iteminfo.h"
+#include "../resources/resourcemanager.h"
+#include "../utils/gettext.h"
+#include "../utils/strprintf.h"
+
+ItemPopup::ItemPopup()
+{
+
+ setResizable(false);
+ setTitleBarHeight(0);
+
+ // Item Name
+ mItemName = new gcn::Label("Label");
+ mItemName->setFont(gui->getFont());
+ mItemName->setPosition(2, 2);
+ mItemName->setWidth(getWidth() - 4);
+
+ // 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, 14));
+ mItemDescScroll->setOpaque(false);
+ mItemDescScroll->setPosition(2, 15);
+
+ // 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, 14));
+ mItemEffectScroll->setOpaque(false);
+ mItemEffectScroll->setPosition(2, 35);
+
+ add(mItemName);
+ add(mItemDescScroll);
+ add(mItemEffectScroll);
+
+ setLocationRelativeTo(getParent());
+
+ // LEEOR / TODO: This causes an exception error.
+ //moveToBottom(getParent());
+
+ mItemDesc->setTextWrapped( "" );
+ mItemEffect->setTextWrapped( "" );
+}
+
+void ItemPopup::setItem(Item *item)
+{
+
+ ItemInfo const *info = item ? &item->getInfo() : NULL;
+
+ mItemName->setCaption(info->getName());
+ mItemDesc->setTextWrapped( info->getDescription() );
+ mItemEffect->setTextWrapped( info->getEffect() );
+
+ int numRowsDesc = mItemDesc->getNumberOfRows();
+ int numRowsEffect = mItemEffect->getNumberOfRows();
+
+ if(info->getEffect() == "")
+ {
+ setContentSize(200, (numRowsDesc * 14) + 30);
+ } else {
+ setContentSize(200, (numRowsDesc * 14) + (numRowsEffect*14) + 30);
+ }
+
+ mItemDescScroll->setDimension(gcn::Rectangle(2, 0, 196, numRowsDesc * 14));
+
+ mItemEffectScroll->setDimension(gcn::Rectangle(2, 0, 196, numRowsEffect * 14));
+
+ mItemDescScroll->setPosition(2, 20);
+ mItemEffectScroll->setPosition(2, (numRowsDesc * 15) + 25);
+}
+
+unsigned int ItemPopup::getNumRows()
+{
+ return mItemDesc->getNumberOfRows(), mItemEffect->getNumberOfRows();
+}
diff --git a/src/gui/itempopup.h b/src/gui/itempopup.h
new file mode 100644
index 00000000..0082ec2c
--- /dev/null
+++ b/src/gui/itempopup.h
@@ -0,0 +1,51 @@
+/*
+*
+ * The Legend of Mazzeroth
+ * Copyright (C) 2008, The Legend of Mazzeroth Development Team
+ *
+ * This file is part of The Legend of Mazzeroth based on original code
+ * from The Mana World.
+ *
+ * The Legend of Mazzeroth is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Legend of Mazzeroth is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Legend of Mazzeroth; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _LOM_ITEMPOPUP_H__
+#define _LOM_ITEMPOPUP_H__
+
+#include "scrollarea.h"
+#include "textbox.h"
+#include "window.h"
+
+#include "../item.h"
+
+class ItemPopup : public Window
+ {
+ public:
+
+ ItemPopup();
+
+ void setItem(Item *item);
+ unsigned int getNumRows();
+
+ private:
+ gcn::Label *mItemName;
+ TextBox *mItemDesc;
+ TextBox *mItemEffect;
+ ScrollArea *mItemDescScroll;
+ ScrollArea *mItemEffectScroll;
+
+ };
+
+#endif
diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp
index 2ea5d584..de5e1956 100644
--- a/src/gui/itemshortcutcontainer.cpp
+++ b/src/gui/itemshortcutcontainer.cpp
@@ -21,12 +21,12 @@
#include "itemshortcutcontainer.h"
-#include "../localplayer.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"
@@ -96,6 +96,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 =
diff --git a/src/gui/itemshortcutcontainer.h b/src/gui/itemshortcutcontainer.h
index 76ca870c..a8daca0b 100644
--- a/src/gui/itemshortcutcontainer.h
+++ b/src/gui/itemshortcutcontainer.h
@@ -26,6 +26,8 @@
#include <guichan/widget.hpp>
#include <guichan/widgetlistener.hpp>
+#include "../guichanfwd.h"
+
class Image;
class Item;
diff --git a/src/gui/itemshortcutwindow.cpp b/src/gui/itemshortcutwindow.cpp
index e7364411..5a4dfacd 100644
--- a/src/gui/itemshortcutwindow.cpp
+++ b/src/gui/itemshortcutwindow.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "itemshortcutwindow.h"
-
#include "itemshortcutcontainer.h"
+#include "itemshortcutwindow.h"
#include "scrollarea.h"
static const int SCROLL_PADDING = 0;
diff --git a/src/gui/itemshortcutwindow.h b/src/gui/itemshortcutwindow.h
index 017df5ec..587f15c8 100644
--- a/src/gui/itemshortcutwindow.h
+++ b/src/gui/itemshortcutwindow.h
@@ -24,6 +24,8 @@
#include "window.h"
+#include "../guichanfwd.h"
+
class ItemShortcutContainer;
class ScrollArea;
diff --git a/src/gui/listbox.cpp b/src/gui/listbox.cpp
index 28bb82e9..4dca66a0 100644
--- a/src/gui/listbox.cpp
+++ b/src/gui/listbox.cpp
@@ -19,13 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "listbox.h"
-
#include <guichan/font.hpp>
#include <guichan/graphics.hpp>
#include <guichan/listmodel.hpp>
#include <guichan/mouseinput.hpp>
+#include "listbox.h"
+
ListBox::ListBox(gcn::ListModel *listModel):
gcn::ListBox(listModel)
{
diff --git a/src/gui/listbox.h b/src/gui/listbox.h
index 1d627b3b..30eb4c79 100644
--- a/src/gui/listbox.h
+++ b/src/gui/listbox.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/listbox.hpp>
+#include "../guichanfwd.h"
+
class SelectionListener;
/**
diff --git a/src/gui/login.cpp b/src/gui/login.cpp
index 06a5f9f0..fa47af32 100644
--- a/src/gui/login.cpp
+++ b/src/gui/login.cpp
@@ -19,80 +19,125 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "login.h"
-
#include <string>
+#include <vector>
#include <guichan/widgets/label.hpp>
-#include "../main.h"
-#include "../logindata.h"
-
#include "button.h"
#include "checkbox.h"
+#include "login.h"
#include "ok_dialog.h"
#include "passwordfield.h"
#include "textfield.h"
+#include "../main.h"
+#include "../logindata.h"
+#include "../configuration.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)
{
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("www.aethyra.org");
+ dfltServer.push_back("www.aethyra.org");
+ std::vector<std::string> dfltPort;
+ dfltPort.push_back("21001");
+ dfltPort.push_back("22001");
+ mServerList = new DropDownList("MostRecent00", dfltServer, dfltPort,
+ MAX_SERVER_LIST_SIZE);
+ mServerListBox = new gcn::ListBox(mServerList);
+ mServerScrollArea = new ScrollArea();
+
mUserField = new TextField(mLoginData->username);
mPassField = new PasswordField(mLoginData->password);
- mServerField = new TextField(mLoginData->hostname);
+ mServerField = new TextField(mServerList->getServerAt(0));
+ mPortField = new TextField(mServerList->getPortAt(0));
+ mServerDropDown = new DropDown(mServerList,
+ mServerScrollArea,
+ mServerListBox);
+
mKeepCheck = new CheckBox("Keep", mLoginData->remember);
mOkButton = new Button("OK", "ok", this);
mCancelButton = new Button("Cancel", "cancel", this);
mRegisterButton = new Button("Register", "register", this);
- const int width = 220;
- const int height = 100;
-
- setContentSize(width, height);
-
- userLabel->setPosition(5, 5);
- passLabel->setPosition(5, 14 + userLabel->getHeight());
- serverLabel->setPosition(
- 5, 23 + userLabel->getHeight() + passLabel->getHeight());
- mUserField->setPosition(65, 5);
- mPassField->setPosition(65, 14 + userLabel->getHeight());
- mServerField->setPosition(
- 65, 23 + userLabel->getHeight() + passLabel->getHeight());
- mUserField->setWidth(width - 70);
- mPassField->setWidth(width - 70);
- mServerField->setWidth(width - 70);
- mKeepCheck->setPosition(4, 77);
+ setContentSize(LOGIN_DIALOG_WIDTH, LOGIN_DIALOG_HEIGHT);
+
+ const int USER_TOP = 5;
+ userLabel->setPosition(5, USER_TOP);
+ mUserField->setPosition(65, USER_TOP);
+ mUserField->setWidth(FIELD_WIDTH);
+
+ const int PASS_TOP = 9 + USER_TOP + userLabel->getHeight();
+ passLabel->setPosition(5, PASS_TOP);
+ mPassField->setPosition(65, PASS_TOP);
+ mPassField->setWidth(FIELD_WIDTH);
+
+ const int SERVER_TOP = 9 + PASS_TOP + passLabel->getHeight();
+ serverLabel->setPosition(5, SERVER_TOP);
+ mServerField->setPosition(65, SERVER_TOP);
+ mServerField->setWidth(FIELD_WIDTH);
+
+ const int PORT_TOP = 9 + SERVER_TOP + serverLabel->getHeight();
+ portLabel->setPosition(5, PORT_TOP);
+ mPortField->setPosition(65, PORT_TOP);
+ mPortField->setWidth(FIELD_WIDTH);
+
+ const int DROP_DOWN_TOP = 9 + PORT_TOP + serverLabel->getHeight();
+ dropdownLabel->setPosition(5, DROP_DOWN_TOP);
+ mServerDropDown->setPosition(65, DROP_DOWN_TOP);
+ mServerDropDown->setWidth(FIELD_WIDTH);
+
+ const int REST_TOP = LOGIN_DIALOG_HEIGHT - mCancelButton->getHeight() - 5;
+
+ mKeepCheck->setPosition(4, REST_TOP);
mCancelButton->setPosition(
- width - mCancelButton->getWidth() - 5,
- height - mCancelButton->getHeight() - 5);
+ LOGIN_DIALOG_WIDTH - mCancelButton->getWidth() - 5, REST_TOP);
mOkButton->setPosition(
- mCancelButton->getX() - mOkButton->getWidth() - 5,
- height - mOkButton->getHeight() - 5);
+ mCancelButton->getX() - mOkButton->getWidth() - 5, REST_TOP);
mRegisterButton->setPosition(
- mKeepCheck->getX() + mKeepCheck->getWidth() + 10,
- height - mRegisterButton->getHeight() - 5);
+ mKeepCheck->getX() + mKeepCheck->getWidth() + 10, REST_TOP);
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);
add(userLabel);
add(passLabel);
add(serverLabel);
+ add(portLabel);
+ add(dropdownLabel);
add(mUserField);
add(mPassField);
add(mServerField);
+ add(mPortField);
+ add(mServerDropDown);
add(mKeepCheck);
add(mOkButton);
add(mCancelButton);
@@ -112,6 +157,9 @@ LoginDialog::LoginDialog(LoginData *loginData):
LoginDialog::~LoginDialog()
{
+ delete mServerList;
+ delete mServerListBox;
+ delete mServerScrollArea;
}
void
@@ -120,6 +168,7 @@ 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();
@@ -127,9 +176,15 @@ 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;
@@ -138,6 +193,14 @@ 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();
@@ -157,5 +220,147 @@ LoginDialog::canSubmit()
return !mUserField->getText().empty() &&
!mPassField->getText().empty() &&
!mServerField->getText().empty() &&
+ isUShort(mPortField->getText()) &&
state == LOGIN_STATE;
}
+
+bool
+LoginDialog::isUShort(const std::string &str)
+{
+ if (str == "")
+ {
+ return false;
+ }
+ unsigned long l = 0;
+ for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end();
+ strPtr != strEnd; ++strPtr)
+ {
+ if (*strPtr < '0' || *strPtr > '9')
+ {
+ return false;
+ }
+ l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative
+ if (l > 65535)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+unsigned short
+LoginDialog::getUShort(const std::string &str)
+{
+ unsigned long l = 0;
+ for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end();
+ strPtr != strEnd; ++strPtr)
+ {
+ l = l * 10 + (*strPtr - '0');
+ }
+ return static_cast<unsigned short>(l);
+}
+
+/**
+ * LoginDialog::DropDownList
+ */
+
+void
+LoginDialog::DropDownList::saveEntry(const std::string &server,
+ const std::string &port, int &saved)
+{
+ if (saved < MAX_SERVER_LIST_SIZE && server != "")
+ {
+ config.setValue(mConfigPrefix + "Server" + toString(saved), server);
+ config.setValue(mConfigPrefix + "Port" + toString(saved), port);
+ ++saved;
+ }
+}
+
+LoginDialog::DropDownList::DropDownList(std::string prefix,
+ std::vector<std::string> dflt,
+ std::vector<std::string> dfltPort,
+ int maxEntries) :
+ mConfigPrefix(prefix),
+ mMaxEntries(maxEntries)
+{
+ for (int i = 0; i < maxEntries; ++i)
+ {
+ std::string server = config.getValue(mConfigPrefix + "Server" +
+ toString(i), "");
+ if (server == "") // Just in case had original config entries
+ {
+ server = config.getValue(mConfigPrefix + "ServerList" +
+ toString(i), "");
+ }
+ std::string port = config.getValue(mConfigPrefix + "Port" +
+ toString(i), dfltPort.front());
+
+ if (server != "")
+ {
+ mServers.push_back(server);
+ mPorts.push_back(port);
+ }
+ }
+ if (mServers.size() == 0)
+ {
+ mServers.assign(dflt.begin(), dflt.end());
+ mPorts.assign(dfltPort.begin(), dfltPort.end());
+ }
+}
+
+void
+LoginDialog::DropDownList::save(const std::string &server,
+ const std::string &port)
+{
+ int position = 0;
+ saveEntry(server, port, position);
+ for (std::vector<std::string>::const_iterator sPtr = mServers.begin(),
+ sEnd = mServers.end(),
+ pPtr = mPorts.begin(),
+ pEnd = mPorts.end();
+ sPtr != sEnd && pPtr != pEnd;
+ ++sPtr, ++pPtr)
+ {
+ if (*sPtr != server || *pPtr != port)
+ {
+ saveEntry(*sPtr, *pPtr, position);
+ }
+ }
+}
+
+int
+LoginDialog::DropDownList::getNumberOfElements()
+{
+ return mServers.size();
+}
+
+std::string
+LoginDialog::DropDownList::getElementAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return getServerAt(i) + ":" + getPortAt(i);
+}
+
+std::string
+LoginDialog::DropDownList::getServerAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return mServers.at(i);
+}
+
+
+std::string
+LoginDialog::DropDownList::getPortAt(int i)
+{
+ if (i < 0 || i >= getNumberOfElements())
+ {
+ return "";
+ }
+ return mPorts.at(i);
+}
diff --git a/src/gui/login.h b/src/gui/login.h
index 4760817c..3b911424 100644
--- a/src/gui/login.h
+++ b/src/gui/login.h
@@ -23,10 +23,17 @@
#define _TMW_LOGIN_H
#include <iosfwd>
+#include <string>
+#include <vector>
+
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
+#include "scrollarea.h"
#include "window.h"
+
+#include "widgets/dropdown.h"
+
#include "../guichanfwd.h"
class LoginData;
@@ -70,15 +77,66 @@ class LoginDialog : public Window, public gcn::ActionListener,
bool
canSubmit();
+ /**
+ * Function to decide whether string is an unsigned short or not
+ *
+ * @param str the string to parse
+ *
+ * @return true is str is an unsigned short, false otherwise
+ */
+ static bool
+ isUShort(const std::string &str);
+
+ /**
+ * Converts string to an unsigned short (undefined if invalid)
+ *
+ * @param str the string to parse
+ *
+ * @return the value str represents
+ */
+ static unsigned short
+ getUShort(const std::string &str);
+
+ DropDown *mServerDropDown;
gcn::TextField *mUserField;
gcn::TextField *mPassField;
gcn::TextField *mServerField;
+ gcn::TextField *mPortField;
gcn::CheckBox *mKeepCheck;
gcn::Button *mOkButton;
gcn::Button *mCancelButton;
gcn::Button *mRegisterButton;
LoginData *mLoginData;
+
+ /**
+ * Helper class to keep a list of all the recent entries for the
+ * dropdown
+ */
+ class DropDownList : public gcn::ListModel
+ {
+ private:
+ std::vector<std::string> mServers;
+ std::vector<std::string> mPorts;
+ std::string mConfigPrefix;
+ int mMaxEntries;
+ void saveEntry(const std::string &server,
+ const std::string &port, int &saved);
+ public:
+ DropDownList(std::string prefix,
+ std::vector<std::string> dfltServer,
+ std::vector<std::string> dfltPort,
+ int maxEntries);
+ void save(const std::string &server, const std::string &port);
+ int getNumberOfElements();
+ std::string getElementAt(int i);
+ std::string getServerAt(int i);
+ std::string getPortAt(int i);
+ };
+ DropDownList *mServerList;
+ gcn::ListBox *mServerListBox;
+ ScrollArea *mServerScrollArea;
+
};
#endif
diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp
index 3c3e4ab8..79281631 100644
--- a/src/gui/menuwindow.cpp
+++ b/src/gui/menuwindow.cpp
@@ -19,21 +19,21 @@
* 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"
-extern Window *setupWindow;
-extern Window *inventoryWindow;
+extern Window *chatWindow;
extern Window *equipmentWindow;
+extern Window *inventoryWindow;
+extern Window *itemShortcutWindow;
+extern Window *setupWindow;
extern Window *skillDialog;
extern Window *statusWindow;
-extern Window *itemShortcutWindow;
namespace {
struct MenuWindowListener : public gcn::ActionListener
@@ -56,6 +56,7 @@ MenuWindow::MenuWindow():
// Buttons
const char *buttonNames[] =
{
+ "Chat",
"Status",
"Equipment",
"Inventory",
@@ -89,7 +90,11 @@ 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;
}
diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp
index f07cb417..8339e478 100644
--- a/src/gui/minimap.cpp
+++ b/src/gui/minimap.cpp
@@ -30,11 +30,11 @@
Minimap::Minimap():
Window("Map"),
- mMapImage(NULL)
+ mMapImage(NULL),
+ mProportion(0.5)
{
+ setCloseButton(true);
setWindowName("MiniMap");
- setDefaultSize(5, 25, 100, 100);
- loadWindowState();
}
Minimap::~Minimap()
@@ -51,7 +51,21 @@ void Minimap::setMapImage(Image *img)
mMapImage = img;
if (mMapImage)
+ {
+ int offsetX = getPadding();
+ int offsetY = getTitleBarHeight();
mMapImage->setAlpha(0.7);
+ setDefaultSize(offsetX, offsetY,
+ mMapImage->getWidth() < (100 + offsetX) ?
+ mMapImage->getWidth() : (100 + offsetX),
+ mMapImage->getHeight() < (100 + offsetY) ?
+ mMapImage->getHeight() : (100 + offsetY));
+ loadWindowState();
+ }
+ else
+ {
+ setVisible(false);
+ }
}
void Minimap::draw(gcn::Graphics *graphics)
@@ -68,9 +82,10 @@ 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 += ((a.width) / 2) - (player_node->mX * mProportion);
+ mapOriginY += ((a.height) / 2) - (player_node->mY * mProportion);
}
+
static_cast<Graphics*>(graphics)->
drawImage(mMapImage, mapOriginX, mapOriginY);
}
@@ -106,10 +121,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 f91dc22d..7897ebdb 100644
--- a/src/gui/minimap.h
+++ b/src/gui/minimap.h
@@ -24,6 +24,8 @@
#include "window.h"
+#include "../guichanfwd.h"
+
class Image;
/**
@@ -50,12 +52,18 @@ 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; }
+
+ /**
* Draws the minimap.
*/
void draw(gcn::Graphics *graphics);
private:
Image *mMapImage;
+ float mProportion;
};
extern Minimap *minimap;
diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp
index baae14a7..59dca0e1 100644
--- a/src/gui/ministatus.cpp
+++ b/src/gui/ministatus.cpp
@@ -19,16 +19,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "ministatus.h"
-
#include <guichan/widgets/label.hpp>
#include "gui.h"
+#include "ministatus.h"
#include "progressbar.h"
-#include "../localplayer.h"
#include "../configuration.h"
#include "../graphics.h"
+#include "../localplayer.h"
#include "../utils/tostring.h"
@@ -97,11 +96,6 @@ void MiniStatusWindow::update()
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);
diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp
index 34c9cce1..b53de828 100644
--- a/src/gui/npc_text.cpp
+++ b/src/gui/npc_text.cpp
@@ -19,12 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npc_text.h"
-
#include <string>
-#include "scrollarea.h"
-#include "button.h"
+#include "npc_text.h"
#include "textbox.h"
#include "../npc.h"
@@ -60,7 +57,11 @@ NpcTextDialog::NpcTextDialog():
void NpcTextDialog::setText(const std::string &text)
{
+ const gcn::Rectangle &area = getChildrenArea();
+ const int width = area.width;
+
mText = text;
+ mTextBox->setMinWidth(width - 30);
mTextBox->setTextWrapped(mText);
}
@@ -77,6 +78,9 @@ void NpcTextDialog::widgetResized(const gcn::Event &event)
const int width = area.width;
const int height = area.height;
+ mTextBox->setMinWidth(width - 30);
+ mTextBox->setTextWrapped(mText);
+
scrollArea->setDimension(gcn::Rectangle(
5, 5, width - 10, height - 15 - okButton->getHeight()));
okButton->setPosition(
diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h
index 76161f88..b647b9a1 100644
--- a/src/gui/npc_text.h
+++ b/src/gui/npc_text.h
@@ -23,10 +23,15 @@
#define _TMW_NPC_TEXT_H
#include <iosfwd>
+
#include <guichan/actionlistener.hpp>
+#include "button.h"
+#include "scrollarea.h"
#include "window.h"
+#include "../guichanfwd.h"
+
class TextBox;
/**
diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp
index cdd38312..c17cd4aa 100644
--- a/src/gui/npclistdialog.cpp
+++ b/src/gui/npclistdialog.cpp
@@ -19,13 +19,10 @@
* 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 "../npc.h"
diff --git a/src/gui/npclistdialog.h b/src/gui/npclistdialog.h
index f548dbba..099d03c0 100644
--- a/src/gui/npclistdialog.h
+++ b/src/gui/npclistdialog.h
@@ -28,6 +28,8 @@
#include <guichan/actionlistener.hpp>
#include <guichan/listmodel.hpp>
+#include "button.h"
+#include "scrollarea.h"
#include "window.h"
#include "../guichanfwd.h"
diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp
index d43c8e69..421c873e 100644
--- a/src/gui/ok_dialog.cpp
+++ b/src/gui/ok_dialog.cpp
@@ -20,33 +20,52 @@
*/
#include "ok_dialog.h"
-#include "textbox.h"
-#include "button.h"
-#include "scrollarea.h"
+
+#include <guichan/font.hpp>
OkDialog::OkDialog(const std::string &title, const std::string &msg,
Window *parent):
Window(title, true, parent)
{
- TextBox *textBox = new TextBox();
- textBox->setEditable(false);
+ mTextBox = new TextBox();
+ mTextBox->setEditable(false);
+ mTextBox->setOpaque(false);
+
+ mTextArea = new ScrollArea(mTextBox);
+ okButton = new Button("Ok", "ok", this);
+
+ mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mTextArea->setOpaque(false);
- gcn::ScrollArea *scrollArea = new ScrollArea(textBox);
- gcn::Button *okButton = new Button("Ok", "ok", this);
+ mTextBox->setMinWidth(260);
+ mTextBox->setTextWrapped(msg);
- setContentSize(260, 175);
- scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
- scrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS);
- scrollArea->setDimension(gcn::Rectangle(
- 5, 5, 250, 160 - okButton->getHeight()));
+ int numRows = mTextBox->getNumberOfRows();
- textBox->setTextWrapped(msg);
+ if (numRows > 1)
+ {
+ // 15 == height of each line of text (based on font heights)
+ // 14 == row top + bottom graphic pixel heights
+ setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + okButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5,
+ 3 + (numRows * 14)));
+ }
+ else
+ {
+ int width = getFont()->getWidth(title);
+ if (width < getFont()->getWidth(msg))
+ width = getFont()->getWidth(msg);
+ if (width < okButton->getWidth())
+ width = okButton->getWidth();
+ setContentSize(width + 15, 30 + okButton->getHeight());
+ mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17));
+ }
- okButton->setPosition(
- 260 - 5 - okButton->getWidth(),
- 175 - 5 - okButton->getHeight());
+ okButton->setPosition((mTextBox->getMinWidth() - okButton->getWidth()) / 2,
+ (numRows * 14) + okButton->getHeight() - 8);
- add(scrollArea);
+ add(mTextArea);
add(okButton);
setLocationRelativeTo(getParent());
@@ -54,6 +73,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 cba12d72..a06ddd7c 100644
--- a/src/gui/ok_dialog.h
+++ b/src/gui/ok_dialog.h
@@ -24,8 +24,13 @@
#include <guichan/actionlistener.hpp>
+#include "button.h"
+#include "scrollarea.h"
+#include "textbox.h"
#include "window.h"
+#include "../guichanfwd.h"
+
/**
* An 'Ok' button dialog.
*
@@ -41,10 +46,17 @@ class OkDialog : public Window, public gcn::ActionListener {
OkDialog(const std::string &title, const std::string &msg,
Window *parent = NULL);
+ unsigned int getNumRows();
+
/**
* Called when receiving actions from the widgets.
*/
void action(const gcn::ActionEvent &event);
+
+ private:
+ TextBox *mTextBox;
+ ScrollArea *mTextArea;
+ gcn::Button *okButton;
};
#endif
diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h
index 8a14b72a..9aa6ab49 100644
--- a/src/gui/passwordfield.h
+++ b/src/gui/passwordfield.h
@@ -24,6 +24,8 @@
#include "textfield.h"
+#include "../guichanfwd.h"
+
/**
* A password field.
*
diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp
index b6b7663a..79c5676f 100644
--- a/src/gui/playerbox.cpp
+++ b/src/gui/playerbox.cpp
@@ -23,8 +23,8 @@
#include "playerbox.h"
-#include "../player.h"
#include "../graphics.h"
+#include "../player.h"
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h
index 78eeee91..7aec87bf 100644
--- a/src/gui/playerbox.h
+++ b/src/gui/playerbox.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/scrollarea.hpp>
+#include "../guichanfwd.h"
+
class ImageRect;
class Player;
diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp
index 8b73abfe..c0feb68d 100644
--- a/src/gui/popupmenu.cpp
+++ b/src/gui/popupmenu.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "popupmenu.h"
-
#include <cassert>
#include <iostream>
@@ -29,6 +27,7 @@
#include "browserbox.h"
#include "inventorywindow.h"
#include "item_amount.h"
+#include "popupmenu.h"
#include "windowcontainer.h"
#include "../being.h"
@@ -38,8 +37,11 @@
#include "../npc.h"
#include "../player_relations.h"
-#include "../resources/iteminfo.h"
+#include "../net/messageout.h"
+#include "../net/protocol.h"
+
#include "../resources/itemdb.h"
+#include "../resources/iteminfo.h"
extern std::string tradePartnerName;
@@ -68,49 +70,53 @@ void PopupMenu::showPopup(int x, int y, Being *being)
switch (mBeing->getType())
{
- case Being::PLAYER:
- {
- // Players can be traded with. Later also attack, follow and
- // add as buddy will be options in this menu.
- const std::string &name = mBeing->getName();
- mBrowserBox->addRow("@@trade|Trade With " + name + "@@");
- mBrowserBox->addRow("@@attack|Attack " + name + "@@");
-
- mBrowserBox->addRow("##3---");
-
- switch (player_relations.getRelation(name)) {
- case PlayerRelation::NEUTRAL:
- mBrowserBox->addRow("@@friend|Befriend " + name + "@@");
-
- case PlayerRelation::FRIEND:
- mBrowserBox->addRow("@@disregard|Disregard " + name + "@@");
- mBrowserBox->addRow("@@ignore|Ignore " + name + "@@");
- break;
-
- case PlayerRelation::DISREGARDED:
- mBrowserBox->addRow("@@unignore|Un-Ignore " + name + "@@");
- mBrowserBox->addRow("@@ignore|Completely ignore " + name + "@@");
- break;
-
- case PlayerRelation::IGNORED:
- mBrowserBox->addRow("@@unignore|Un-Ignore " + name + "@@");
- break;
- }
-
- //mBrowserBox->addRow("@@follow|Follow " + name + "@@");
- //mBrowserBox->addRow("@@buddy|Add " + name + " to Buddy List@@");
- }
- break;
-
- case Being::NPC:
- // NPCs can be talked to (single option, candidate for removal
- // unless more options would be added)
- mBrowserBox->addRow("@@talk|Talk To NPC@@");
- break;
-
- default:
- /* Other beings aren't interesting... */
- break;
+ case Being::PLAYER:
+ {
+ // Players can be traded with. Later also attack, follow and
+ // add as buddy will be options in this menu.
+ const std::string &name = mBeing->getName();
+ mBrowserBox->addRow("@@trade|Trade With " + name + "@@");
+ mBrowserBox->addRow("@@attack|Attack " + name + "@@");
+
+ mBrowserBox->addRow("##3---");
+
+ switch (player_relations.getRelation(name)) {
+ case PlayerRelation::NEUTRAL:
+ mBrowserBox->addRow("@@friend|Befriend " + name + "@@");
+
+ case PlayerRelation::FRIEND:
+ mBrowserBox->addRow("@@disregard|Disregard " + name + "@@");
+ mBrowserBox->addRow("@@ignore|Ignore " + name + "@@");
+ break;
+
+ case PlayerRelation::DISREGARDED:
+ mBrowserBox->addRow("@@unignore|Un-Ignore " + name + "@@");
+ mBrowserBox->addRow("@@ignore|Completely ignore " + name + "@@");
+ break;
+
+ case PlayerRelation::IGNORED:
+ mBrowserBox->addRow("@@unignore|Un-Ignore " + name + "@@");
+ break;
+ }
+
+ //mBrowserBox->addRow("@@follow|Follow " + name + "@@");
+ //mBrowserBox->addRow("@@buddy|Add " + name + " to Buddy List@@");
+
+ mBrowserBox->addRow("##3---");
+ mBrowserBox->addRow("@@party-invite|Invite " + name +
+ " to party@@");
+ }
+ break;
+
+ case Being::NPC:
+ // NPCs can be talked to (single option, candidate for removal
+ // unless more options would be added)
+ mBrowserBox->addRow("@@talk|Talk To NPC@@");
+ break;
+
+ default:
+ /* Other beings aren't interesting... */
+ break;
}
//browserBox->addRow("@@look|Look To@@");
@@ -140,56 +146,56 @@ void PopupMenu::handleLink(const std::string& link)
{
// Talk To action
if (link == "talk" &&
- mBeing != NULL &&
- mBeing->getType() == Being::NPC &&
- current_npc == 0)
+ mBeing != NULL &&
+ mBeing->getType() == Being::NPC &&
+ current_npc == 0)
{
- dynamic_cast<NPC*>(mBeing)->talk();
+ dynamic_cast<NPC*>(mBeing)->talk();
}
// Trade action
else if (link == "trade" &&
- mBeing != NULL &&
- mBeing->getType() == Being::PLAYER)
+ mBeing != NULL &&
+ mBeing->getType() == Being::PLAYER)
{
- player_node->trade(mBeing);
- tradePartnerName = mBeing->getName();
+ player_node->trade(mBeing);
+ tradePartnerName = mBeing->getName();
}
// Attack action
else if (link == "attack" &&
- mBeing != NULL &&
- mBeing->getType() == Being::PLAYER)
+ mBeing != NULL &&
+ mBeing->getType() == Being::PLAYER)
{
- player_node->attack(mBeing, true);
+ player_node->attack(mBeing, true);
}
else if (link == "unignore" &&
- mBeing != NULL &&
- mBeing->getType() == Being::PLAYER)
+ mBeing != NULL &&
+ mBeing->getType() == Being::PLAYER)
{
- player_relations.setRelation(mBeing->getName(), PlayerRelation::NEUTRAL);
+ player_relations.setRelation(mBeing->getName(), PlayerRelation::NEUTRAL);
}
else if (link == "ignore" &&
- mBeing != NULL &&
- mBeing->getType() == Being::PLAYER)
+ mBeing != NULL &&
+ mBeing->getType() == Being::PLAYER)
{
- player_relations.setRelation(mBeing->getName(), PlayerRelation::IGNORED);
+ player_relations.setRelation(mBeing->getName(), PlayerRelation::IGNORED);
}
else if (link == "disregard" &&
- mBeing != NULL &&
- mBeing->getType() == Being::PLAYER)
+ mBeing != NULL &&
+ mBeing->getType() == Being::PLAYER)
{
- player_relations.setRelation(mBeing->getName(), PlayerRelation::DISREGARDED);
+ player_relations.setRelation(mBeing->getName(), PlayerRelation::DISREGARDED);
}
else if (link == "friend" &&
- mBeing != NULL &&
- mBeing->getType() == Being::PLAYER)
+ mBeing != NULL &&
+ mBeing->getType() == Being::PLAYER)
{
- player_relations.setRelation(mBeing->getName(), PlayerRelation::FRIEND);
+ player_relations.setRelation(mBeing->getName(), PlayerRelation::FRIEND);
}
/*
@@ -202,16 +208,16 @@ void PopupMenu::handleLink(const std::string& link)
// Add Buddy action
else if ((link == "buddy") && mBeing != NULL && mBeing->isPlayer())
{
- if (!buddyWindow->isVisible())
- buddyWindow->setVisible(true);
+ if (!buddyWindow->isVisible())
+ buddyWindow->setVisible(true);
- buddyWindow->addBuddy(mBeing->getName());
+ buddyWindow->addBuddy(mBeing->getName());
}*/
// Pick Up Floor Item action
else if ((link == "pickup") && mFloorItem != NULL)
{
- player_node->pickUp(mFloorItem);
+ player_node->pickUp(mFloorItem);
}
// Look To action
@@ -221,39 +227,47 @@ void PopupMenu::handleLink(const std::string& link)
else if (link == "use")
{
- assert(mItem);
- if (mItem->isEquipment())
- {
- if (mItem->isEquipped())
- {
- player_node->unequipItem(mItem);
- }
- else
- {
- player_node->equipItem(mItem);
- }
- }
- else
- {
- player_node->useItem(mItem);
- }
+ assert(mItem);
+ if (mItem->isEquipment())
+ {
+ if (mItem->isEquipped())
+ {
+ player_node->unequipItem(mItem);
+ }
+ else
+ {
+ player_node->equipItem(mItem);
+ }
+ }
+ else
+ {
+ player_node->useItem(mItem);
+ }
}
else if (link == "drop")
{
- new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem);
+ new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem);
}
else if (link == "description")
{
- // do nothing for now, I need to write
- // a window for the description first
+ // do nothing for now, I need to write
+ // a window for the description first
+ }
+ else if (link == "party-invite" &&
+ mBeing != NULL &&
+ mBeing->getType() == Being::PLAYER)
+ {
+ MessageOut outMsg(player_node->getNetwork());
+ outMsg.writeInt16(CMSG_PARTY_INVITE);
+ outMsg.writeInt32(mBeing->getId());
}
// Unknown actions
else
{
- std::cout << link << std::endl;
+ std::cout << link << std::endl;
}
setVisible(false);
@@ -271,13 +285,13 @@ void PopupMenu::showPopup(int x, int y, Item *item)
if (item->isEquipment())
{
- if (item->isEquipped())
- mBrowserBox->addRow("@@use|Unequip@@");
- else
- mBrowserBox->addRow("@@use|Equip@@");
+ if (item->isEquipped())
+ mBrowserBox->addRow("@@use|Unequip@@");
+ else
+ mBrowserBox->addRow("@@use|Equip@@");
}
else
- mBrowserBox->addRow("@@use|Use@@");
+ mBrowserBox->addRow("@@use|Use@@");
mBrowserBox->addRow("@@drop|Drop@@");
mBrowserBox->addRow("@@description|Description@@");
@@ -291,9 +305,9 @@ void PopupMenu::showPopup(int x, int y)
{
setContentSize(mBrowserBox->getWidth() + 8, mBrowserBox->getHeight() + 8);
if (windowContainer->getWidth() < (x + getWidth() + 5))
- x = windowContainer->getWidth() - getWidth();
+ x = windowContainer->getWidth() - getWidth();
if (windowContainer->getHeight() < (y + getHeight() + 5))
- y = windowContainer->getHeight() - getHeight();
+ y = windowContainer->getHeight() - getHeight();
setPosition(x, y);
setVisible(true);
requestMoveToTop();
diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h
index 2d10e6eb..3cf949b3 100644
--- a/src/gui/popupmenu.h
+++ b/src/gui/popupmenu.h
@@ -22,15 +22,14 @@
#ifndef _TMW_POPUP_MENU_H
#define _TMW_POPUP_MENU_H
-#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.h b/src/gui/progressbar.h
index 70cfa15c..a20c901f 100644
--- a/src/gui/progressbar.h
+++ b/src/gui/progressbar.h
@@ -26,8 +26,9 @@
#include <SDL_types.h>
-class ImageRect;
+#include "../guichanfwd.h"
+class ImageRect;
/**
* A progress bar.
diff --git a/src/gui/radiobutton.h b/src/gui/radiobutton.h
index 6506444f..8fb6d832 100644
--- a/src/gui/radiobutton.h
+++ b/src/gui/radiobutton.h
@@ -24,8 +24,9 @@
#include <guichan/widgets/radiobutton.hpp>
-class Image;
+#include "../guichanfwd.h"
+class Image;
/*
* Guichan based RadioButton with custom look
diff --git a/src/gui/register.cpp b/src/gui/register.cpp
index 2a97a3e5..ec6a9756 100644
--- a/src/gui/register.cpp
+++ b/src/gui/register.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "register.h"
-
#include <string>
#include <sstream>
@@ -34,10 +32,13 @@
#include "button.h"
#include "checkbox.h"
#include "login.h"
+#include "ok_dialog.h"
#include "passwordfield.h"
#include "radiobutton.h"
+#include "register.h"
#include "textfield.h"
-#include "ok_dialog.h"
+
+#include "../utils/tostring.h"
void
WrongDataNoticeListener::setTarget(gcn::TextField *textField)
@@ -63,53 +64,65 @@ 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);
mCancelButton = new Button("Cancel", "cancel", this);
- const int width = 220;
- const int height = 150;
- setContentSize(width, height);
-
- mUserField->setPosition(65, 5);
- mUserField->setWidth(width - 70);
- mPasswordField->setPosition(
- 65, mUserField->getY() + mUserField->getHeight() + 7);
- mPasswordField->setWidth(mUserField->getWidth());
- mConfirmField->setPosition(
- 65, mPasswordField->getY() + mPasswordField->getHeight() + 7);
- mConfirmField->setWidth(mUserField->getWidth());
- mServerField->setPosition(
- 65, 23 + mConfirmField->getY() + mConfirmField->getHeight() + 7);
- mServerField->setWidth(mUserField->getWidth());
-
- userLabel->setPosition(5, mUserField->getY() + 1);
- passwordLabel->setPosition(5, mPasswordField->getY() + 1);
- confirmLabel->setPosition(5, mConfirmField->getY() + 1);
- serverLabel->setPosition(5, mServerField->getY() + 1);
-
- mMaleButton->setPosition(
- 70, mConfirmField->getY() + mConfirmField->getHeight() + 7);
- mFemaleButton->setPosition(
- 70 + 10 + mMaleButton->getWidth(),
- mMaleButton->getY());
+ const int WIDTH = 220;
+ const int HEIGHT = 170;
+ const int FIELD_WIDTH = WIDTH - 70;
+
+ setContentSize(WIDTH, HEIGHT);
+
+ const int USER_TOP = 5;
+ userLabel->setPosition(5, USER_TOP);
+ mUserField->setPosition(65, USER_TOP);
+ mUserField->setWidth(FIELD_WIDTH);
+
+ const int PASS_TOP = 9 + USER_TOP + userLabel->getHeight();
+ passwordLabel->setPosition(5, PASS_TOP);
+ mPasswordField->setPosition(65, PASS_TOP);
+ mPasswordField->setWidth(FIELD_WIDTH);
+
+ const int CONFIRM_TOP = 9 + PASS_TOP + passwordLabel->getHeight();
+ confirmLabel->setPosition(5, CONFIRM_TOP);
+ mConfirmField->setPosition(65, CONFIRM_TOP);
+ mConfirmField->setWidth(FIELD_WIDTH);
+
+ const int SEX_TOP = 9 + CONFIRM_TOP + confirmLabel->getHeight();
+ mMaleButton->setPosition(70, SEX_TOP);
+ mFemaleButton->setPosition(80 + mMaleButton->getWidth(), SEX_TOP);
+
+ const int SERVER_TOP = 9 + SEX_TOP + mMaleButton->getHeight() + 5;
+ serverLabel->setPosition(5, SERVER_TOP);
+ mServerField->setPosition(65, SERVER_TOP);
+ mServerField->setWidth(FIELD_WIDTH);
+
+ const int PORT_TOP = 9 + SERVER_TOP + serverLabel->getHeight();
+ portLabel->setPosition(5, PORT_TOP);
+ mPortField->setPosition(65, PORT_TOP);
+ mPortField->setWidth(FIELD_WIDTH);
mCancelButton->setPosition(
- width - mCancelButton->getWidth() - 5,
- height - mCancelButton->getHeight() - 5);
+ WIDTH - mCancelButton->getWidth() - 5,
+ HEIGHT - mCancelButton->getHeight() - 5);
mRegisterButton->setPosition(
mCancelButton->getX() - mRegisterButton->getWidth() - 5,
- height - mRegisterButton->getHeight() - 5);
+ HEIGHT - mRegisterButton->getHeight() - 5);
mUserField->addKeyListener(this);
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,19 +133,26 @@ 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);
add(userLabel);
add(passwordLabel);
- add(serverLabel);
add(confirmLabel);
+ add(serverLabel);
+ add(portLabel);
+
add(mUserField);
add(mPasswordField);
add(mConfirmField);
add(mServerField);
+ add(mPortField);
+
add(mMaleButton);
add(mFemaleButton);
add(mRegisterButton);
@@ -230,7 +250,7 @@ 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";
@@ -254,5 +274,42 @@ RegisterDialog::canSubmit()
!mPasswordField->getText().empty() &&
!mConfirmField->getText().empty() &&
!mServerField->getText().empty() &&
+ isUShort(mPortField->getText()) &&
state == REGISTER_STATE;
}
+
+bool
+RegisterDialog::isUShort(const std::string &str)
+{
+ if (str == "")
+ {
+ return false;
+ }
+ unsigned long l = 0;
+ for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end();
+ strPtr != strEnd; ++strPtr)
+ {
+ if (*strPtr < '0' || *strPtr > '9')
+ {
+ return false;
+ }
+ l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative
+ if (l > 65535)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+unsigned short
+RegisterDialog::getUShort(const std::string &str)
+{
+ unsigned long l = 0;
+ for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end();
+ strPtr != strEnd; ++strPtr)
+ {
+ l = l * 10 + (*strPtr - '0');
+ }
+ return static_cast<unsigned short>(l);
+}
diff --git a/src/gui/register.h b/src/gui/register.h
index 771962cc..87a11bb9 100644
--- a/src/gui/register.h
+++ b/src/gui/register.h
@@ -23,10 +23,12 @@
#define _TMW_REGISTER_H
#include <iosfwd>
+
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
#include "window.h"
+
#include "../guichanfwd.h"
class LoginData;
@@ -85,10 +87,31 @@ class RegisterDialog : public Window, public gcn::ActionListener,
bool
canSubmit();
+ /**
+ * 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.h b/src/gui/scrollarea.h
index d21dae11..ebe2c77b 100644
--- a/src/gui/scrollarea.h
+++ b/src/gui/scrollarea.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/scrollarea.hpp>
+#include "../guichanfwd.h"
+
class Image;
class ImageRect;
diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp
index 6df1cbf6..63af1aaa 100644
--- a/src/gui/sell.cpp
+++ b/src/gui/sell.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "sell.h"
-
#include <cassert>
#include <guichan/widgets/label.hpp>
@@ -28,17 +26,18 @@
#include "button.h"
#include "shoplistbox.h"
#include "scrollarea.h"
+#include "sell.h"
#include "shop.h"
#include "slider.h"
#include "../item.h"
#include "../npc.h"
-#include "../resources/iteminfo.h"
-
#include "../net/messageout.h"
#include "../net/protocol.h"
+#include "../resources/iteminfo.h"
+
#include "../utils/tostring.h"
SellDialog::SellDialog(Network *network):
diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp
index 4fae514f..2c22a426 100644
--- a/src/gui/setup.cpp
+++ b/src/gui/setup.cpp
@@ -20,41 +20,42 @@
*/
#include <algorithm>
-
-#include "setup.h"
+#include <iostream>
#include "button.h"
+#include "setup.h"
#include "setup_audio.h"
+#include "setup_colours.h"
#include "setup_joystick.h"
-#include "setup_video.h"
#include "setup_keyboard.h"
#include "setup_players.h"
+#include "setup_video.h"
#include "tabbedcontainer.h"
#include "../utils/dtor.h"
-#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;
Setup::Setup():
Window("Setup")
{
setCloseButton(true);
int width = 310;
- int height = 265;
+ int height = 310;
setContentSize(width, height);
const char *buttonNames[] = {
"Apply", "Cancel", "Reset Windows", 0
};
int x = width;
- for (const char **curBtn = buttonNames; *curBtn; ++curBtn) {
+ for (const char **curBtn = buttonNames; *curBtn; ++curBtn)
+ {
Button *btn = new Button(*curBtn, *curBtn, this);
x -= btn->getWidth() + 5;
btn->setPosition(x, height - btn->getHeight() - 5);
@@ -65,7 +66,7 @@ Setup::Setup():
btn->setEnabled(statusWindow != NULL);
}
- TabbedContainer *panel = new TabbedContainer();
+ TabbedContainer *panel = new TabbedContainer(width, 5, 20, 45, 5, 3);
panel->setDimension(gcn::Rectangle(5, 5, width, height - 40));
panel->setOpaque(false);
@@ -87,6 +88,10 @@ Setup::Setup():
panel->addTab(tab, "Keyboard");
mTabs.push_back(tab);
+ tab = new Setup_Colours();
+ panel->addTab(tab, "Colours");
+ mTabs.push_back(tab);
+
tab = new Setup_Players();
panel->addTab(tab, "Players");
mTabs.push_back(tab);
@@ -98,7 +103,7 @@ Setup::Setup():
Setup::~Setup()
{
- for_each(mTabs.begin(), mTabs.end(), make_dtor(mTabs));
+ delete_all(mTabs);
}
void Setup::action(const gcn::ActionEvent &event)
diff --git a/src/gui/setup.h b/src/gui/setup.h
index 5268f725..fd200f4c 100644
--- a/src/gui/setup.h
+++ b/src/gui/setup.h
@@ -28,6 +28,8 @@
#include "window.h"
+#include "../guichanfwd.h"
+
class SetupTab;
/**
diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp
index a027e133..70b34a31 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 "../configuration.h"
diff --git a/src/gui/setup_audio.h b/src/gui/setup_audio.h
index eaa55de6..9835a8fb 100644
--- a/src/gui/setup_audio.h
+++ b/src/gui/setup_audio.h
@@ -22,10 +22,10 @@
#ifndef _TMW_GUI_SETUP_AUDIO_H
#define _TMW_GUI_SETUP_AUDIO_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
+#include "setuptab.h"
+
#include "../guichanfwd.h"
class Setup_Audio : public SetupTab, public gcn::ActionListener
diff --git a/src/gui/setup_colours.cpp b/src/gui/setup_colours.cpp
new file mode 100644
index 00000000..0becd48f
--- /dev/null
+++ b/src/gui/setup_colours.cpp
@@ -0,0 +1,207 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <vector>
+
+#include <guichan/listmodel.hpp>
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/slider.hpp>
+
+#include "colour.h"
+#include "scrollarea.h"
+#include "setup_colours.h"
+#include "slider.h"
+
+#include "../configuration.h"
+
+Setup_Colours::Setup_Colours() :
+ mColourLabel("Colour:"),
+ mSelected(-1)
+{
+ mColourBox = new gcn::ListBox(textColour);
+ mScroll = new ScrollArea(mColourBox);
+
+ mColourLabel.setX(5);
+ mColourLabel.setY(5);
+
+ mColourBox->setDimension(gcn::Rectangle(0, 10 + mColourLabel.getHeight(),
+ 80,
+ 115 - mColourLabel.getHeight()));
+ mScroll->setDimension(gcn::Rectangle(5, 10 + mColourLabel.getHeight(),
+ 100, 115 - mColourLabel.getHeight()));
+ mColourBox->setSelected(-1);
+ mColourBox->setActionEventId("colour_box");
+ mColourBox->addActionListener(this);
+
+ setOpaque(false);
+
+ add(&mColourLabel);
+ add(mScroll);
+
+ setupPlacer(140, mLabel1, mSlider1, mText1, "R", "1");
+ setupPlacer(165, mLabel2, mSlider2, mText2, "G", "2");
+ setupPlacer(190, mLabel3, mSlider3, mText3, "B", "3");
+
+}
+
+Setup_Colours::~Setup_Colours()
+{
+ delete mLabel1;
+ delete mSlider1;
+ delete mText1;
+
+ delete mLabel2;
+ delete mSlider2;
+ delete mText2;
+
+ delete mLabel3;
+ delete mSlider3;
+ delete mText3;
+
+ delete mScroll;
+}
+
+void Setup_Colours::action(const gcn::ActionEvent &event)
+{
+ if (event.getId() == "colour_box")
+ {
+ mSelected = mColourBox->getSelected();
+ int col = textColour->getColourAt(mSelected);
+ setEntry(mSlider1, mText1, col >> 16);
+ setEntry(mSlider2, mText2, (col >> 8) & 0xff);
+ setEntry(mSlider3, mText3, col & 0xff);
+ return;
+ }
+
+ if (event.getId() == "slider1")
+ {
+ char buffer[30];
+ std::sprintf(buffer, "%d", static_cast<int>(mSlider1->getValue()));
+ mText1->setText(buffer);
+ updateColour();
+ return;
+ }
+
+ if (event.getId() == "slider2")
+ {
+ char buffer[30];
+ std::sprintf(buffer, "%d", static_cast<int>(mSlider2->getValue()));
+ mText2->setText(buffer);
+ updateColour();
+ return;
+ }
+
+ if (event.getId() == "slider3")
+ {
+ char buffer[30];
+ std::sprintf(buffer, "%d", static_cast<int>(mSlider3->getValue()));
+ mText3->setText(buffer);
+ updateColour();
+ return;
+ }
+}
+
+void Setup_Colours::setEntry(Slider *s, TextField *t, int value)
+{
+ s->setValue(value);
+ char buffer[100];
+ sprintf(buffer, "%d", value);
+ t->setText(buffer);
+}
+
+void Setup_Colours::apply()
+{
+ textColour->commit();
+}
+
+void Setup_Colours::cancel()
+{
+ textColour->rollback();
+ int col = textColour->getColourAt(mSelected);
+ setEntry(mSlider1, mText1, col >> 16);
+ setEntry(mSlider2, mText2, (col >> 8) & 0xff);
+ setEntry(mSlider3, mText3, col & 0xff);
+}
+
+void Setup_Colours::setupPlacer(int v, gcn::Label *&l, Slider *&s,
+ TextField *&t, std::string lbl,
+ std::string sfx)
+{
+ l = new gcn::Label(lbl + ":");
+ l->setX(5);
+ l->setY(v - l->getHeight() / 2);
+
+ s = new Slider(0, 255);
+ s->setHeight(10);
+ s->setX(25);
+ s->setY(v - s->getHeight() / 2);
+ s->setWidth(128);
+ s->setScale(0, 255);
+
+ t = new TextField();
+ t->setX(165);
+ t->setY(v - t->getHeight() / 2);
+ t->setWidth(40);
+ t->setNumeric(true);
+ t->setRange(0, 255);
+ t->addListener(this);
+
+ s->setActionEventId("slider" + sfx);
+ s->addActionListener(this);
+
+ add(l);
+ add(s);
+ add(t);
+}
+
+void Setup_Colours::listen(const TextField *tf)
+{
+ if (tf == mText1)
+ {
+ mSlider1->setValue(tf->getValue());
+ updateColour();
+ return;
+ }
+ if (tf == mText2)
+ {
+ mSlider2->setValue(tf->getValue());
+ updateColour();
+ return;
+ }
+ if (tf == mText3)
+ {
+ mSlider3->setValue(tf->getValue());
+ updateColour();
+ return;
+ }
+}
+
+void Setup_Colours::updateColour()
+{
+ if (mSelected == -1)
+ {
+ return;
+ }
+ int rgb = static_cast<int>(mSlider1->getValue()) << 16 |
+ static_cast<int>(mSlider2->getValue()) << 8 |
+ static_cast<int>(mSlider3->getValue());
+ textColour->setColourAt(mSelected, rgb);
+}
diff --git a/src/gui/setup_colours.h b/src/gui/setup_colours.h
new file mode 100644
index 00000000..3bd87848
--- /dev/null
+++ b/src/gui/setup_colours.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef _SETUP_COLOURS_H
+#define _SETUP_COLOURS_H
+
+#include <string>
+#include <vector>
+
+#include <guichan/actionlistener.hpp>
+#include <guichan/widgets/label.hpp>
+#include <guichan/widgets/listbox.hpp>
+
+#include "scrollarea.h"
+#include "setuptab.h"
+#include "slider.h"
+#include "textfield.h"
+
+#include "../guichanfwd.h"
+
+class Setup_Colours : public SetupTab, public gcn::ActionListener,
+ public TextFieldListener
+{
+ public:
+ Setup_Colours();
+ ~Setup_Colours();
+ void apply();
+ void cancel();
+ void action(const gcn::ActionEvent &event);
+
+ void listen(const TextField *tf);
+ private:
+ gcn::ListBox *mColourBox;
+ gcn::Label mColourLabel;
+ ScrollArea *mScroll;
+ int mSelected;
+
+ gcn::Label *mLabel1;
+ Slider *mSlider1;
+ TextField *mText1;
+ int mValue1;
+
+ gcn::Label *mLabel2;
+ Slider *mSlider2;
+ TextField *mText2;
+ int mValue2;
+
+ gcn::Label *mLabel3;
+ Slider *mSlider3;
+ TextField *mText3;
+ int mValue3;
+
+ void setupPlacer(int v, gcn::Label *&l, Slider *&s, TextField *&t,
+ std::string lbl, std::string sfx);
+ void setEntry(Slider *s, TextField *t, int value);
+ void updateColour();
+};
+#endif
diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp
index c59068f7..723d0597 100644
--- a/src/gui/setup_joystick.cpp
+++ b/src/gui/setup_joystick.cpp
@@ -19,12 +19,12 @@
* 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 "../configuration.h"
#include "../joystick.h"
diff --git a/src/gui/setup_joystick.h b/src/gui/setup_joystick.h
index 0b7ebe98..d2973a89 100644
--- a/src/gui/setup_joystick.h
+++ b/src/gui/setup_joystick.h
@@ -22,10 +22,10 @@
#ifndef _TMW_GUI_SETUP_JOYSTICK_H
#define _TMW_GUI_SETUP_JOYSTICK_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
+#include "setuptab.h"
+
#include "../guichanfwd.h"
class Setup_Joystick : public SetupTab, public gcn::ActionListener
diff --git a/src/gui/setup_keyboard.cpp b/src/gui/setup_keyboard.cpp
index c6247487..007fcb52 100644
--- a/src/gui/setup_keyboard.cpp
+++ b/src/gui/setup_keyboard.cpp
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup_keyboard.h"
+#include <SDL_keyboard.h>
#include <guichan/widgets/label.hpp>
#include <guichan/listmodel.hpp>
@@ -28,14 +28,13 @@
#include "listbox.h"
#include "ok_dialog.h"
#include "scrollarea.h"
+#include "setup_keyboard.h"
#include "../configuration.h"
#include "../keyboardconfig.h"
#include "../utils/tostring.h"
-#include <SDL_keyboard.h>
-
/**
* The list model for key function list.
*
diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h
index 50fa76fb..937790af 100644
--- a/src/gui/setup_keyboard.h
+++ b/src/gui/setup_keyboard.h
@@ -22,14 +22,14 @@
#ifndef _TMW_GUI_SETUP_KEYBOARD_H
#define _TMW_GUI_SETUP_KEYBOARD_H
-#include "setuptab.h"
-#include "button.h"
-#include "../guichanfwd.h"
+#include <string>
#include <guichan/actionlistener.hpp>
+#include "button.h"
+#include "setuptab.h"
-#include <string>
+#include "../guichanfwd.h"
class Setup_Keyboard : public SetupTab, public gcn::ActionListener
{
diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp
index 7dcbb5dc..d07a9685 100644
--- a/src/gui/setup_players.cpp
+++ b/src/gui/setup_players.cpp
@@ -19,19 +19,19 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "setup_players.h"
-
#include <vector>
+
#include <guichan/widgets/dropdown.hpp>
#include <guichan/widgets/label.hpp>
#include "button.h"
#include "checkbox.h"
#include "ok_dialog.h"
+#include "setup_players.h"
-#include "../player_relations.h"
#include "../configuration.h"
#include "../log.h"
+#include "../player_relations.h"
#include "../sound.h"
#define COLUMNS_NR 2 // name plus listbox
@@ -46,7 +46,7 @@
#define WIDGET_AT(row, column) (((row) * COLUMNS_NR) + column)
-static std::string table_titles[COLUMNS_NR] = {"name", "relation"};
+static std::string table_titles[COLUMNS_NR] = {" name", "relation "};
static const std::string RELATION_NAMES[PlayerRelation::RELATIONS_NR] = {
"neutral", "friend", "disregarded", "ignored"
diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h
index b04023ab..b693a952 100644
--- a/src/gui/setup_players.h
+++ b/src/gui/setup_players.h
@@ -22,15 +22,14 @@
#ifndef _TMW_GUI_SETUP_PLAYERS_H
#define _TMW_GUI_SETUP_PLAYERS_H
-#include "setuptab.h"
+#include <guichan/actionlistener.hpp>
-#include "scrollarea.h"
#include "button.h"
+#include "scrollarea.h"
+#include "setuptab.h"
#include "table.h"
-#include <guichan/actionlistener.hpp>
#include "../guichanfwd.h"
-
#include "../player_relations.h"
class PlayerTableModel;
diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp
index 5db2c262..15841615 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"
@@ -104,6 +103,8 @@ Setup_Video::Setup_Video():
mFullScreenEnabled(config.getValue("screen", 0)),
mOpenGLEnabled(config.getValue("opengl", 0)),
mCustomCursorEnabled(config.getValue("customcursor", 1)),
+ mParticleEffectsEnabled(config.getValue("particleeffects", 1)),
+ mSpeechBubbleEnabled(config.getValue("speechbubble", 1)),
mOpacity(config.getValue("guialpha", 0.8)),
mFps((int)config.getValue("fpslimit", 60)),
mModeListModel(new ModeListModel()),
@@ -111,6 +112,8 @@ 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)),
mAlphaSlider(new Slider(0.2, 1.0)),
mFpsCheckBox(new CheckBox("FPS Limit: ")),
mFpsSlider(new Slider(10, 200)),
@@ -138,16 +141,18 @@ Setup_Video::Setup_Video():
mOpenGLCheckBox->setEnabled(false);
#endif
- mModeList->setDimension(gcn::Rectangle(0, 0, 60, 50));
- scrollArea->setDimension(gcn::Rectangle(10, 10, 90, 50));
+ mModeList->setDimension(gcn::Rectangle(0, 0, 60, 70));
+ scrollArea->setDimension(gcn::Rectangle(10, 10, 90, 70));
mFsCheckBox->setPosition(110, 10);
mOpenGLCheckBox->setPosition(110, 30);
+ mParticleEffectsCheckBox->setPosition(175, 30);
mCustomCursorCheckBox->setPosition(110, 50);
- mAlphaSlider->setDimension(gcn::Rectangle(10, 80, 100, 10));
+ mSpeechBubbleCheckBox->setPosition(110, 70);
+ mAlphaSlider->setDimension(gcn::Rectangle(10, 100, 75, 10));
alphaLabel->setPosition(20 + mAlphaSlider->getWidth(),
mAlphaSlider->getY());
- mFpsCheckBox->setPosition(90, 100);
- mFpsSlider->setDimension(gcn::Rectangle(10, 100, 75, 10));
+ mFpsCheckBox->setPosition(90, 120);
+ mFpsSlider->setDimension(gcn::Rectangle(10, 120, 75, 10));
mFpsField->setPosition(100 + mFpsCheckBox->getWidth(), 100);
mFpsField->setWidth(30);
@@ -161,6 +166,8 @@ Setup_Video::Setup_Video():
mFpsCheckBox->setSelected(mFps > 0);
mCustomCursorCheckBox->setActionEventId("customcursor");
+ mParticleEffectsCheckBox->setActionEventId("particleeffects");
+ mSpeechBubbleCheckBox->setActionEventId("speechbubble");
mAlphaSlider->setActionEventId("guialpha");
mFpsCheckBox->setActionEventId("fpslimitcheckbox");
mFpsSlider->setActionEventId("fpslimitslider");
@@ -174,6 +181,8 @@ Setup_Video::Setup_Video():
mParticleDetailField->setActionEventId("particledetailfield");
mCustomCursorCheckBox->addActionListener(this);
+ mParticleEffectsCheckBox->addActionListener(this);
+ mSpeechBubbleCheckBox->addActionListener(this);
mAlphaSlider->addActionListener(this);
mFpsCheckBox->addActionListener(this);
mFpsSlider->addActionListener(this);
@@ -187,26 +196,26 @@ Setup_Video::Setup_Video():
mParticleDetailSlider->addActionListener(this);
mParticleDetailField->addKeyListener(this);
- mScrollRadiusSlider->setDimension(gcn::Rectangle(10, 120, 75, 10));
+ mScrollRadiusSlider->setDimension(gcn::Rectangle(10, 140, 75, 10));
gcn::Label *scrollRadiusLabel = new gcn::Label("Scroll radius");
- scrollRadiusLabel->setPosition(90, 120);
- mScrollRadiusField->setPosition(mFpsField->getX(), 120);
+ scrollRadiusLabel->setPosition(90, 140);
+ mScrollRadiusField->setPosition(mFpsField->getX(), 140);
mScrollRadiusField->setWidth(30);
mScrollRadiusField->setText(toString(mOriginalScrollRadius));
mScrollRadiusSlider->setValue(mOriginalScrollRadius);
- mScrollLazinessSlider->setDimension(gcn::Rectangle(10, 140, 75, 10));
+ mScrollLazinessSlider->setDimension(gcn::Rectangle(10, 160, 75, 10));
gcn::Label *scrollLazinessLabel = new gcn::Label("Scroll laziness");
- scrollLazinessLabel->setPosition(90, 140);
- mScrollLazinessField->setPosition(mFpsField->getX(), 140);
+ scrollLazinessLabel->setPosition(90, 160);
+ mScrollLazinessField->setPosition(mFpsField->getX(), 160);
mScrollLazinessField->setWidth(30);
mScrollLazinessField->setText(toString(mOriginalScrollLaziness));
mScrollLazinessSlider->setValue(mOriginalScrollLaziness);
- mOverlayDetailSlider->setDimension(gcn::Rectangle(10, 160, 75, 10));
+ mOverlayDetailSlider->setDimension(gcn::Rectangle(10, 180, 75, 10));
gcn::Label *overlayDetailLabel = new gcn::Label("Ambient FX");
- overlayDetailLabel->setPosition(90, 160);
- mOverlayDetailField->setPosition(180, 160);
+ overlayDetailLabel->setPosition(90, 180);
+ mOverlayDetailField->setPosition(180, 180);
mOverlayDetailField->setWidth(30);
switch (mOverlayDetail)
{
@@ -222,10 +231,10 @@ Setup_Video::Setup_Video():
}
mOverlayDetailSlider->setValue(mOverlayDetail);
- mParticleDetailSlider->setDimension(gcn::Rectangle(10, 180, 75, 10));
+ mParticleDetailSlider->setDimension(gcn::Rectangle(10, 200, 75, 10));
gcn::Label *particleDetailLabel = new gcn::Label("Particle Detail");
- particleDetailLabel->setPosition(90, 180);
- mParticleDetailField->setPosition(180, 180);
+ particleDetailLabel->setPosition(90, 200);
+ mParticleDetailField->setPosition(180, 200);
mParticleDetailField->setWidth(60);
switch (mParticleDetail)
{
@@ -248,6 +257,8 @@ Setup_Video::Setup_Video():
add(mFsCheckBox);
add(mOpenGLCheckBox);
add(mCustomCursorCheckBox);
+ add(mParticleEffectsCheckBox);
+ add(mSpeechBubbleCheckBox);
add(mAlphaSlider);
add(alphaLabel);
add(mFpsCheckBox);
@@ -328,6 +339,8 @@ void Setup_Video::apply()
// We sync old and new values at apply time
mFullScreenEnabled = config.getValue("screen", 0);
mCustomCursorEnabled = config.getValue("customcursor", 1);
+ mParticleEffectsEnabled = config.getValue("particleeffects", 1);
+ mSpeechBubbleEnabled = config.getValue("speechbubble", 1);
mOpacity = config.getValue("guialpha", 0.8);
mOverlayDetail = (int)config.getValue("OverlayDetail", 2);
mOpenGLEnabled = config.getValue("opengl", 0);
@@ -370,6 +383,8 @@ void Setup_Video::cancel()
config.setValue("screen", mFullScreenEnabled ? 1 : 0);
config.setValue("customcursor", mCustomCursorEnabled ? 1 : 0);
+ config.setValue("particleeffects", mParticleEffectsEnabled ? 1 : 0);
+ config.setValue("speechbubble", mSpeechBubbleEnabled ? 1 : 0);
config.setValue("guialpha", mOpacity);
config.setValue("opengl", mOpenGLEnabled ? 1 : 0);
}
@@ -385,6 +400,18 @@ void Setup_Video::action(const gcn::ActionEvent &event)
config.setValue("customcursor",
mCustomCursorCheckBox->isSelected() ? 1 : 0);
}
+ else if (event.getId() == "particleeffects")
+ {
+ config.setValue("particleeffects",
+ mParticleEffectsCheckBox->isSelected() ? 1 : 0);
+ new OkDialog("Particle effect settings changed",
+ "Restart your client or change maps for the change to take effect.");
+ }
+ else if (event.getId() == "speechbubble")
+ {
+ config.setValue("speechbubble",
+ mSpeechBubbleCheckBox->isSelected() ? 1 : 0);
+ }
else if (event.getId() == "fpslimitslider")
{
mFps = (int) mFpsSlider->getValue();
diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h
index 355a321e..4103c5ef 100644
--- a/src/gui/setup_video.h
+++ b/src/gui/setup_video.h
@@ -22,11 +22,11 @@
#ifndef _TMW_GUI_SETUP_VIDEO_H
#define _TMW_GUI_SETUP_VIDEO_H
-#include "setuptab.h"
-
#include <guichan/actionlistener.hpp>
#include <guichan/keylistener.hpp>
+#include "setuptab.h"
+
#include "../guichanfwd.h"
class Setup_Video : public SetupTab, public gcn::ActionListener,
@@ -49,6 +49,8 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
bool mFullScreenEnabled;
bool mOpenGLEnabled;
bool mCustomCursorEnabled;
+ bool mParticleEffectsEnabled;
+ bool mSpeechBubbleEnabled;
double mOpacity;
int mFps;
@@ -58,6 +60,8 @@ class Setup_Video : public SetupTab, public gcn::ActionListener,
gcn::CheckBox *mFsCheckBox;
gcn::CheckBox *mOpenGLCheckBox;
gcn::CheckBox *mCustomCursorCheckBox;
+ gcn::CheckBox *mParticleEffectsCheckBox;
+ gcn::CheckBox *mSpeechBubbleCheckBox;
gcn::Slider *mAlphaSlider;
gcn::CheckBox *mFpsCheckBox;
diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp
index 085e93ce..a4478a62 100644
--- a/src/gui/shop.cpp
+++ b/src/gui/shop.cpp
@@ -23,8 +23,6 @@
#include "../utils/dtor.h"
-#include <algorithm>
-
ShopItems::~ShopItems()
{
clear();
@@ -59,7 +57,7 @@ ShopItem* ShopItems::at(int i) const
void ShopItems::clear()
{
- std::for_each(mShopItems.begin(), mShopItems.end(), make_dtor(mShopItems));
+ delete_all(mShopItems);
mShopItems.clear();
}
diff --git a/src/gui/shop.h b/src/gui/shop.h
index 915ddd15..97b8d173 100644
--- a/src/gui/shop.h
+++ b/src/gui/shop.h
@@ -27,10 +27,11 @@
#include <guichan/listmodel.hpp>
-#include "../resources/image.h"
-
+#include "../guichanfwd.h"
#include "../shopitem.h"
+#include "../resources/image.h"
+
class ShopItems : public gcn::ListModel
{
public:
diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp
index bce6a48c..e31eee58 100644
--- a/src/gui/shoplistbox.cpp
+++ b/src/gui/shoplistbox.cpp
@@ -19,14 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "shoplistbox.h"
-
+#include <guichan/basiccontainer.hpp>
#include <guichan/font.hpp>
#include <guichan/graphics.hpp>
+#include <guichan/imagefont.hpp>
#include <guichan/listmodel.hpp>
#include <guichan/mouseinput.hpp>
-#include <guichan/imagefont.hpp>
-#include <guichan/basiccontainer.hpp>
+
+#include "shoplistbox.h"
#include "../graphics.h"
diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h
index 75f514ab..e856c076 100644
--- a/src/gui/shoplistbox.h
+++ b/src/gui/shoplistbox.h
@@ -25,6 +25,8 @@
#include "listbox.h"
#include "shop.h"
+#include "../guichanfwd.h"
+
/**
* A list box, meant to be used inside a scroll area. Same as the Guichan list
* box except this one doesn't have a background, instead completely relying
diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp
index a7b598eb..8e61dea4 100644
--- a/src/gui/skill.cpp
+++ b/src/gui/skill.cpp
@@ -23,18 +23,16 @@
#include <guichan/widgets/label.hpp>
-#include "skill.h"
-
#include "button.h"
#include "listbox.h"
-#include "scrollarea.h"
+#include "skill.h"
#include "windowcontainer.h"
#include "../localplayer.h"
+#include "../log.h"
#include "../utils/dtor.h"
#include "../utils/xml.h"
-#include "../log.h"
#define SKILLS_FILE "skills.xml"
@@ -79,7 +77,7 @@ public:
virtual void
update(void)
{
- static const SkillInfo fakeSkillInfo = { "Mystery Skill", false };
+ static const SkillInfo fakeSkillInfo = { "???", false };
mEntriesNr = mDialog->getSkills().size();
resize();
@@ -130,7 +128,7 @@ SkillDialog::SkillDialog():
setDefaultSize(windowContainer->getWidth() - 255, 25, 240, 240);
// mSkillListBox = new ListBox(this);
- ScrollArea *skillScrollArea = new ScrollArea(&mTable);
+ skillScrollArea = new ScrollArea(&mTable);
mPointsLabel = new gcn::Label("Skill Points:");
mIncButton = new Button("Up", "inc", this);
mUseButton = new Button("Use", "use", this);
diff --git a/src/gui/skill.h b/src/gui/skill.h
index bbd950cb..2095e098 100644
--- a/src/gui/skill.h
+++ b/src/gui/skill.h
@@ -24,9 +24,11 @@
#include <vector>
-#include <guichan/listmodel.hpp>
#include <guichan/actionlistener.hpp>
+#include <guichan/listmodel.hpp>
+#include "scrollarea.h"
+#include "table.h"
#include "window.h"
#include "table.h"
@@ -72,6 +74,7 @@ class SkillDialog : public Window, public gcn::ActionListener
private:
GuiTable mTable;//gcn::ListBox *mSkillListBox;
+ ScrollArea *skillScrollArea;
SkillGuiTableModel *mTableModel;
gcn::Label *mPointsLabel;
gcn::Button *mIncButton;
diff --git a/src/gui/slider.h b/src/gui/slider.h
index 3b796425..36bfe698 100644
--- a/src/gui/slider.h
+++ b/src/gui/slider.h
@@ -24,8 +24,9 @@
#include <guichan/widgets/slider.hpp>
-class Image;
+#include "../guichanfwd.h"
+class Image;
/**
* Slider widget. Same as the Guichan slider but with custom look.
diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp
new file mode 100644
index 00000000..6af16496
--- /dev/null
+++ b/src/gui/speechbubble.cpp
@@ -0,0 +1,93 @@
+/*
+ * The Legend of Mazzeroth
+ * Copyright (C) 2008, The Legend of Mazzeroth Development Team
+ *
+ * This file is part of The Legend of Mazzeroth based on original code
+ * from The Mana World.
+ *
+ * The Legend of Mazzeroth is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Legend of Mazzeroth is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Legend of Mazzeroth; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/font.hpp>
+
+#include "speechbubble.h"
+
+#include "../resources/image.h"
+#include "../resources/resourcemanager.h"
+
+// TODO: Fix windows so that they can each load their own skins without the
+// other windows overriding another window's skin.
+SpeechBubble::SpeechBubble():
+ Window("Message", false, NULL, "graphics/gui/speechbubble.xml")
+{
+ mSpeechBox = new TextBox();
+ mSpeechBox->setEditable(false);
+ mSpeechBox->setOpaque(false);
+
+ mSpeechArea = new ScrollArea(mSpeechBox);
+
+ // Height == Top Graphic (14px) + 1 Row of Text (15px) + Bottom Graphic (17px)
+ setContentSize(140, 46);
+ setTitleBarHeight(5);
+
+ mSpeechArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mSpeechArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER);
+ mSpeechArea->setDimension(gcn::Rectangle(4, 15, 130, 28));
+ mSpeechArea->setOpaque(false);
+
+ add(mSpeechArea);
+
+ setLocationRelativeTo(getParent());
+
+ // LEEOR / TODO: This causes an exception error.
+ //moveToBottom(getParent());
+
+ mSpeechBox->setTextWrapped( "" );
+}
+
+void SpeechBubble::setText(std::string mText)
+{
+ while (mText[0] == ' ')
+ {
+ mText = mText.substr(1, mText.size());
+ }
+
+ mSpeechBox->setMinWidth(140);
+ mSpeechBox->setTextWrapped( mText );
+
+ int numRows = mSpeechBox->getNumberOfRows();
+
+ if (numRows > 1)
+ {
+ // 15 == height of each line of text (based on font heights)
+ // 14 == speechbubble Top + Bottom graphic pixel heights
+ setContentSize(mSpeechBox->getMinWidth() + 15, 15 + (numRows * 15));
+ mSpeechArea->setDimension(gcn::Rectangle(4, 15, mSpeechBox->getMinWidth() + 5,
+ 3 +(numRows * 14)));
+ }
+ else
+ {
+ int width = getFont()->getWidth(this->getCaption());
+ if (width < getFont()->getWidth(mText))
+ width = getFont()->getWidth(mText);
+ setContentSize(width + 15, 30);
+ mSpeechArea->setDimension(gcn::Rectangle(4, 15, width + 5, 17));
+ }
+}
+
+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..9b8eab70
--- /dev/null
+++ b/src/gui/speechbubble.h
@@ -0,0 +1,45 @@
+/*
+ * The Legend of Mazzeroth
+ * Copyright (C) 2008, The Legend of Mazzeroth Development Team
+ *
+ * This file is part of The Legend of Mazzeroth based on original code
+ * from The Mana World.
+ *
+ * The Legend of Mazzeroth is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Legend of Mazzeroth is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Legend of Mazzeroth; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _LOM_SPEECHBUBBLE_H__
+#define _LOM_SPEECHBUBBLE_H__
+
+#include "scrollarea.h"
+#include "textbox.h"
+#include "window.h"
+
+class SpeechBubble : public Window
+{
+ public:
+
+ SpeechBubble();
+
+ void setText(std::string mText);
+ void setLocation(int x, int y);
+ unsigned int getNumRows();
+
+ private:
+ TextBox *mSpeechBox;
+ ScrollArea *mSpeechArea;
+};
+
+#endif
diff --git a/src/gui/status.cpp b/src/gui/status.cpp
index 1a257ae8..fbcc01d6 100644
--- a/src/gui/status.cpp
+++ b/src/gui/status.cpp
@@ -19,12 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "status.h"
-
#include <guichan/widgets/label.hpp>
#include "button.h"
#include "progressbar.h"
+#include "status.h"
#include "windowcontainer.h"
#include "../localplayer.h"
@@ -36,7 +35,6 @@ StatusWindow::StatusWindow(LocalPlayer *player):
mPlayer(player)
{
setWindowName("Status");
- setResizable(true);
setCloseButton(true);
setDefaultSize((windowContainer->getWidth() - 365) / 2,
(windowContainer->getHeight() - 255) / 2, 365, 275);
diff --git a/src/gui/tabbedcontainer.cpp b/src/gui/tabbedcontainer.cpp
index fba4e846..8e95aa7c 100644
--- a/src/gui/tabbedcontainer.cpp
+++ b/src/gui/tabbedcontainer.cpp
@@ -21,18 +21,23 @@
#include <algorithm>
-#include "tabbedcontainer.h"
-
#include "button.h"
+#include "tabbedcontainer.h"
-#include "../utils/tostring.h"
#include "../utils/dtor.h"
+#include "../utils/tostring.h"
-#define TABWIDTH 60
-#define TABHEIGHT 20
-
-TabbedContainer::TabbedContainer():
- mActiveContent(0)
+TabbedContainer::TabbedContainer(int width, int padX, int buttonHeight,
+ int height, int padY, int buttonsPerRow):
+ mActiveContent(0),
+ mWidth(width),
+ mPadX(padX),
+ mButtonHeight(buttonHeight),
+ mHeight(height),
+ mPadY(padY),
+ mButtonsPerRow(buttonsPerRow),
+
+ mButtonWidth((width - (buttonsPerRow - 1) * padX) / buttonsPerRow - padX)
{
}
@@ -50,13 +55,14 @@ void TabbedContainer::addTab(gcn::Widget *widget, const std::string &caption)
Button *tab = new Button(caption, toString(tabNumber), this);
- tab->setSize(TABWIDTH, TABHEIGHT);
- add(tab, TABWIDTH * tabNumber, 0);
+ tab->setSize(mButtonWidth, mButtonHeight);
+ add(tab, (mButtonWidth + mPadX) * (tabNumber % mButtonsPerRow),
+ (mButtonHeight + mPadY) * (tabNumber / mButtonsPerRow));
mTabs[caption] = tab;
mContents.push_back(widget);
- widget->setPosition(0, TABHEIGHT);
+ widget->setPosition(0, mHeight);
// If this is the first tab in this container, make it visible
if (!mActiveContent) {
@@ -81,7 +87,7 @@ void TabbedContainer::logic()
if (mActiveContent) {
mActiveContent->setSize(
getWidth() - 2 * mActiveContent->getFrameSize(),
- getHeight() - TABHEIGHT - 2 * mActiveContent->getFrameSize());
+ getHeight() - mHeight - 2 * mActiveContent->getFrameSize());
}
Container::logic();
diff --git a/src/gui/tabbedcontainer.h b/src/gui/tabbedcontainer.h
index babf68a2..2fc41247 100644
--- a/src/gui/tabbedcontainer.h
+++ b/src/gui/tabbedcontainer.h
@@ -23,8 +23,8 @@
#define _TMW_TABPANE_H
#include <iosfwd>
-#include <vector>
#include <map>
+#include <vector>
#include <guichan/actionlistener.hpp>
@@ -35,7 +35,8 @@
class TabbedContainer : public gcn::Container, public gcn::ActionListener
{
public:
- TabbedContainer();
+ TabbedContainer(int width, int padX, int buttonHeight,
+ int height, int padY, int buttonsPerRow);
~TabbedContainer();
void addTab(gcn::Widget *widget, const std::string &caption);
@@ -60,6 +61,14 @@ class TabbedContainer : public gcn::Container, public gcn::ActionListener
std::map<gcn::Widget*, std::string> mWidgets;
gcn::Widget *mActiveContent;
+
+ int mWidth; /**< The total width of all buttons */
+ int mPadX; /**< The horizontal gap between buttons */
+ int mButtonHeight; /**< The height of each button */
+ int mHeight; /**< Height of the panel */
+ int mPadY; /**< The vertical gap between buttons */
+ int mButtonsPerRow; /**< The number of buttons on each row */
+ int mButtonWidth; /**< The width of each button */
};
#endif
diff --git a/src/gui/table.cpp b/src/gui/table.cpp
index bddfbfed..e4d7812e 100644
--- a/src/gui/table.cpp
+++ b/src/gui/table.cpp
@@ -19,12 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/graphics.hpp>
-#include <guichan/actionlistener.hpp>
-#include "table.h"
#include <cassert>
+#include <guichan/graphics.hpp>
+#include <guichan/actionlistener.hpp>
+#include "table.h"
class GuiTableActionListener : public gcn::ActionListener
{
@@ -102,6 +102,7 @@ GuiTable::setModel(TableModel *new_model)
mModel->removeListener(this);
}
+
mModel = new_model;
installActionListeners();
diff --git a/src/gui/table.h b/src/gui/table.h
index cef82d5d..b4c607ae 100644
--- a/src/gui/table.h
+++ b/src/gui/table.h
@@ -31,6 +31,7 @@
#include <guichan/widget.hpp>
#include "table_model.h"
+
#include "../guichanfwd.h"
class GuiTableActionListener;
diff --git a/src/gui/table_model.cpp b/src/gui/table_model.cpp
index 57da29d9..e1afef96 100644
--- a/src/gui/table_model.cpp
+++ b/src/gui/table_model.cpp
@@ -19,8 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <guichan/widget.hpp>
#include <cstdlib>
+
+#include <guichan/widget.hpp>
+
#include "table_model.h"
void
diff --git a/src/gui/table_model.h b/src/gui/table_model.h
index 4be4e60e..a52a7561 100644
--- a/src/gui/table_model.h
+++ b/src/gui/table_model.h
@@ -22,9 +22,11 @@
#ifndef TMW_TABLE_MODEL_H_
#define TMW_TABLE_MODEL_H_
-#include <guichan/gui.hpp>
#include <set>
#include <vector>
+
+#include <guichan/gui.hpp>
+
#include "../guichanfwd.h"
class TableModelListener
diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp
index 619265ec..d7b589fa 100644
--- a/src/gui/textbox.cpp
+++ b/src/gui/textbox.cpp
@@ -19,13 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "textbox.h"
-
#include <sstream>
#include <guichan/basiccontainer.hpp>
#include <guichan/font.hpp>
+#include "textbox.h"
+
TextBox::TextBox():
gcn::TextBox()
{
@@ -43,6 +43,8 @@ void TextBox::setTextWrapped(const std::string &text)
std::stringstream wrappedStream;
std::string::size_type newlinePos, lastNewlinePos = 0;
+ int minWidth = 0;
+ int xpos;
do
{
@@ -57,7 +59,7 @@ void TextBox::setTextWrapped(const std::string &text)
std::string line =
text.substr(lastNewlinePos, newlinePos - lastNewlinePos);
std::string::size_type spacePos, lastSpacePos = 0;
- int xpos = 0;
+ xpos = 0;
do
{
@@ -73,7 +75,7 @@ void TextBox::setTextWrapped(const std::string &text)
int width = getFont()->getWidth(word);
- if (xpos != 0 && xpos + width < getWidth())
+ if (xpos != 0 && xpos + width + getFont()->getWidth(" ") <= mMinWidth)
{
xpos += width + getFont()->getWidth(" ");
wrappedStream << " " << word;
@@ -85,10 +87,30 @@ void TextBox::setTextWrapped(const std::string &text)
}
else
{
+ if (xpos > minWidth)
+ {
+ minWidth = xpos;
+ }
+ // The window wasn't big enough. Resize it and try again.
+ if (minWidth > mMinWidth)
+ {
+ mMinWidth = minWidth;
+ wrappedStream.clear();
+ wrappedStream.str("");
+ spacePos = 0;
+ lastNewlinePos = 0;
+ newlinePos = text.find("\n", lastNewlinePos);
+ line = text.substr(lastNewlinePos, newlinePos -
+ lastNewlinePos);
+ width = 0;
+ break;
+ }
+ else
+ {
+ wrappedStream << "\n" << word;
+ }
xpos = width;
- wrappedStream << "\n" << word;
}
-
lastSpacePos = spacePos + 1;
}
while (spacePos != line.size());
@@ -97,10 +119,15 @@ void TextBox::setTextWrapped(const std::string &text)
{
wrappedStream << "\n";
}
-
lastNewlinePos = newlinePos + 1;
}
while (newlinePos != text.size());
+ if (xpos > minWidth)
+ {
+ minWidth = xpos;
+ }
+ mMinWidth = minWidth;
+
gcn::TextBox::setText(wrappedStream.str());
}
diff --git a/src/gui/textbox.h b/src/gui/textbox.h
index 2060e377..a0f0f947 100644
--- a/src/gui/textbox.h
+++ b/src/gui/textbox.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/textbox.hpp>
+#include "../guichanfwd.h"
+
/**
* A text box, meant to be used inside a scroll area. Same as the Guichan text
* box except this one doesn't have a background or border, instead completely
@@ -42,6 +44,19 @@ class TextBox : public gcn::TextBox {
* Sets the text after wrapping it to the current width of the widget.
*/
void setTextWrapped(const std::string &text);
+
+ /**
+ * Get the minimum text width for the text box.
+ */
+ int getMinWidth() { return mMinWidth; }
+
+ /**
+ * Set the minimum text width for the text box.
+ */
+ void setMinWidth(int width) { mMinWidth = width; }
+
+ private:
+ int mMinWidth;
};
#endif
diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp
index ea82ba77..bd016a8d 100644
--- a/src/gui/textfield.cpp
+++ b/src/gui/textfield.cpp
@@ -23,6 +23,8 @@
#include <guichan/font.hpp>
+#include <guichan/sdl/sdlinput.hpp>
+
#include "textfield.h"
#include "../graphics.h"
@@ -36,7 +38,9 @@ int TextField::instances = 0;
ImageRect TextField::skin;
TextField::TextField(const std::string& text):
- gcn::TextField(text)
+ gcn::TextField(text),
+ mNumeric(false),
+ mListener(0)
{
setFrameSize(2);
@@ -100,3 +104,67 @@ 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;
+ }
+ }
+}
+
+void TextField::keyPressed(gcn::KeyEvent &keyEvent)
+{
+ if (mNumeric)
+ {
+ while (true)
+ {
+ const gcn::Key &key = keyEvent.getKey();
+ if (key.isNumber())
+ {
+ break;
+ }
+ int value = key.getValue();
+ if (value == SDLK_LEFT || value == SDLK_RIGHT ||
+ value == SDLK_HOME || value == SDLK_END ||
+ value == SDLK_BACKSPACE || value == SDLK_DELETE)
+ {
+ break;
+ }
+ return;
+ }
+ }
+ gcn::TextField::keyPressed(keyEvent);
+ if (mListener)
+ {
+ mListener->listen(this);
+ }
+}
+
+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;
+}
diff --git a/src/gui/textfield.h b/src/gui/textfield.h
index 60a50c69..6def784d 100644
--- a/src/gui/textfield.h
+++ b/src/gui/textfield.h
@@ -24,8 +24,18 @@
#include <guichan/widgets/textfield.hpp>
+#include "../guichanfwd.h"
+
class ImageRect;
+class TextField;
+
+class TextFieldListener
+{
+ public:
+ virtual void listen(const TextField *value) = 0;
+};
+
/**
* A text field.
*
@@ -53,9 +63,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; }
+
+ /**
+ * Restrict keyboard input if numeric
+ */
+ void keyPressed(gcn::KeyEvent &keyEvent);
+
+ /**
+ * Set the minimum value for a range
+ */
+ void setMinimum(int min) {mMinimum = min; }
+
+ /**
+ * Set the maximum value for a range
+ */
+ void setMaximum(int max) {mMaximum = max; }
+
+ /**
+ * Return the value for a numeric field
+ */
+ int getValue() const;
+
+ /**
+ * Add a listener
+ */
+ void addListener(TextFieldListener *listener) {mListener = listener; }
+
private:
static int instances;
static ImageRect skin;
+ bool mNumeric;
+ int mMinimum;
+ int mMaximum;
+ TextFieldListener *mListener;
};
#endif
diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp
index 9cb0d34f..8c02ab01 100644
--- a/src/gui/trade.cpp
+++ b/src/gui/trade.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "trade.h"
-
#include <sstream>
#include <guichan/widgets/label.hpp>
@@ -32,9 +30,11 @@
#include "itemcontainer.h"
#include "scrollarea.h"
#include "textfield.h"
+#include "trade.h"
#include "../inventory.h"
#include "../item.h"
+#include "../localplayer.h"
#include "../net/messageout.h"
#include "../net/protocol.h"
@@ -46,8 +46,8 @@
TradeWindow::TradeWindow(Network *network):
Window("Trade: You"),
mNetwork(network),
- mMyInventory(new Inventory()),
- mPartnerInventory(new Inventory())
+ mMyInventory(new Inventory(INVENTORY_SIZE)),
+ mPartnerInventory(new Inventory(INVENTORY_SIZE))
{
setWindowName("Trade");
setDefaultSize(115, 197, 332, 209);
@@ -57,14 +57,14 @@ TradeWindow::TradeWindow(Network *network):
mCancelButton = new Button("Cancel", "cancel", this);
mTradeButton = new Button("Trade", "trade", this);
- mMyItemContainer = new ItemContainer(mMyInventory.get());
+ mMyItemContainer = new ItemContainer(mMyInventory.get(), 2);
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->addSelectionListener(this);
mPartnerItemContainer->setPosition(2, 58);
diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp
index 7f7d45fc..36d00bec 100644
--- a/src/gui/updatewindow.cpp
+++ b/src/gui/updatewindow.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "updatewindow.h"
-
#include <iostream>
#include <SDL.h>
#include <SDL_thread.h>
@@ -32,6 +30,7 @@
#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>
@@ -40,10 +39,10 @@
#include "../log.h"
#include "../main.h"
-#include "../utils/tostring.h"
-
#include "../resources/resourcemanager.h"
+#include "../utils/tostring.h"
+
/**
* Calculates the Alder-32 checksum for the given file.
*/
@@ -113,7 +112,7 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost,
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, w - 10, 20, 168, 116, 31);
mCancelButton = new Button("Cancel", "cancel", this);
mPlayButton = new Button("Play", "play", this);
diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h
index a7dfe2cb..9cd3405e 100644
--- a/src/gui/updatewindow.h
+++ b/src/gui/updatewindow.h
@@ -23,6 +23,7 @@
#define _UPDATERWINDOW_H
#include <guichan/actionlistener.hpp>
+
#include <string>
#include <vector>
diff --git a/src/gui/vbox.h b/src/gui/vbox.h
index 2072ab24..4538338f 100644
--- a/src/gui/vbox.h
+++ b/src/gui/vbox.h
@@ -24,6 +24,8 @@
#include "box.h"
+#include "../guichanfwd.h"
+
class VBox : public Box
{
public:
diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp
index 37e7bcce..e50903b6 100644
--- a/src/gui/viewport.cpp
+++ b/src/gui/viewport.cpp
@@ -19,18 +19,19 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "viewport.h"
+#include <cassert>
#include <guichan/sdl/sdlinput.hpp>
#include "gui.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"
@@ -38,14 +39,14 @@
#include "../textmanager.h"
#include "../resources/animation.h"
-#include "../resources/monsterinfo.h"
-#include "../resources/resourcemanager.h"
#include "../resources/image.h"
#include "../resources/imageset.h"
+#include "../resources/monsterinfo.h"
+#include "../resources/resourcemanager.h"
#include "../utils/tostring.h"
-#include <cassert>
+extern volatile int tick_time;
extern volatile int tick_time;
@@ -71,64 +72,11 @@ 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
@@ -224,34 +172,29 @@ 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);
+ }
}
}
@@ -272,8 +215,7 @@ Viewport::draw(gcn::Graphics *gcnGraphics)
WindowContainer::draw(gcnGraphics);
}
-void
-Viewport::logic()
+void Viewport::logic()
{
WindowContainer::logic();
@@ -290,49 +232,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)
@@ -344,8 +246,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)
@@ -353,11 +257,11 @@ Viewport::mousePressed(gcn::MouseEvent &event)
Being *being;
FloorItem *floorItem;
- if ((being = beingManager->findBeing(tilex, tiley)) &&
- being != player_node)
+ if ((being = beingManager->findBeingByPixel(x, y)) &&
+ being != player_node)
{
- mPopupMenu->showPopup(event.getX(), event.getY(), being);
- return;
+ mPopupMenu->showPopup(event.getX(), event.getY(), being);
+ return;
}
else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley)))
{
@@ -378,11 +282,9 @@ Viewport::mousePressed(gcn::MouseEvent &event)
{
Being *being;
FloorItem *item;
-
+
// Interact with some being
-// if ((being = beingManager->findBeing(tilex, tiley))
- int x = (int)((float) event.getX() + mPixelViewX);
- int y = (int)((float) event.getY() + mPixelViewY);
+// if ((being = beingManager->findBeing(tilex, tiley)))
if ((being = beingManager->findBeingByPixel(x, y)))
{
switch (being->getType())
@@ -396,59 +298,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;
@@ -461,20 +351,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 707ad33b..3120de91 100644
--- a/src/gui/viewport.h
+++ b/src/gui/viewport.h
@@ -26,8 +26,9 @@
#include "windowcontainer.h"
-#include "../configlistener.h"
#include "../being.h"
+#include "../configlistener.h"
+#include "../guichanfwd.h"
class Map;
class FloorItem;
@@ -35,7 +36,6 @@ class ImageSet;
class Item;
class PopupMenu;
class Graphics;
-class SimpleAnimation;
/**
* The viewport on the map. Displays the current map and handles mouse input
@@ -115,16 +115,16 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
optionChanged(const std::string &name);
/**
- * Returns camera x offset in tiles.
+ * Returns camera x offset in pixels.
*/
int
- getCameraX() { return mTileViewX; }
+ getCameraX() const { return (int) mPixelViewX; }
/**
- * Returns camera y offset in tiles.
+ * Returns camera y offset in pixels.
*/
int
- getCameraY() { return mTileViewY; }
+ getCameraY() const { return (int) mPixelViewY; }
/**
* Changes viewpoint by relative pixel coordinates.
@@ -133,26 +133,6 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; }
private:
- /**
- * Helper function for loading target cursors
- */
- void
- loadTargetCursor(std::string filename, int width, int height,
- bool outRange, Being::TargetCursorSize size);
-
- /**
- * Draws range based target cursor
- */
- void
- drawTargetCursor(Graphics *graphics);
-
- /**
- * Draws target name
- */
- void
- drawTargetName(Graphics *graphics);
-
-
Map *mMap; /**< The current map. */
int mScrollRadius;
@@ -165,18 +145,6 @@ class Viewport : public WindowContainer, public gcn::MouseListener,
int mTileViewY; /**< Current viewpoint in tiles. */
bool mShowDebugPath; /**< Show a path from player to pointer. */
- /** Images of in range target cursor. */
- ImageSet *mInRangeImages[Being::NUM_TC];
-
- /** Images of out of range target cursor. */
- ImageSet *mOutRangeImages[Being::NUM_TC];
-
- /** Animated in range target cursor. */
- SimpleAnimation *mTargetCursorInRange[Being::NUM_TC];
-
- /** Animated out of range target cursor. */
- SimpleAnimation *mTargetCursorOutRange[Being::NUM_TC];
-
bool mPlayerFollowMouse;
int mWalkTime;
diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp
new file mode 100644
index 00000000..88a12d68
--- /dev/null
+++ b/src/gui/widgets/dropdown.cpp
@@ -0,0 +1,167 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <algorithm>
+
+#include "dropdown.h"
+
+#include "../../graphics.h"
+
+#include "../../resources/image.h"
+#include "../../resources/resourcemanager.h"
+
+#include "../../utils/dtor.h"
+
+int DropDown::instances = 0;
+Image *DropDown::buttons[2][2];
+ImageRect DropDown::skin;
+
+DropDown::DropDown(gcn::ListModel *listModel,
+ gcn::ScrollArea *scrollArea,
+ gcn::ListBox *listBox):
+ gcn::DropDown::DropDown(listModel,
+ scrollArea, listBox)
+{
+ setFrameSize(2);
+
+ // Initialize graphics
+ if (instances == 0)
+ {
+ // Load the background skin
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ // Get the button skin
+ buttons[1][0] =
+ resman->getImage("graphics/gui/vscroll_up_default.png");
+ buttons[0][0] =
+ resman->getImage("graphics/gui/vscroll_down_default.png");
+ buttons[1][1] =
+ resman->getImage("graphics/gui/vscroll_up_pressed.png");
+ buttons[0][1] =
+ resman->getImage("graphics/gui/vscroll_down_pressed.png");
+
+ // get the border skin
+ Image *boxBorder = resman->getImage("graphics/gui/deepbox.png");
+ int gridx[4] = {0, 3, 28, 31};
+ int gridy[4] = {0, 3, 28, 31};
+ int a = 0, x, y;
+
+ for (y = 0; y < 3; y++) {
+ for (x = 0; x < 3; x++) {
+ skin.grid[a] = boxBorder->getSubImage(
+ gridx[x], gridy[y],
+ gridx[x + 1] - gridx[x] + 1,
+ gridy[y + 1] - gridy[y] + 1);
+ a++;
+ }
+ }
+
+ boxBorder->decRef();
+ }
+
+ instances++;
+}
+
+DropDown::~DropDown()
+{
+ instances--;
+ // Free images memory
+ if (instances == 0)
+ {
+ buttons[0][0]->decRef();
+ buttons[0][1]->decRef();
+ buttons[1][0]->decRef();
+ buttons[1][1]->decRef();
+
+ for_each(skin.grid, skin.grid + 9, dtor<Image*>());
+ }
+}
+
+void DropDown::draw(gcn::Graphics* graphics)
+{
+ int h;
+
+ if (mDroppedDown)
+ {
+ h = mFoldedUpHeight;
+ }
+ else
+ {
+ h = getHeight();
+ }
+
+ int alpha = getBaseColor().a;
+ gcn::Color faceColor = getBaseColor();
+ faceColor.a = alpha;
+ gcn::Color highlightColor = faceColor + 0x303030;
+ highlightColor.a = alpha;
+ gcn::Color shadowColor = faceColor - 0x303030;
+ shadowColor.a = alpha;
+
+
+ graphics->setColor(getBackgroundColor());
+ graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h));
+
+ graphics->setColor(getForegroundColor());
+ graphics->setFont(getFont());
+
+ if (mListBox->getListModel() && mListBox->getSelected() >= 0)
+ {
+ graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0);
+ }
+
+ if (isFocused())
+ {
+ graphics->setColor(highlightColor);
+ graphics->drawRectangle(gcn::Rectangle(0, 0, getWidth() - h, h));
+ }
+
+ drawButton(graphics);
+
+ if (mDroppedDown)
+ {
+ drawChildren(graphics);
+
+ // Draw two lines separating the ListBox with se selected
+ // element view.
+ graphics->setColor(highlightColor);
+ graphics->drawLine(0, h, getWidth(), h);
+ graphics->setColor(shadowColor);
+ graphics->drawLine(0, h + 1, getWidth(), h + 1);
+ }
+}
+
+void DropDown::drawFrame(gcn::Graphics *graphics)
+{
+ const int bs = getFrameSize();
+ const int w = getWidth() + bs * 2;
+ const int h = getHeight() + bs * 2;
+
+ static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin);
+}
+
+void DropDown::drawButton(gcn::Graphics *graphics)
+{
+ int height = mDroppedDown ? mFoldedUpHeight : getHeight();
+
+ static_cast<Graphics*>(graphics)->
+ drawImage(buttons[mDroppedDown][mPushed], getWidth() - height + 2, 1);
+}
diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h
new file mode 100644
index 00000000..25ae05f8
--- /dev/null
+++ b/src/gui/widgets/dropdown.h
@@ -0,0 +1,86 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef DROPDOWN_H
+#define DROPDOWN_H
+
+#include <iosfwd>
+
+#include <guichan/widgets/dropdown.hpp>
+
+#include "../listbox.h"
+#include "../scrollarea.h"
+
+#include "../../guichanfwd.h"
+
+class Image;
+class ImageRect;
+
+ /**
+ * A drop down box from which you can select different values. It is one of
+ * the most complicated Widgets you will find in Guichan. For drawing the
+ * DroppedDown box it uses one ScrollArea and one ListBox. It also uses an
+ * internal FocusHandler to handle the focus of the internal ScollArea and
+ * ListBox. DropDown uses a ListModel to handle the list. To be able to use
+ * DropDown you must give DropDown an implemented ListModel which represents
+ * your list.
+ */
+class DropDown : public gcn::DropDown
+{
+ public:
+ /**
+ * Contructor.
+ *
+ * @param listModel the ListModel to use.
+ * @param scrollArea the ScrollArea to use.
+ * @param listBox the listBox to use.
+ * @see ListModel, ScrollArea, ListBox.
+ */
+ DropDown(gcn::ListModel *listModel = NULL,
+ gcn::ScrollArea *scrollArea = NULL,
+ gcn::ListBox *listBox = NULL);
+
+ /**
+ * Destructor.
+ */
+ ~DropDown();
+
+ void draw(gcn::Graphics* graphics);
+
+ void drawFrame(gcn::Graphics* graphics);
+
+
+ protected:
+ /**
+ * Draws the button with the little down arrow.
+ *
+ * @param graphics a Graphics object to draw with.
+ */
+ void drawButton(gcn::Graphics *graphics);
+
+ // Add own Images.
+ static int instances;
+ static Image *buttons[2][2];
+ static ImageRect skin;
+};
+
+#endif // end DROPDOWN_H
+
diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp
index c3b537db..87527f0a 100644
--- a/src/gui/widgets/resizegrip.cpp
+++ b/src/gui/widgets/resizegrip.cpp
@@ -19,10 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "resizegrip.h"
-
#include <guichan/graphics.hpp>
+#include "resizegrip.h"
+
#include "../../graphics.h"
#include "../../resources/image.h"
@@ -31,13 +31,13 @@
Image *ResizeGrip::gripImage = 0;
int ResizeGrip::mInstances = 0;
-ResizeGrip::ResizeGrip()
+ResizeGrip::ResizeGrip(std::string image)
{
if (mInstances == 0)
{
// Load the grip image
ResourceManager *resman = ResourceManager::getInstance();
- gripImage = resman->getImage("graphics/gui/resize.png");
+ gripImage = resman->getImage(image);
}
mInstances++;
diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h
index f57eda94..acb934d2 100644
--- a/src/gui/widgets/resizegrip.h
+++ b/src/gui/widgets/resizegrip.h
@@ -24,6 +24,8 @@
#include <guichan/widget.hpp>
+#include "../../guichanfwd.h"
+
class Image;
/**
@@ -39,7 +41,7 @@ class ResizeGrip : public gcn::Widget
/**
* Constructor.
*/
- ResizeGrip();
+ ResizeGrip(std::string image = "graphics/gui/resize.png");
/**
* Destructor.
diff --git a/src/gui/window.cpp b/src/gui/window.cpp
index 58544f7e..30456a81 100644
--- a/src/gui/window.cpp
+++ b/src/gui/window.cpp
@@ -20,16 +20,17 @@
*/
#include <algorithm>
+#include <cassert>
#include <climits>
#include <cassert>
#include <guichan/exception.hpp>
-#include <guichan/widgets/icon.hpp>
-#include "window.h"
+#include <guichan/widgets/icon.hpp>
#include "gui.h"
#include "gccontainer.h"
+#include "window.h"
#include "windowcontainer.h"
#include "widgets/resizegrip.h"
@@ -42,24 +43,28 @@
#include "../resources/image.h"
#include "../resources/resourcemanager.h"
+#include "../utils/xml.h"
+
ConfigListener *Window::windowConfigListener = 0;
WindowContainer *Window::windowContainer = 0;
int Window::instances = 0;
int Window::mouseResize = 0;
-ImageRect Window::border;
+//ImageRect Window::border;
Image *Window::closeImage = NULL;
+bool Window::mAlphaChanged = false;
class WindowConfigListener : public ConfigListener
{
void optionChanged(const std::string &)
{
- for_each(Window::border.grid, Window::border.grid + 9,
- std::bind2nd(std::mem_fun(&Image::setAlpha),
- config.getValue("guialpha", 0.8)));
+ Window::mAlphaChanged = true;
+// for_each(Window::border.grid, Window::border.grid + 9,
+// std::bind2nd(std::mem_fun(&Image::setAlpha),
+// config.getValue("guialpha", 0.8)));
}
};
-Window::Window(const std::string& caption, bool modal, Window *parent):
+Window::Window(const std::string& caption, bool modal, Window *parent, const std::string& skin):
gcn::Window(caption),
mGrip(0),
mParent(parent),
@@ -71,7 +76,8 @@ 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());
@@ -79,23 +85,13 @@ Window::Window(const std::string& caption, bool modal, Window *parent):
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");
@@ -147,22 +143,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();
}
@@ -537,3 +530,185 @@ int Window::getResizeHandles(gcn::MouseEvent &event)
return resizeHandles;
}
+
+void Window::setGuiAlpha()
+{
+ //logger->log("Window::setGuiAlpha: Alpha Value %f", config.getValue("guialpha", 0.8));
+ for(int i = 0; i < 9; i++)
+ {
+ //logger->log("Window::setGuiAlpha: Border Image (%i)", i);
+ border.grid[i]->setAlpha(config.getValue("guialpha", 0.8));
+ }
+
+ mAlphaChanged = false;
+}
+
+void Window::loadSkin(const std::string filename)
+{
+ const std::string windowId = Window::getId();
+
+ ResourceManager *resman = ResourceManager::getInstance();
+
+ logger->log("Loading Window Skin '%s'.", filename.c_str());
+ logger->log("Loading Window ID '%s'.", windowId.c_str());
+
+
+ if(filename == "")
+ logger->error("Window::loadSkin(): Invalid File Name.");
+
+ // TODO:
+ // If there is an error loading the specified file, we should try to revert
+ // to a 'default' skin file. Only if the 'default' skin file can't be loaded
+ // should we have a terminating error.
+ XML::Document doc(filename);
+ xmlNodePtr rootNode = doc.rootNode();
+
+ if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skinset"))
+ {
+ logger->error("Widget Skinning error");
+ }
+
+ std::string skinSetImage;
+ skinSetImage = XML::getProperty(rootNode, "image", "");
+ Image *dBorders = NULL;
+ if(skinSetImage != "")
+ {
+ logger->log("Window::loadSkin(): <skinset> defines '%s' as a skin image.", skinSetImage.c_str());
+ dBorders = resman->getImage("graphics/gui/" + skinSetImage);//"graphics/gui/speech_bubble.png");
+ }
+ else
+ {
+ logger->error("Window::loadSkin(): Skinset does not define an image!");
+ }
+
+ //iterate <widget>'s
+ for_each_xml_child_node(widgetNode, rootNode)
+ {
+ if (!xmlStrEqual(widgetNode->name, BAD_CAST "widget"))
+ continue;
+
+ std::string widgetType;
+ widgetType = XML::getProperty(widgetNode, "type", "unknown");
+ if (widgetType == "Window")
+ {
+ // Iterate through <part>'s
+ // LEEOR / TODO:
+ // We need to make provisions to load in a CloseButton image. For now it
+ // can just be hard-coded.
+ for_each_xml_child_node(partNode, widgetNode)
+ {
+ if (!xmlStrEqual(partNode->name, BAD_CAST "part"))
+ {
+ continue;
+ }
+
+ std::string partType;
+ partType = XML::getProperty(partNode, "type", "unknown");
+ // TOP ROW
+ if(partType == "top-left-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[0] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "top-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[1] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "top-right-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[2] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // MIDDLE ROW
+ else if(partType == "left-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[3] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bg-quad")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[4] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "right-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[5] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // BOTTOM ROW
+ else if(partType == "bottom-left-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[6] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bottom-edge")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[7] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+ else if(partType == "bottom-right-corner")
+ {
+ const int xPos = XML::getProperty(partNode, "xpos", 0);
+ const int yPos = XML::getProperty(partNode, "ypos", 0);
+ const int width = XML::getProperty(partNode, "width", 1);
+ const int height = XML::getProperty(partNode, "height", 1);
+
+ border.grid[8] = dBorders->getSubImage(xPos, yPos, width, height);
+ }
+
+ // Part is of an uknown type.
+ else
+ {
+ logger->log("Window::loadSkin(): Unknown Part Type '%s'", partType.c_str());
+ }
+ }
+ }
+ // Widget is of an uknown type.
+ else
+ {
+ logger->log("Window::loadSkin(): Unknown Widget Type '%s'", widgetType.c_str());
+ }
+ }
+ dBorders->decRef();
+
+ logger->log("Finished loading Window Skin.");
+
+ // Hard-coded for now until we update the above code to look for window buttons.
+ closeImage = resman->getImage("graphics/gui/close_button.png");
+}
+
diff --git a/src/gui/window.h b/src/gui/window.h
index 984c6f06..9380fc88 100644
--- a/src/gui/window.h
+++ b/src/gui/window.h
@@ -22,17 +22,17 @@
#ifndef _TMW_WINDOW_H__
#define _TMW_WINDOW_H__
-#include <guichan/widgets/window.hpp>
#include <guichan/widgetlistener.hpp>
+#include <guichan/widgets/window.hpp>
+
+#include "../graphics.h"
#include "../guichanfwd.h"
class ConfigListener;
class GCContainer;
-class ImageRect;
class ResizeGrip;
class WindowContainer;
-class Image;
/**
* A window. This window can be dragged around and has a title bar. Windows are
@@ -54,9 +54,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.
@@ -235,6 +236,11 @@ class Window : public gcn::Window, gcn::WidgetListener
*/
virtual void resetToDefaultSize();
+ /**
+ * Loads a window skin
+ */
+ void loadSkin(const std::string filename);
+
enum ResizeHandles
{
TOP = 0x01,
@@ -253,6 +259,8 @@ class Window : public gcn::Window, gcn::WidgetListener
*/
int getResizeHandles(gcn::MouseEvent &event);
+ void setGuiAlpha();
+
GCContainer *mChrome; /**< Contained container */
ResizeGrip *mGrip; /**< Resize grip */
Window *mParent; /**< The parent window */
@@ -261,6 +269,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 */
@@ -269,6 +278,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 window container windows add themselves to. */
static WindowContainer *windowContainer;
@@ -280,7 +290,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.cpp b/src/gui/windowcontainer.cpp
index f92e8388..d8535f73 100644
--- a/src/gui/windowcontainer.cpp
+++ b/src/gui/windowcontainer.cpp
@@ -19,15 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
-
#include "windowcontainer.h"
#include "../utils/dtor.h"
void WindowContainer::logic()
{
- for_each(mDeathList.begin(), mDeathList.end(), make_dtor(mDeathList));
+ delete_all(mDeathList);
mDeathList.clear();
gcn::Container::logic();
diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h
index 88a13d31..d783fefd 100644
--- a/src/gui/windowcontainer.h
+++ b/src/gui/windowcontainer.h
@@ -24,6 +24,8 @@
#include <guichan/widgets/container.hpp>
+#include "../guichanfwd.h"
+
/**
* A window container. This container adds functionality for more convenient
* widget (windows in particular) destruction.
diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp
index 65780345..6d74801e 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 58c75f2c..da9aed02 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "inventory.h"
-
#include <algorithm>
#include <cassert>
+#include "inventory.h"
#include "item.h"
#include "log.h"
@@ -34,15 +33,16 @@ struct SlotUsed : public std::unary_function<Item*, bool>
}
};
-Inventory::Inventory()
+Inventory::Inventory(int size):
+ mSize(size)
{
- mItems = new Item*[INVENTORY_SIZE];
- std::fill_n(mItems, INVENTORY_SIZE, (Item*) 0);
+ mItems = new Item*[mSize];
+ std::fill_n(mItems, mSize, (Item*) 0);
}
Inventory::~Inventory()
{
- for (int i = 0; i < INVENTORY_SIZE; i++)
+ for (int i = 0; i < mSize; i++)
delete mItems[i];
delete [] mItems;
@@ -58,7 +58,7 @@ Item* Inventory::getItem(int index) const
Item* Inventory::findItem(int itemId) const
{
- for (int i = 0; i < INVENTORY_SIZE; i++)
+ for (int i = 0; i < mSize; i++)
{
if (mItems[i] && mItems[i]->getId() == itemId)
return mItems[i];
@@ -73,19 +73,11 @@ void Inventory::addItem(int id, int quantity, bool equipment)
void Inventory::setItem(int index, int id, int quantity, bool equipment)
{
- if (index < 0 || index >= INVENTORY_SIZE) {
+ if (index < 0 || index >= mSize) {
logger->log("Warning: invalid inventory index: %d", index);
return;
}
- /* TODO: Check where to reenable this code.
- // Dont stack equipment other than arrows.
- if (equipment && !(id == 1199 || id == 529))
- mItems[index].setQuantity(quantity);
- else
- mItems[index].increaseQuantity(quantity);
- */
-
if (!mItems[index] && id > 0) {
Item *item = new Item(id, quantity, equipment);
item->setInvIndex(index);
@@ -101,14 +93,14 @@ void Inventory::setItem(int index, int id, int quantity, bool equipment)
void Inventory::clear()
{
- for (int i = 0; i < INVENTORY_SIZE; i++) {
+ for (int i = 0; i < mSize; i++) {
removeItemAt(i);
}
}
void Inventory::removeItem(int id)
{
- for (int i = 0; i < INVENTORY_SIZE; i++) {
+ for (int i = 0; i < mSize; i++) {
if (mItems[i] && mItems[i]->getId() == id) {
removeItemAt(i);
}
@@ -123,7 +115,7 @@ void Inventory::removeItemAt(int index)
bool Inventory::contains(Item *item) const
{
- for (int i = 0; i < INVENTORY_SIZE; i++) {
+ for (int i = 0; i < mSize; i++) {
if (mItems[i] && mItems[i]->getId() == item->getId()) {
return true;
}
@@ -134,19 +126,19 @@ bool Inventory::contains(Item *item) const
int Inventory::getFreeSlot() const
{
- Item **i = std::find_if(mItems + 2, mItems + INVENTORY_SIZE,
+ Item **i = std::find_if(mItems + 2, mItems + mSize,
std::not1(SlotUsed()));
- return (i == mItems + INVENTORY_SIZE) ? -1 : (i - mItems);
+ return (i == mItems + mSize) ? -1 : (i - mItems);
}
int Inventory::getNumberOfSlotsUsed() const
{
- return count_if(mItems, mItems + INVENTORY_SIZE, SlotUsed());
+ return count_if(mItems, mItems + mSize, SlotUsed());
}
int Inventory::getLastUsedSlot() const
{
- for (int i = INVENTORY_SIZE - 1; i >= 0; i--) {
+ for (int i = mSize - 1; i >= 0; i--) {
if (SlotUsed()(mItems[i])) {
return i;
}
diff --git a/src/inventory.h b/src/inventory.h
index 2fbbbf4c..91bb7d04 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/itemshortcut.cpp b/src/itemshortcut.cpp
index babe3dfb..cfe46238 100644
--- a/src/itemshortcut.cpp
+++ b/src/itemshortcut.cpp
@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "itemshortcut.h"
-
#include "configuration.h"
#include "inventory.h"
#include "item.h"
+#include "itemshortcut.h"
#include "localplayer.h"
#include "utils/tostring.h"
diff --git a/src/joystick.cpp b/src/joystick.cpp
index b05e9b5f..4cee4464 100644
--- a/src/joystick.cpp
+++ b/src/joystick.cpp
@@ -19,9 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "joystick.h"
+#include <cassert>
#include "configuration.h"
+#include "joystick.h"
#include "log.h"
#include <cassert>
diff --git a/src/joystick.h b/src/joystick.h
index ee029915..2baf3e61 100644
--- a/src/joystick.h
+++ b/src/joystick.h
@@ -30,7 +30,9 @@ class Joystick
/**
* Number of buttons we can handle.
*/
- enum { MAX_BUTTONS = 6 };
+ enum {
+ MAX_BUTTONS = 6
+ };
/**
* Directions, to be used as bitmask values.
diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp
index 19cbb945..f67c9534 100644
--- a/src/keyboardconfig.cpp
+++ b/src/keyboardconfig.cpp
@@ -19,12 +19,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "keyboardconfig.h"
+#include <guichan/sdl/sdlinput.hpp>
+
#include "configuration.h"
+#include "keyboardconfig.h"
#include "log.h"
-#include <guichan/sdl/sdlinput.hpp>
-
#include "gui/setup_keyboard.h"
struct KeyData
@@ -42,8 +42,10 @@ static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = {
{"keyMoveRight", SDLK_RIGHT, "Move Right"},
{"keyAttack", SDLK_LCTRL, "Attack"},
{"keySmilie", SDLK_LALT, "Smilie"},
- {"keyTarget", SDLK_LSHIFT, "Target"},
+ {"keyTalk", SDLK_t, "Talk"},
+ {"keyTarget", SDLK_LSHIFT, "Stop Attack"},
{"keyTargetClosest", SDLK_a, "Target Closest"},
+ {"keyTargetNPC", SDLK_n, "Target NPC"},
{"keyTargetPlayer", SDLK_q, "Target Player"},
{"keyPickup", SDLK_z, "Pickup"},
{"keyHideWindows", SDLK_h, "Hide Windows"},
diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h
index 9c5fe943..158252d4 100644
--- a/src/keyboardconfig.h
+++ b/src/keyboardconfig.h
@@ -24,10 +24,10 @@
#include <string>
-#include "gui/setup_keyboard.h"
-
#include <guichan/sdl/sdlinput.hpp>
+#include "gui/setup_keyboard.h"
+
/**
* Each key represents a key function. Such as 'Move up', 'Attack' etc.
*/
@@ -150,8 +150,10 @@ class KeyboardConfig
KEY_MOVE_RIGHT,
KEY_ATTACK,
KEY_SMILIE,
+ KEY_TALK,
KEY_TARGET,
KEY_TARGET_CLOSEST,
+ KEY_TARGET_NPC,
KEY_TARGET_PLAYER,
KEY_PICKUP,
KEY_HIDE_WINDOWS,
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index 3550b092..292f70e0 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -18,15 +18,16 @@
* 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 "localplayer.h"
+#include <cassert>
#include "equipment.h"
#include "floor_item.h"
#include "game.h"
#include "inventory.h"
#include "item.h"
+#include "localplayer.h"
#include "main.h"
+#include "monster.h"
#include "particle.h"
#include "sound.h"
#include "monster.h"
@@ -36,6 +37,9 @@
#include "net/messageout.h"
#include "net/protocol.h"
+#include "resources/imageset.h"
+#include "resources/resourcemanager.h"
+
#include "utils/tostring.h"
LocalPlayer *player_node = NULL;
@@ -48,20 +52,44 @@ LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map):
mXp(0), mNetwork(0),
mTarget(NULL), mPickUpTarget(NULL),
mTrading(false), mGoingToTarget(false),
- mLastAction(-1),
- mWalkingDir(0), mDestX(0), mDestY(0),
- mInventory(new Inventory)
+ mTargetTime(-1), mLastAction(-1),
+ mLastTarget(-1), mWalkingDir(0),
+ mDestX(0), mDestY(0),
+ mInventory(new Inventory(INVENTORY_SIZE)),
+ mStorage(new Inventory(STORAGE_SIZE))
{
+ initTargetCursor();
}
LocalPlayer::~LocalPlayer()
{
delete mInventory;
+ delete mStorage;
+
+ 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) {
@@ -79,7 +107,6 @@ void LocalPlayer::logic()
mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed;
if (mFrame >= frames) {
nextStep();
- attack();
}
break;
}
@@ -88,6 +115,35 @@ 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();
}
@@ -228,9 +284,19 @@ void LocalPlayer::walk(unsigned char dir)
void LocalPlayer::setTarget(Being *target)
{
- if (target == mTarget)
- {
+ if (mLastTarget != -1 || target == this)
return;
+ mLastTarget = tick_time;
+
+ if ((target == NULL) || target == mTarget)
+ {
+ target = NULL;
+ mKeepAttacking = false;
+ mTargetTime = -1;
+ }
+ if (target)
+ {
+ mTargetTime = tick_time;
}
if (mTarget && mTarget->getType() == Being::MONSTER)
{
@@ -375,25 +441,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)
@@ -412,8 +478,10 @@ void LocalPlayer::attack(Being *target, bool keep)
// Implement charging attacks here
mLastAttackTime = 0;
- setAction(ATTACK);
mWalkTime = tick_time;
+ mTargetTime = tick_time;
+
+ setAction(ATTACK);
if (mEquippedWeapon)
{
@@ -428,11 +496,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
@@ -475,7 +554,90 @@ bool LocalPlayer::withinAttackRange(Being *target)
void LocalPlayer::setGotoTarget(Being *target)
{
+ mLastTarget = -1;
setTarget(target);
mGoingToTarget = true;
setDestination(target->mX, target->mY);
}
+
+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 34f10a4a..ad59d138 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -23,11 +23,16 @@
#define _TMW_LOCALPLAYER_H
#include "player.h"
+#include "simpleanimation.h"
// TODO move into some sane place...
#define MAX_SLOT 2
+#define INVENTORY_SIZE 102
+#define STORAGE_SIZE 301
+
class FloorItem;
+class ImageSet;
class Inventory;
class Item;
class Network;
@@ -69,6 +74,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);
@@ -164,6 +174,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 +214,14 @@ class LocalPlayer : public Player
float mLastAttackTime; /**< Used to synchronize the charge dialog */
+ void drawTargetCursor(Graphics *graphics, int offsetX, int offsetY);
+
+ /** Animated in range target cursor. */
+ SimpleAnimation *mTargetCursorInRange[NUM_TC];
+
+ /** Animated out of range target cursor. */
+ SimpleAnimation *mTargetCursorOutRange[NUM_TC];
+
protected:
void walk(unsigned char dir);
@@ -208,13 +232,33 @@ class LocalPlayer : public Player
FloorItem *mPickUpTarget;
bool mTrading;
+ bool mInStorage; /**< Whether storage is currently accessible */
bool mGoingToTarget;
+ 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. */
Inventory *mInventory;
+ Inventory *mStorage;
+
+ /**
+ * Helper function for loading target cursors
+ */
+ void loadTargetCursor(std::string filename, int width, int height,
+ bool outRange, Being::TargetCursorSize size);
+
+ /** Images of in range target cursor. */
+ ImageSet *mInRangeImages[NUM_TC];
+
+ /** Images of out of range target cursor. */
+ ImageSet *mOutRangeImages[NUM_TC];
+
+ // Load the target cursors into memory
+ void initTargetCursor();
};
extern LocalPlayer *player_node;
diff --git a/src/main.cpp b/src/main.cpp
index e246b6a9..4049aa78 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,46 +19,41 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "main.h"
-
#include <getopt.h>
#include <iostream>
#include <physfs.h>
+#include <SDL_image.h>
#include <unistd.h>
#include <vector>
-#include <SDL_image.h>
#include <guichan/actionlistener.hpp>
+
#include <guichan/sdl/sdlinput.hpp>
+
#include <guichan/widgets/label.hpp>
#include <libxml/parser.h>
-#ifndef WIN32
-#include <cerrno>
-#include <sys/stat.h>
-#endif
-#if defined __APPLE__
-#include <CoreFoundation/CFBundle.h>
-#endif
-
#include "configuration.h"
-#include "keyboardconfig.h"
-#include "player_relations.h"
#include "game.h"
#include "graphics.h"
#include "itemshortcut.h"
-#include "lockedarray.h"
+#include "keyboardconfig.h"
#include "localplayer.h"
+#include "lockedarray.h"
#include "log.h"
#include "logindata.h"
+#include "main.h"
#ifdef USE_OPENGL
#include "openglgraphics.h"
#endif
+#include "player_relations.h"
+#include "serverinfo.h"
#include "sound.h"
#include "gui/char_server.h"
#include "gui/char_select.h"
+#include "gui/colour.h"
#include "gui/gui.h"
#include "gui/login.h"
#include "gui/ok_dialog.h"
@@ -67,6 +62,7 @@
#include "gui/setup.h"
#include "gui/updatewindow.h"
#include "gui/textfield.h"
+#include "gui/updatewindow.h"
#include "net/charserverhandler.h"
#include "net/loginhandler.h"
@@ -74,6 +70,7 @@
#include "net/messageout.h"
#include "net/network.h"
+#include "resources/colordb.h"
#include "resources/image.h"
#include "resources/itemdb.h"
#include "resources/monsterdb.h"
@@ -83,8 +80,20 @@
#include "utils/dtor.h"
#include "utils/tostring.h"
+#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 {
@@ -123,6 +132,7 @@ CharServerHandler charServerHandler;
LoginData loginData;
LockedArray<LocalPlayer*> charInfo(MAX_SLOT + 1);
+Colour *textColour;
// This anonymous namespace hides whatever is inside from other modules.
namespace {
@@ -168,10 +178,12 @@ struct Options
*/
void setUpdatesDir()
{
+ std::stringstream updates;
+
// If updatesHost is currently empty, fill it from config file
if (updateHost.empty()) {
updateHost =
- config.getValue("updatehost", "http://updates.themanaworld.org");
+ config.getValue("updatehost", "http://www.aethyra.org/updates");
}
// Remove any trailing slash at the end of the update host
@@ -183,8 +195,9 @@ void setUpdatesDir()
pos = updateHost.find("://");
if (pos != updateHost.npos) {
if (pos + 3 < updateHost.length()) {
- updatesDir =
- "updates/" + updateHost.substr(pos + 3);
+ 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;
@@ -192,7 +205,8 @@ void setUpdatesDir()
}
} 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();
@@ -213,18 +227,18 @@ void setUpdatesDir()
*/
void init_engine(const Options &options)
{
- homeDir = std::string(PHYSFS_getUserDir()) + "/.tmw";
+ homeDir = std::string(PHYSFS_getUserDir()) + "/.aethyra";
#if defined WIN32
if (!CreateDirectory(homeDir.c_str(), 0) &&
GetLastError() != ERROR_ALREADY_EXISTS)
#elif defined __APPLE__
- // Use Application Directory instead of .tmw
- homeDir = std::string(PHYSFS_getUserDir()) +
- "/Library/Application Support/The Mana World";
+ // Use Application Directory instead of .aethyra
+ homeDir = std::string(PHYSFS_getUserDir()) +
+ "/Library/Application Support/Aethyra";
if ((mkdir(homeDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) &&
(errno != EEXIST))
#else
- // Checking if /home/user/.tmw folder exists.
+ // Checking if /home/user/.Aethyra folder exists.
if ((mkdir(homeDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) &&
(errno != EEXIST))
#endif
@@ -236,12 +250,12 @@ void init_engine(const Options &options)
}
// Set log file
- logger->setLogFile(homeDir + std::string("/tmw.log"));
+ logger->setLogFile(homeDir + std::string("/aethyra.log"));
#ifdef PACKAGE_VERSION
- logger->log("Starting The Mana World Version %s", PACKAGE_VERSION);
+ logger->log("Starting Aethyra Version %s", PACKAGE_VERSION);
#else
- logger->log("Starting The Mana World - Version not defined");
+ logger->log("Starting Aethyra - Version not defined");
#endif
// Initialize SDL
@@ -286,13 +300,13 @@ void init_engine(const Options &options)
strncat(path, "/data", PATH_MAX - 1);
resman->addToSearchPath(path, true);
#else
- resman->addToSearchPath(TMW_DATADIR "data", true);
+ resman->addToSearchPath(AETHYRA_DATADIR "data", true);
#endif
// Fill configuration with defaults
logger->log("Initializing configuration...");
- config.setValue("host", "server.themanaworld.org");
- config.setValue("port", 6901);
+ config.setValue("host", "www.aethyra.org");
+ config.setValue("port", 21001);
config.setValue("hwaccel", 0);
#if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL
config.setValue("opengl", 1);
@@ -306,34 +320,34 @@ void init_engine(const Options &options)
config.setValue("sfxVolume", 100);
config.setValue("musicVolume", 60);
config.setValue("fpslimit", 60);
- config.setValue("updatehost", "http://updates.themanaworld.org");
+ config.setValue("updatehost", "http://www.aethyra.org/updates");
config.setValue("customcursor", 1);
config.setValue("ChatLogLength", 128);
// Checking if the configuration file exists... otherwise creates it with
// default options !
- FILE *tmwFile = 0;
+ FILE *aethyraFile = 0;
std::string configPath = options.configPath;
if (configPath.empty())
configPath = homeDir + "/config.xml";
- tmwFile = fopen(configPath.c_str(), "r");
+ aethyraFile = fopen(configPath.c_str(), "r");
// If we can't read it, it doesn't exist !
- if (tmwFile == NULL) {
+ if (aethyraFile == NULL) {
// We reopen the file in write mode and we create it
- tmwFile = fopen(configPath.c_str(), "wt");
+ aethyraFile = fopen(configPath.c_str(), "wt");
}
- if (tmwFile == NULL) {
+ if (aethyraFile == NULL) {
std::cout << "Can't create " << configPath << ". "
"Using Defaults." << std::endl;
} else {
- fclose(tmwFile);
+ fclose(aethyraFile);
config.init(configPath);
}
- SDL_WM_SetCaption("The Mana World", NULL);
+ SDL_WM_SetCaption("Aethyra", NULL);
#ifdef WIN32
static SDL_SysWMinfo pInfo;
SDL_GetWMInfo(&pInfo);
@@ -343,7 +357,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(AETHYRA_DATADIR "data/icons/aethyra.png");
if (icon)
{
SDL_SetAlpha(icon, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
@@ -429,6 +443,7 @@ void exit_engine()
sound.close();
// Unload XML databases
+ ColorDB::unload();
ItemDB::unload();
MonsterDB::unload();
NPCDB::unload();
@@ -440,26 +455,28 @@ void exit_engine()
void printHelp()
{
std::cout
- << "tmw" << std::endl << std::endl
+ << "aethyra" << 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
+ << " -C --configfile : Configuration file to use" << 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
+ << " -D --default : Bypass the login process with default "
+ "settings" << std::endl
+ << " -h --help : Display this help" << std::endl
+ << " -H --updatehost : Use this update host" << std::endl
<< " -p --playername : Login with this player" << std::endl
- << " -C --configfile : Configuration file to use" << std::endl
- << " -H --updatehost : Use this update host" << 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 << "Aethyra version " << PACKAGE_VERSION <<
+ std::endl;
#else
- std::cout << "The Mana World version " <<
+ std::cout << "Aethyra version " <<
"(local build?, PACKAGE_VERSION is not defined)" << std::endl;
#endif
}
@@ -469,16 +486,16 @@ void parseOptions(int argc, char *argv[], Options &options)
const char *optstring = "hvud:U:P:Dp:C:H:";
const struct option long_options[] = {
- { "help", no_argument, 0, 'h' },
- { "version", no_argument, 0, 'v' },
- { "skipupdate", no_argument, 0, 'u' },
+ { "configfile", required_argument, 0, 'C' },
{ "data", required_argument, 0, 'd' },
- { "username", required_argument, 0, 'U' },
- { "password", required_argument, 0, 'P' },
{ "default", no_argument, 0, 'D' },
{ "playername", required_argument, 0, 'p' },
- { "configfile", required_argument, 0, 'C' },
+ { "password", required_argument, 0, 'P' },
+ { "help", no_argument, 0, 'h' },
{ "updatehost", required_argument, 0, 'H' },
+ { "skipupdate", no_argument, 0, 'u' },
+ { "username", required_argument, 0, 'U' },
+ { "version", no_argument, 0, 'v' },
{ 0 }
};
@@ -490,36 +507,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;
}
}
@@ -597,6 +614,18 @@ void accountLogin(Network *network, LoginData *loginData)
config.setValue("remember", loginData->remember);
}
+inline int MIN(int x, int y)
+{
+ return x < y ? x : y;
+}
+
+void positionDialog(Window *dialog, int screenWidth, int screenHeight)
+{
+ dialog->setPosition(
+ MIN(screenWidth * 5 / 8, screenWidth - dialog->getWidth()),
+ MIN(screenHeight * 5 / 8, screenHeight - dialog->getHeight()));
+}
+
void charLogin(Network *network, LoginData *loginData)
{
logger->log("Trying to connect to char server...");
@@ -716,13 +745,39 @@ int main(int argc, char *argv[])
if (!options.password.empty()) {
loginData.password = options.password;
}
- loginData.hostname = config.getValue("host", "server.themanaworld.org");
- loginData.port = (short)config.getValue("port", 0);
+ loginData.hostname = config.getValue("host", "www.aethyra.org");
+ loginData.port = (short)config.getValue("port", 21001);
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;
+
+ if (screenWidth <= 800)
+ wallpaperName = "graphics/images/login_wallpaper.png";
+ else if (screenWidth <= 1024)
+ wallpaperName = "graphics/images/login_wallpaper_1024x768.png";
+ else if (screenWidth <= 1280)
+ wallpaperName = "graphics/images/login_wallpaper_1280x960.png";
+ else if (screenWidth <= 1440)
+ wallpaperName = "graphics/images/login_wallpaper_1440x1080.png";
+ else
+ wallpaperName = "graphics/images/login_wallpaper_1600x1200.png";
+
+ login_wallpaper = ResourceManager::getInstance()-> getImage(wallpaperName);
+
+ if (!login_wallpaper)
+ logger->log("Couldn't load %s as wallpaper", wallpaperName.c_str());
+
+ // Needs to be created in main, as the updater uses it
+ textColour = new Colour();
+
while (state != EXIT_STATE)
{
// Handle SDL events
@@ -758,16 +813,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);
@@ -796,7 +841,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
@@ -835,6 +880,7 @@ int main(int argc, char *argv[])
false);
// Load XML databases
+ ColorDB::load();
ItemDB::load();
MonsterDB::load();
NPCDB::load();
@@ -849,33 +895,48 @@ int main(int argc, char *argv[])
state = ACCOUNT_STATE;
} else {
currentDialog = new LoginDialog(&loginData);
+ positionDialog(currentDialog, screenWidth,
+ screenHeight);
}
break;
case REGISTER_STATE:
logger->log("State: REGISTER");
currentDialog = new RegisterDialog(&loginData);
+ positionDialog(currentDialog, screenWidth, screenHeight);
break;
case CHAR_SERVER_STATE:
logger->log("State: CHAR_SERVER");
+
+ if (n_server == 1)
+ {
+ SERVER_INFO *si = *server_info;
+ loginData.hostname = iptostring(si->address);
+ loginData.port = si->port;
+ loginData.updateHost = si->updateHost;
+ state = UPDATE_STATE;
+ }
+ else
{
int nextState = (options.skipUpdate) ?
LOADDATA_STATE : UPDATE_STATE;
currentDialog = new ServerSelectDialog(&loginData,
- nextState);
- }
- if (options.chooseDefault || options.playername != "") {
- ((ServerSelectDialog*) currentDialog)->action(
- gcn::ActionEvent(NULL, "ok"));
+ nextState);
+ positionDialog(currentDialog, screenWidth,
+ screenHeight);
+ if (options.chooseDefault || options.playername != "")
+ {
+ ((ServerSelectDialog*) currentDialog)->action(
+ gcn::ActionEvent(NULL, "ok"));
+ }
}
break;
-
case CHAR_SELECT_STATE:
logger->log("State: CHAR_SELECT");
currentDialog = new CharSelectDialog(network, &charInfo,
1 - loginData.sex);
-
+ positionDialog(currentDialog, screenWidth, screenHeight);
if (((CharSelectDialog*) currentDialog)->
selectByName(options.playername))
options.chooseDefault = true;
@@ -923,13 +984,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();
@@ -965,8 +1034,15 @@ int main(int argc, char *argv[])
break;
}
}
+ /*
+ * This loop can really stress the CPU, for no reason since it's
+ * just constantly redrawing the wallpaper. Added the following
+ * usleep to limit it to 20 FPS during the login sequence
+ */
+ usleep(50000);
}
+ delete textColour;
#ifdef PACKAGE_VERSION
delete versionLabel;
#endif
diff --git a/src/main.h b/src/main.h
index 3070804f..a0fe65cb 100644
--- a/src/main.h
+++ b/src/main.h
@@ -30,8 +30,8 @@
#include "winver.h"
#endif
-#ifndef TMW_DATADIR
-#define TMW_DATADIR ""
+#ifndef AETHYRA_DATADIR
+#define AETHYRA_DATADIR ""
#endif
/*
diff --git a/src/map.cpp b/src/map.cpp
index 928a0154..02b046fb 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -19,22 +19,21 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "map.h"
-
-#include <algorithm>
#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"
@@ -111,6 +110,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++;
@@ -153,9 +153,9 @@ Map::~Map()
{
// delete metadata, layers, tilesets and overlays
delete[] mMetaTiles;
- for_each(mLayers.begin(), mLayers.end(), make_dtor(mLayers));
- for_each(mTilesets.begin(), mTilesets.end(), make_dtor(mTilesets));
- for_each(mOverlays.begin(), mOverlays.end(), make_dtor(mOverlays));
+ delete_all(mLayers);
+ delete_all(mTilesets);
+ delete_all(mOverlays);
}
void Map::initializeOverlays()
@@ -218,7 +218,8 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY)
mSprites.sort(spriteCompare);
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,
@@ -285,7 +286,7 @@ Tileset* Map::getTilesetWithGid(int gid) const
containsGid.gid = gid;
Tilesets::const_iterator i = find_if(mTilesets.begin(), mTilesets.end(),
- containsGid);
+ containsGid);
return (i == mTilesets.end()) ? NULL : *i;
}
@@ -294,7 +295,7 @@ void Map::setWalk(int x, int y, bool walkable)
{
mMetaTiles[x + y * mWidth].walkable = walkable;
}
-
+
bool Map::occupied(int x, int y) const
{
Beings &beings = beingManager->getAll();
@@ -312,7 +313,7 @@ bool Map::occupied(int x, int y) const
bool Map::tileCollides(int x, int y) const
{
- return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable);
+ return !(contains(x, y) && mMetaTiles[x + y * mWidth].walkable);
}
bool Map::contains(int x, int y) const
@@ -414,13 +415,6 @@ Path Map::findPath(int startX, int startY, int destX, int destY)
// 14 for moving diagonal (sqrt(200) = 14.1421...)
int Gcost = curr.tile->Gcost + ((dx == 0 || dy == 0) ? 10 : 14);
- // It costs extra to walk through a being (needs to be enough
- // to make it more attractive to walk around).
- if (occupied(x, y))
- {
- Gcost += 30;
- }
-
// Skip if Gcost becomes too much
// Warning: probably not entirely accurate
if (Gcost > 200)
@@ -509,11 +503,14 @@ 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/monster.cpp b/src/monster.cpp
index 8666fe26..04624b8c 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -19,14 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "monster.h"
-
#include "animatedsprite.h"
#include "game.h"
-#include "sound.h"
+#include "localplayer.h"
+#include "monster.h"
#include "particle.h"
+#include "sound.h"
#include "text.h"
-#include "localplayer.h"
#include "gui/gui.h"
@@ -46,6 +45,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++)
@@ -63,26 +63,28 @@ 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));
+ }
}
}
-Monster::~Monster()
+Monster::~Monster()
{
if (mText)
{
- player_node->setTarget(0);
+ delete mText;
+ player_node->setTarget(NULL);
}
}
-void
-Monster::logic()
+void Monster::logic()
{
if (mAction != STAND)
{
@@ -97,16 +99,16 @@ Monster::logic()
Being::logic();
}
-Being::Type
-Monster::getType() const
+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)
{
@@ -120,13 +122,34 @@ Monster::setAction(Uint8 action)
case ATTACK:
currentAction = ACTION_ATTACK;
mSprites[BASE_SPRITE]->reset();
+
+ //attack particle effect
+ particleEffect = getInfo().getAttackParticleEffect();
+ if (particleEffect != "" && mParticleEffects)
+ {
+ switch (mDirection)
+ {
+ case DOWN: rotation = 0; break;
+ case LEFT: rotation = 90; break;
+ case UP: rotation = 180; break;
+ case RIGHT: rotation = 270; break;
+ default: break;
+ }
+ Particle *p;
+ p = particleEngine->addEffect(
+ particleEffect, 0, 0, rotation);
+ controlParticle(p);
+ }
break;
case STAND:
- currentAction = ACTION_STAND;
- break;
+ currentAction = ACTION_STAND;
+ break;
case HURT:
- // Not implemented yet
- break;
+ // Not implemented yet
+ break;
+ case SIT:
+ // Also not implemented yet
+ break;
}
if (currentAction != ACTION_INVALID)
@@ -142,8 +165,7 @@ Monster::setAction(Uint8 action)
}
}
-void
-Monster::handleAttack(Being *victim, int damage)
+void Monster::handleAttack(Being *victim, int damage)
{
Being::handleAttack(victim, damage);
@@ -152,34 +174,34 @@ Monster::handleAttack(Being *victim, int damage)
MONSTER_EVENT_HIT : MONSTER_EVENT_MISS));
}
-void
-Monster::takeDamage(int amount)
+void Monster::takeDamage(int amount)
{
if (amount > 0) sound.playSfx(getInfo().getSound(MONSTER_EVENT_HURT));
Being::takeDamage(amount);
}
-Being::TargetCursorSize
-Monster::getTargetCursorSize() const
+Being::TargetCursorSize Monster::getTargetCursorSize() const
{
return getInfo().getTargetCursorSize();
}
-const MonsterInfo&
-Monster::getInfo() const
+const MonsterInfo& Monster::getInfo() const
{
return MonsterDB::get(mJob - 1002);
}
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,
- speechFont, gcn::Color(255, 32, 32));
+ mobNameFont, gcn::Color(255, 32, 32));
}
else
{
diff --git a/src/monster.h b/src/monster.h
index c8f0a8f7..cb8f7f18 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;
diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp
index 086b4280..3c022af6 100644
--- a/src/net/beinghandler.cpp
+++ b/src/net/beinghandler.cpp
@@ -19,24 +19,24 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "beinghandler.h"
-
+#include <iostream>
#include <SDL_types.h>
+#include "beinghandler.h"
#include "messagein.h"
#include "protocol.h"
#include "../being.h"
#include "../beingmanager.h"
+#include "../effectmanager.h"
#include "../game.h"
#include "../localplayer.h"
#include "../log.h"
#include "../main.h"
+#include "../npc.h"
#include "../particle.h"
-#include "../sound.h"
-#include <iostream>
#include "../player_relations.h"
-#include "../npc.h"
+#include "../sound.h"
const int EMOTION_TIME = 150; /**< Duration of emotion icon */
@@ -72,6 +72,7 @@ void BeingHandler::handleMessage(MessageIn *msg)
Uint16 headTop, headMid, headBottom;
Uint16 shoes, gloves, cape, misc1, misc2;
Uint16 weapon, shield;
+ Uint16 gmstatus;
Sint16 param1;
Sint8 type;
Being *srcBeing, *dstBeing;
@@ -128,8 +129,8 @@ void BeingHandler::handleMessage(MessageIn *msg)
headTop = msg->readInt16();
headMid = msg->readInt16();
hairColor = msg->readInt16();
- shoes = msg->readInt16(); // clothes color - "abused" as shoes
- gloves = msg->readInt16(); // head dir - "abused" as gloves
+ shoes = msg->readInt16();
+ gloves = msg->readInt16();
msg->readInt16(); // guild
msg->readInt16(); // unknown
msg->readInt16(); // unknown
@@ -201,22 +202,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;
@@ -234,28 +230,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);
}
@@ -269,8 +263,10 @@ void BeingHandler::handleMessage(MessageIn *msg)
break;
int effectType = msg->readInt32();
+ Being* being = beingManager->findBeing(id);
- beingManager->findBeing(id)->triggerEffect(effectType);
+ effectManager->trigger(effectType, (int) being->getPixelX(),
+ (int) being->getPixelY());
break;
}
@@ -403,8 +399,8 @@ void BeingHandler::handleMessage(MessageIn *msg)
headTop = msg->readInt16();
headMid = msg->readInt16();
hairColor = msg->readInt16();
- msg->readInt16(); // clothes color - Aethyra-"abused" as shoes, we ignore it
- msg->readInt16(); // head dir - Aethyra-"abused" as gloves, we ignore it
+ shoes = msg->readInt16();
+ gloves = msg->readInt16();
msg->readInt32(); // guild
msg->readInt32(); // emblem
msg->readInt16(); // manner
@@ -417,6 +413,10 @@ void BeingHandler::handleMessage(MessageIn *msg)
dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom);
dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid);
dstBeing->setSprite(Being::HAT_SPRITE, headTop);
+ dstBeing->setSprite(Being::SHOE_SPRITE, shoes);
+ // Compensation for the unpatched TMW server
+ if (gloves > 10)
+ dstBeing->setSprite(Being::GLOVES_SPRITE, gloves);
dstBeing->setSprite(Being::CAPE_SPRITE, cape);
dstBeing->setSprite(Being::MISC1_SPRITE, misc1);
dstBeing->setSprite(Being::MISC2_SPRITE, misc2);
@@ -437,18 +437,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)
@@ -465,16 +469,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()) {
@@ -492,11 +496,11 @@ void BeingHandler::handleMessage(MessageIn *msg)
case SMSG_PLAYER_MOVE_TO_ATTACK:
/*
- * This is an *advisory* message, telling the client that
- * it needs to move the character before attacking
- * a target (out of range, obstruction in line of fire).
- * We can safely ignore this...
- */
+ * This is an *advisory* message, telling the client that
+ * it needs to move the character before attacking
+ * a target (out of range, obstruction in line of fire).
+ * We can safely ignore this...
+ */
break;
case 0x0119:
diff --git a/src/net/beinghandler.h b/src/net/beinghandler.h
index 5e22a670..9e736751 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 16cfdc06..b2fe99b9 100644
--- a/src/net/buysellhandler.cpp
+++ b/src/net/buysellhandler.cpp
@@ -19,10 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "buysellhandler.h"
-
#include <SDL_types.h>
+#include "buysellhandler.h"
#include "messagein.h"
#include "protocol.h"
@@ -37,8 +36,8 @@
#include "../gui/sell.h"
extern BuyDialog *buyDialog;
-extern SellDialog *sellDialog;
extern Window *buySellDialog;
+extern SellDialog *sellDialog;
BuySellHandler::BuySellHandler()
{
diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp
index 9fb67ea5..281923f8 100644
--- a/src/net/charserverhandler.cpp
+++ b/src/net/charserverhandler.cpp
@@ -20,19 +20,24 @@
*/
#include "charserverhandler.h"
-
#include "messagein.h"
#include "network.h"
#include "protocol.h"
+#include "../extensions.h"
#include "../game.h"
#include "../localplayer.h"
#include "../log.h"
#include "../logindata.h"
#include "../main.h"
-#include "../gui/ok_dialog.h"
#include "../gui/char_select.h"
+#include "../gui/ok_dialog.h"
+
+/*
+ * Yeah, this is a global. Get over it.
+ */
+struct EXTENSIONS extensions;
CharServerHandler::CharServerHandler():
mCharCreateDialog(0)
@@ -54,6 +59,7 @@ CharServerHandler::CharServerHandler():
void CharServerHandler::handleMessage(MessageIn *msg)
{
int slot;
+ int flags;
LocalPlayer *tempPlayer;
logger->log("CharServerHandler: Packet ID: %x, Length: %d",
@@ -61,8 +67,13 @@ void CharServerHandler::handleMessage(MessageIn *msg)
switch (msg->getId())
{
case 0x006b:
- // Skip length word and an additional mysterious 20 bytes
- msg->skip(2 + 20);
+ msg->skip(2); // Length word
+ flags = msg->readInt32(); // Aethyra extensions flags
+ logger->log("Server flags are: %x", flags);
+ extensions.aethyra_inventory = (bool)(flags & 0x01);
+ extensions.aethyra_spells = (bool)(flags & 0x02);
+ extensions.aethyra_misc = (bool)(flags & 0x04);
+ msg->skip(16); // Unused
// Derive number of characters from message length
n_character = (msg->getLength() - 24) / 106;
diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp
index d852798d..b73b86b4 100644
--- a/src/net/chathandler.cpp
+++ b/src/net/chathandler.cpp
@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "chathandler.h"
-
#include <SDL_types.h>
#include <string>
+#include "chathandler.h"
#include "messagein.h"
#include "protocol.h"
diff --git a/src/net/equipmenthandler.cpp b/src/net/equipmenthandler.cpp
index 580cef6b..2e0cc562 100644
--- a/src/net/equipmenthandler.cpp
+++ b/src/net/equipmenthandler.cpp
@@ -20,7 +20,6 @@
*/
#include "equipmenthandler.h"
-
#include "messagein.h"
#include "protocol.h"
@@ -107,7 +106,10 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
break;
}
- // Unequip any existing equipped item in this position
+ /*
+ * An item may occupy more than 1 slot. If so, it's
+ * only shown as equipped on the *first* slot.
+ */
mask = 1;
position = 0;
while (!(equipPoint & mask)) {
@@ -115,7 +117,10 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
position++;
}
logger->log("Position %i", position);
- item = player_node->getInventory()->getItem(player_node->mEquipment->getEquipment(position));
+
+ item = player_node->getInventory()->getItem(player_node->mEquipment->getEquipment(position));
+
+ // Unequip any existing equipped item in this position
if (item) {
item->setEquipped(false);
}
@@ -152,24 +157,11 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
item->setEquipped(false);
- switch (item->getId()) {
- case 529:
- case 1199:
- player_node->mEquipment->setArrows(0);
- break;
- case 521:
- case 522:
- case 530:
- case 536:
- case 1200:
- case 1201:
- player_node->setSprite(Being::WEAPON_SPRITE, 0);
- // TODO: Why this break? Shouldn't a weapon be
- // unequipped in inventory too?
- break;
- default:
- player_node->mEquipment->removeEquipment(position);
- break;
+ if (equipPoint & 0x8000) { // Arrows
+ player_node->mEquipment->setArrows(0);
+ }
+ else {
+ player_node->mEquipment->removeEquipment(position);
}
logger->log("Unequipping: %i %i(%i) %i",
index, equipPoint, type, position);
@@ -186,12 +178,12 @@ void EquipmentHandler::handleMessage(MessageIn *msg)
break;
item = inventory->getItem(index);
- if (!item)
- break;
- item->setEquipped(true);
- player_node->mEquipment->setArrows(index);
- logger->log("Arrows equipped: %i", index);
+ if (item) {
+ item->setEquipped(true);
+ player_node->mEquipment->setArrows(index);
+ logger->log("Arrows equipped: %i", index);
+ }
break;
}
}
diff --git a/src/net/inventoryhandler.cpp b/src/net/inventoryhandler.cpp
index 9ddbd62f..12b7d5ef 100644
--- a/src/net/inventoryhandler.cpp
+++ b/src/net/inventoryhandler.cpp
@@ -19,22 +19,22 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "inventoryhandler.h"
-
#include <SDL_types.h>
+#include "inventoryhandler.h"
#include "messagein.h"
#include "protocol.h"
-#include "../resources/iteminfo.h"
+#include "../inventory.h"
#include "../item.h"
#include "../itemshortcut.h"
#include "../localplayer.h"
#include "../log.h"
-#include "../inventory.h"
#include "../gui/chat.h"
+#include "../resources/iteminfo.h"
+
#include "../utils/tostring.h"
InventoryHandler::InventoryHandler()
@@ -45,6 +45,12 @@ InventoryHandler::InventoryHandler()
SMSG_PLAYER_INVENTORY_REMOVE,
SMSG_PLAYER_INVENTORY_USE,
SMSG_ITEM_USE_RESPONSE,
+ SMSG_PLAYER_STORAGE_ITEMS,
+ SMSG_PLAYER_STORAGE_EQUIP,
+ SMSG_PLAYER_STORAGE_STATUS,
+ SMSG_PLAYER_STORAGE_ADD,
+ SMSG_PLAYER_STORAGE_REMOVE,
+ SMSG_PLAYER_STORAGE_CLOSE,
0
};
handledMessages = _messages;
@@ -53,35 +59,69 @@ InventoryHandler::InventoryHandler()
void InventoryHandler::handleMessage(MessageIn *msg)
{
Sint32 number;
- Sint16 index, amount, itemId, equipType;
+ Sint16 index, amount, itemId, equipType, arrow;
+ Sint16 identified, cards[4], itemType;
Inventory *inventory = player_node->getInventory();
+ Inventory *storage = player_node->getStorage();
switch (msg->getId())
{
case SMSG_PLAYER_INVENTORY:
- // Only called on map load / warp. First reset all items
- // to not load them twice on map change.
- inventory->clear();
+ case SMSG_PLAYER_STORAGE_ITEMS:
+ case SMSG_PLAYER_STORAGE_EQUIP:
+ switch (msg->getId()) {
+ case SMSG_PLAYER_INVENTORY:
+ // Clear inventory - this will be a complete refresh
+ inventory->clear();
+ break;
+ case SMSG_PLAYER_STORAGE_ITEMS:
+ /*
+ * This packet will always be followed by a
+ * SMSG_PLAYER_STORAGE_EQUIP packet. The two packets
+ * together comprise a complete refresh of storage, so
+ * clear storage here
+ */
+ storage->clear();
+ logger->log("Received SMSG_PLAYER_STORAGE_ITEMS");
+ break;
+ default:
+ logger->log("Received SMSG_PLAYER_STORAGE_EQUIP");
+ break;
+ }
msg->readInt16(); // length
number = (msg->getLength() - 4) / 18;
- for (int loop = 0; loop < number; loop++)
- {
+ for (int loop = 0; loop < number; loop++) {
index = msg->readInt16();
itemId = msg->readInt16();
- msg->readInt8(); // type
- msg->readInt8(); // identify flag
- amount = msg->readInt16();
- msg->skip(2); // unknown
- msg->skip(8); // card (4 shorts)
-
- inventory->setItem(index, itemId, amount, false);
-
- // Trick because arrows are not considered equipment
- if (itemId == 1199 || itemId == 529)
- {
- if (Item *item = inventory->getItem(index))
- item->setEquipment(true);
+ itemType = msg->readInt8();
+ identified = msg->readInt8();
+ if (msg->getId() == SMSG_PLAYER_STORAGE_EQUIP) {
+ amount = 1;
+ msg->readInt16(); // Equip Point?
+ } else {
+ amount = msg->readInt16();
+ }
+ arrow = msg->readInt16();
+ if (msg->getId() == SMSG_PLAYER_STORAGE_EQUIP) {
+ msg->readInt8(); // Attribute (broken)
+ msg->readInt8(); // Refine level
+ }
+ for (int i = 0; i < 4; i++)
+ cards[i] = msg->readInt16();
+
+ if (msg->getId() == SMSG_PLAYER_INVENTORY) {
+ inventory->setItem(index, itemId, amount, false);
+
+ // Trick because arrows are not considered equipment
+ if (arrow & 0x8000) {
+ if (Item *item = inventory->getItem(index))
+ item->setEquipment(true);
+ }
+ } else {
+ logger->log("Index:%d, ID:%d, Type:%d, Identified:%d, Qty:%d, Cards:%d, %d, %d, %d",
+ index, itemId, itemType, identified, amount, cards[0], cards[1], cards[2], cards[3]);
+ storage->setItem(index, itemId, amount, false);
}
}
break;
@@ -90,12 +130,13 @@ void InventoryHandler::handleMessage(MessageIn *msg)
index = msg->readInt16();
amount = msg->readInt16();
itemId = msg->readInt16();
- msg->readInt8(); // identify flag
+ identified = msg->readInt8();
msg->readInt8(); // attribute
msg->readInt8(); // refine
- msg->skip(8); // card
+ for (int i = 0; i < 4; i++)
+ cards[i] = msg->readInt16();
equipType = msg->readInt16();
- msg->readInt8(); // type
+ itemType = msg->readInt8();
if (msg->readInt8() > 0) {
chatWindow->chatLog("Unable to pick up item", BY_SERVER);
@@ -147,5 +188,38 @@ void InventoryHandler::handleMessage(MessageIn *msg)
item->setQuantity(amount);
}
break;
+
+ case SMSG_PLAYER_STORAGE_STATUS:
+ /*
+ * Basic slots used vs total slots info
+ * We don't really need this information, but this is
+ * the closest we get to an "Open Storage" packet
+ * from the server. It always comes after the two
+ * SMSG_PLAYER_STORAGE_... packets that update
+ * storage contents.
+ */
+ logger->log("Received SMSG_PLAYER_STORAGE_STATUS");
+ player_node->setInStorage(true);
+ break;
+
+ case SMSG_PLAYER_STORAGE_ADD:
+ /*
+ * Move an item into storage
+ */
+ break;
+
+ case SMSG_PLAYER_STORAGE_REMOVE:
+ /*
+ * Move an item out of storage
+ */
+ break;
+
+ case SMSG_PLAYER_STORAGE_CLOSE:
+ /*
+ * Storage access has been closed
+ */
+ player_node->setInStorage(false);
+ logger->log("Received SMSG_PLAYER_STORAGE_CLOSE");
+ break;
}
}
diff --git a/src/net/itemhandler.cpp b/src/net/itemhandler.cpp
index 487b98bf..9cf85ce7 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 169503da..2b98e4e4 100644
--- a/src/net/loginhandler.cpp
+++ b/src/net/loginhandler.cpp
@@ -20,7 +20,6 @@
*/
#include "loginhandler.h"
-
#include "messagein.h"
#include "network.h"
#include "protocol.h"
@@ -35,7 +34,7 @@ extern SERVER_INFO **server_info;
LoginHandler::LoginHandler()
{
static const Uint16 _messages[] = {
- SMSG_UPDATE_HOST,
+ 0x0063,
0x0069,
0x006a,
0
@@ -87,7 +86,7 @@ void LoginHandler::handleMessage(MessageIn *msg)
iptostring(server_info[i]->address),
server_info[i]->port);
}
- state = CHAR_SERVER_STATE;
+ state = CHAR_SERVER_STATE;
break;
case 0x006a:
diff --git a/src/net/loginhandler.h b/src/net/loginhandler.h
index 8a952cd5..047434b4 100644
--- a/src/net/loginhandler.h
+++ b/src/net/loginhandler.h
@@ -22,6 +22,8 @@
#ifndef _TMW_NET_LOGINHANDLER_H
#define _TMW_NET_LOGINHANDLER_H
+#include <string>
+
#include "messagehandler.h"
#include <string>
diff --git a/src/net/maploginhandler.cpp b/src/net/maploginhandler.cpp
index b1000c12..bc08d5d6 100644
--- a/src/net/maploginhandler.cpp
+++ b/src/net/maploginhandler.cpp
@@ -20,7 +20,6 @@
*/
#include "maploginhandler.h"
-
#include "messagein.h"
#include "protocol.h"
diff --git a/src/net/messagehandler.cpp b/src/net/messagehandler.cpp
index 29e34a29..7a41e1ad 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 8e31fded..345e02fc 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),
diff --git a/src/net/messagein.h b/src/net/messagein.h
index da80df9e..81db6cdc 100644
--- a/src/net/messagein.h
+++ b/src/net/messagein.h
@@ -22,8 +22,8 @@
#ifndef _TMW_MESSAGEIN_
#define _TMW_MESSAGEIN_
-#include <string>
#include <SDL_types.h>
+#include <string>
/**
* Used for parsing an incoming message.
diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp
index 96678f19..6aa25411 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 e8b5e949..c9f8d1bd 100644
--- a/src/net/network.cpp
+++ b/src/net/network.cpp
@@ -19,15 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "network.h"
+#include <sstream>
#include "messagehandler.h"
#include "messagein.h"
+#include "network.h"
#include "../log.h"
-#include <sstream>
-
/** Warning: buffers and other variables are shared,
so there can be only one connection active at a time */
diff --git a/src/net/npchandler.cpp b/src/net/npchandler.cpp
index b633835c..4f3c4354 100644
--- a/src/net/npchandler.cpp
+++ b/src/net/npchandler.cpp
@@ -19,16 +19,16 @@
* 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/npclistdialog.h"
#include "../gui/npc_text.h"
+#include "../gui/npclistdialog.h"
extern NpcListDialog *npcListDialog;
extern NpcTextDialog *npcTextDialog;
@@ -54,6 +54,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);
@@ -62,15 +63,15 @@ void NPCHandler::handleMessage(MessageIn *msg)
case SMSG_NPC_MESSAGE:
msg->readInt16(); // length
id = msg->readInt32();
+ player_node->setAction(LocalPlayer::STAND);
current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id));
npcTextDialog->addText(msg->readString(msg->getLength() - 8));
npcListDialog->setVisible(false);
npcTextDialog->setVisible(true);
break;
- case SMSG_NPC_CLOSE:
+ case SMSG_NPC_CLOSE:
id = msg->readInt32();
- dynamic_cast<NPC*>(beingManager->findBeing(id));
if (current_npc == dynamic_cast<NPC*>(beingManager->findBeing(id)))
current_npc = NULL;
break;
diff --git a/src/net/partyhandler.cpp b/src/net/partyhandler.cpp
new file mode 100644
index 00000000..9b5f3080
--- /dev/null
+++ b/src/net/partyhandler.cpp
@@ -0,0 +1,124 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/actionlistener.hpp>
+
+#include "partyhandler.h"
+#include "protocol.h"
+#include "messagein.h"
+
+#include "../gui/chat.h"
+#include "../gui/confirm_dialog.h"
+
+#include "../beingmanager.h"
+#include "../game.h"
+#include "../party.h"
+
+PartyHandler::PartyHandler(Party *party) : mParty(party)
+{
+ static const Uint16 _messages[] = {
+ SMSG_PARTY_CREATE,
+ SMSG_PARTY_INFO,
+ SMSG_PARTY_INVITE,
+ SMSG_PARTY_INVITED,
+ SMSG_PARTY_SETTINGS,
+ SMSG_PARTY_MEMBER_INFO,
+ SMSG_PARTY_LEAVE,
+ SMSG_PARTY_UPDATE_HP,
+ SMSG_PARTY_UPDATE_COORDS,
+ SMSG_PARTY_MESSAGE,
+ 0
+ };
+ handledMessages = _messages;
+}
+
+void
+PartyHandler::handleMessage(MessageIn *msg)
+{
+ switch (msg->getId())
+ {
+ case SMSG_PARTY_CREATE:
+ mParty->createResponse(msg->readInt8());
+ break;
+ case SMSG_PARTY_INFO:
+ break;
+ case SMSG_PARTY_INVITE:
+ {
+ std::string nick = msg->readString(24);
+ int status = msg->readInt8();
+ mParty->inviteResponse(nick, status);
+ break;
+ }
+ case SMSG_PARTY_INVITED:
+ {
+ int id = msg->readInt32();
+ Being *being = beingManager->findBeing(id);
+ if (being == NULL)
+ {
+ break;
+ }
+ std::string nick;
+ int gender = 0;
+ std::string partyName = "";
+ if (being->getType() != Being::PLAYER)
+ {
+ nick = "";
+ }
+ else
+ {
+ nick = being->getName();
+ gender = being->getGender();
+ partyName = msg->readString(24);
+ }
+ mParty->invitedAsk(nick, gender, partyName);
+ break;
+ }
+ case SMSG_PARTY_SETTINGS:
+ break;
+ case SMSG_PARTY_MEMBER_INFO:
+ break;
+ case SMSG_PARTY_LEAVE:
+ {
+ /*int id = */msg->readInt32();
+ std::string nick = msg->readString(24);
+ /*int fail = */msg->readInt8();
+ mParty->leftResponse(nick);
+ break;
+ }
+ case SMSG_PARTY_UPDATE_HP:
+ break;
+ case SMSG_PARTY_UPDATE_COORDS:
+ break;
+ case SMSG_PARTY_MESSAGE:
+ { // new block to enable local variables
+ int msgLength = msg->readInt16() - 8;
+ if (msgLength <= 0)
+ {
+ return;
+ }
+ int id = msg->readInt32();
+ Being *being = beingManager->findBeing(id);
+ std::string chatMsg = msg->readString(msgLength);
+ mParty->receiveChat(being, chatMsg);
+ }
+ break;
+ }
+}
diff --git a/src/net/partyhandler.h b/src/net/partyhandler.h
new file mode 100644
index 00000000..daabc52f
--- /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 _TMW_NET_PARTYHANDLER_H
+#define _TMW_NET_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 50546b1e..a4a2dcc9 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,8 @@
#include "../gui/skill.h"
#include "../gui/viewport.h"
+#include "../utils/tostring.h"
+
// TODO Move somewhere else
OkDialog *weightNotice = NULL;
OkDialog *deathNotice = NULL;
@@ -51,7 +51,7 @@ extern SellDialog *sellDialog;
extern Window *buySellDialog;
static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; /* Max. distance we are willing to scroll after a teleport;
- ** everything beyond will reset the port hard. */
+ * everything beyond will reset the port hard. */
/**
* Listener used for handling the overweigth message.
@@ -110,10 +110,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 +133,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 +145,8 @@ void PlayerHandler::handleMessage(MessageIn *msg)
/* Scroll if neccessary */
if (!nearby
|| (abs(x - player_node->mX) > MAP_TELEPORT_SCROLL_DISTANCE)
- || (abs(y - player_node->mY) > MAP_TELEPORT_SCROLL_DISTANCE)) {
+ || (abs(y - player_node->mY) > MAP_TELEPORT_SCROLL_DISTANCE))
+ {
scrollOffsetX = (x - player_node->mX) * 32;
scrollOffsetY = (y - player_node->mY) * 32;
}
@@ -173,6 +176,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;
@@ -193,10 +199,6 @@ void PlayerHandler::handleMessage(MessageIn *msg)
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 +207,44 @@ void PlayerHandler::handleMessage(MessageIn *msg)
case 0x0031: player_node->HIT = value; break;
case 0x0032: player_node->FLEE = value; break;
case 0x0035: player_node->mAttackSpeed = value; break;
+ case 0x0037: player_node->mJobLevel = value; break;
}
if (player_node->mHp == 0 && deathNotice == NULL)
{
- deathNotice = new OkDialog("Message",
- "You're now dead, press ok to restart");
+ static char const *const deadMsg[] =
+ {
+ "You are dead.",
+ "We regret to inform you that your character was killed in battle.",
+ "You are not that alive anymore.",
+ "The cold hands of the grim reaper are grabbing for your soul.",
+ "Game Over!",
+ "Insert coin to continue",
+ "No, kids. Your character did not really die. It... err... went to a better place.",
+ "Your plan of breaking your enemies weapon by bashing it with your throat failed.",
+ "I guess this did not run too well.",
+ "Do you want your possessions identified?", // Nethack reference
+ "Sadly, no trace of you was ever found...", // Secret of Mana reference
+ "Annihilated.", // Final Fantasy VI reference
+ "Looks like you got your head handed to you.", //Earthbound reference
+ "You screwed up again, dump your body down the tubes and get you another one.", // Leisure Suit Larry 1 Reference
+ "You're not dead yet. You're just resting.", // Monty Python reference from a couple of skits
+ "You are no more.", // Monty Python reference from the dead parrot sketch starting now
+ "You have ceased to be.",
+ "You've expired and gone to meet your maker.",
+ "You're a stiff.",
+ "Bereft of life, you rest in peace.",
+ "If you weren't so animated, you'd be pushing up the daisies.",
+ "Your metabolic processes are now history.",
+ "You're off the twig.",
+ "You've kicked the bucket.",
+ "You've shuffled off your mortal coil, run down the curtain and joined the bleedin' choir invisibile.",
+ "You are an ex-player.",
+ "You're pining for the fjords." // Monty Python reference from the dead parrot sketch
+ };
+ std::string message(deadMsg[rand()%27]);
+
+ deathNotice = new OkDialog("Message", message);
deathNotice->addActionListener(&deathListener);
player_node->setAction(Being::DEAD);
}
@@ -293,7 +327,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();
@@ -361,18 +395,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 d7bdd041..783283ba 100644
--- a/src/net/protocol.h
+++ b/src/net/protocol.h
@@ -22,8 +22,11 @@
#ifndef _TMW_PROTOCOL_
#define _TMW_PROTOCOL_
-// Packets from server to client
+/*********************************
+ * Packets from server to client *
+ *********************************/
#define SMSG_LOGIN_SUCCESS 0x0073 /**< Contains starting location */
+#define SMSG_SERVER_PING 0x007f /**< Contains server tick */
#define SMSG_UPDATE_HOST 0x0063 /**< Custom update host packet */
#define SMSG_PLAYER_UPDATE_1 0x01d8
#define SMSG_PLAYER_UPDATE_2 0x01d9
@@ -66,6 +69,7 @@
#define SMSG_BEING_ACTION 0x008a /**< Attack, sit, stand up, ... */
#define SMSG_BEING_CHAT 0x008d /**< A being talks */
#define SMSG_BEING_NAME_RESPONSE 0x0095 /**< Has to be requested */
+
#define SMSG_NPC_MESSAGE 0x00b4
#define SMSG_NPC_NEXT 0x00b5
#define SMSG_NPC_CLOSE 0x00b6
@@ -75,11 +79,13 @@
#define SMSG_NPC_SELL 0x00c7
#define SMSG_NPC_BUY_RESPONSE 0x00ca
#define SMSG_NPC_SELL_RESPONSE 0x00cb
+
#define SMSG_PLAYER_CHAT 0x008e /**< Player talks */
#define SMSG_WHISPER 0x0097 /**< Whisper Recieved */
#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
@@ -88,7 +94,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
@@ -97,6 +123,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
@@ -113,6 +141,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 2bb5d9dc..b9a232fb 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 955aeff1..746e1d06 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"
@@ -188,11 +187,11 @@ void TradeHandler::handleMessage(MessageIn *msg)
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);
diff --git a/src/npc.cpp b/src/npc.cpp
index 66048005..8dbbf83c 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -19,15 +19,16 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "npc.h"
-
#include "animatedsprite.h"
#include "graphics.h"
+#include "localplayer.h"
+#include "npc.h"
#include "particle.h"
#include "text.h"
#include "net/messageout.h"
#include "net/protocol.h"
+
#include "resources/npcdb.h"
#include "gui/gui.h"
@@ -38,7 +39,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);
@@ -56,28 +57,52 @@ 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;
}
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, speechFont,
+ 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, npcNameFont,
gcn::Color(200, 200, 255));
+ Being::setName(displayName + " (NPC)");
+}
+
+void NPC::setGender(int 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
diff --git a/src/npc.h b/src/npc.h
index 5eb9036d..a37e8c66 100644
--- a/src/npc.h
+++ b/src/npc.h
@@ -22,13 +22,13 @@
#ifndef _TMW_NPC_H
#define _TMW_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,6 +36,8 @@ class NPC : public Being
~NPC();
void setName(const std::string &name);
+ void setGender(int gender);
+ void setSprite(int slot, int id, std::string color);
virtual Type
getType() const;
diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp
index d8d7a807..b3a8db4b 100644
--- a/src/openglgraphics.cpp
+++ b/src/openglgraphics.cpp
@@ -19,33 +19,32 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "main.h"
-
-#ifdef USE_OPENGL
+#include <cstring>
+#include <SDL.h>
-#ifndef GL_TEXTURE_RECTANGLE_ARB
-#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
-#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
-#endif
+#include <guichan/exception.hpp>
+#include <guichan/image.hpp>
+#include "log.h"
+#include "main.h"
#include "openglgraphics.h"
-#include <cstring>
-#include <SDL.h>
+#include "resources/image.h"
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif
-#include <guichan/exception.hpp>
-#include <guichan/image.hpp>
-
-#include "log.h"
+#ifdef USE_OPENGL
-#include "resources/image.h"
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8
+#endif
OpenGLGraphics::OpenGLGraphics():
- mAlpha(false), mTexture(false), mColorAlpha(false)
+ mAlpha(false), mTexture(false), mColorAlpha(false),
+ mSync(false)
{
}
@@ -53,6 +52,11 @@ OpenGLGraphics::~OpenGLGraphics()
{
}
+void OpenGLGraphics::setSync(bool sync)
+{
+ mSync = sync;
+}
+
bool OpenGLGraphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
{
logger->log("Setting video mode %dx%d %s",
@@ -76,6 +80,10 @@ bool OpenGLGraphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel)
#ifdef __APPLE__
// long VBL = 1;
// CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL);
+ if (mSync) {
+ const GLint VBL = 1;
+ CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL);
+ }
#endif
// Setup OpenGL
diff --git a/src/openglgraphics.h b/src/openglgraphics.h
index 7d39e306..ea30e019 100644
--- a/src/openglgraphics.h
+++ b/src/openglgraphics.h
@@ -31,6 +31,13 @@ class OpenGLGraphics : public Graphics
~OpenGLGraphics();
+ /**
+ * Sets whether vertical refresh syncing is enabled. Takes effect after
+ * the next call to setVideoMode(). Only implemented on MacOS for now.
+ */
+ void setSync(bool sync);
+ bool getSync() const { return mSync; }
+
bool setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel);
bool drawImage(Image *image,
@@ -72,6 +79,7 @@ class OpenGLGraphics : public Graphics
private:
bool mAlpha, mTexture;
bool mColorAlpha;
+ bool mSync;
};
#endif
diff --git a/src/particle.cpp b/src/particle.cpp
index d4266df2..f1896ae2 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -22,13 +22,12 @@
#include <algorithm>
#include <cmath>
-#include "particle.h"
-
#include "animationparticle.h"
#include "configuration.h"
#include "imageparticle.h"
#include "log.h"
#include "map.h"
+#include "particle.h"
#include "particleemitter.h"
#include "textparticle.h"
@@ -224,7 +223,7 @@ Particle::update()
Particle*
Particle::addEffect(const std::string &particleEffectFile,
- int pixelX, int pixelY)
+ int pixelX, int pixelY, int rotation)
{
Particle *newParticle = NULL;
@@ -288,7 +287,7 @@ 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);
}
@@ -358,11 +357,9 @@ Particle::~Particle()
void
Particle::clear()
{
- std::for_each(mChildEmitters.begin(), mChildEmitters.end(),
- make_dtor(mChildEmitters));
+ delete_all(mChildEmitters);
mChildEmitters.clear();
- std::for_each(mChildParticles.begin(), mChildParticles.end(),
- make_dtor(mChildParticles));
+ delete_all(mChildParticles);
mChildParticles.clear();
}
diff --git a/src/particle.h b/src/particle.h
index 6c00eadd..0a53f5af 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -107,7 +107,7 @@ class Particle : public Sprite
*/
Particle*
addEffect(const std::string &particleEffectFile,
- int pixelX, int pixelY);
+ int pixelX, int pixelY, int rotation = 0);
/**
* Creates a standalone text particle.
@@ -316,7 +316,7 @@ class Particle : public Sprite
// follow-point particles
Particle *mTarget; /**< The particle that attracts this particle*/
- float mAcceleration; /**< Acceleration towards the target particle in pixels per game-tick²*/
+ float mAcceleration; /**< Acceleration towards the target particle in pixels per game-tick�*/
float mInvDieDistance; /**< Distance in pixels from the target particle that causes the destruction of the particle*/
float mMomentum; /**< How much speed the particle retains after each game tick*/
};
diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp
index 5ae1aae5..03fe4672 100644
--- a/src/particleemitter.cpp
+++ b/src/particleemitter.cpp
@@ -19,24 +19,23 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "particleemitter.h"
-
#include "animationparticle.h"
#include "imageparticle.h"
#include "log.h"
#include "particle.h"
+#include "particleemitter.h"
#include "resources/animation.h"
#include "resources/image.h"
-#include "resources/resourcemanager.h"
#include "resources/imageset.h"
+#include "resources/resourcemanager.h"
#include <cmath>
#define SIN45 0.707106781f
#define DEG_RAD_FACTOR 0.017453293f
-ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map):
+ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map, int rotation):
mOutputPauseLeft(0),
mParticleImage(0)
{
@@ -102,7 +101,9 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *
else if (name == "horizontal-angle")
{
mParticleAngleHorizontal = readParticleEmitterProp(propertyNode, 0.0f);
+ mParticleAngleHorizontal.minVal += rotation;
mParticleAngleHorizontal.minVal *= DEG_RAD_FACTOR;
+ mParticleAngleHorizontal.maxVal += rotation;
mParticleAngleHorizontal.maxVal *= DEG_RAD_FACTOR;
mParticleAngleHorizontal.changeAmplitude *= DEG_RAD_FACTOR;
}
@@ -310,19 +311,19 @@ 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;
}
diff --git a/src/particleemitter.h b/src/particleemitter.h
index ad0e33f8..809a6ded 100644
--- a/src/particleemitter.h
+++ b/src/particleemitter.h
@@ -44,7 +44,7 @@ class ParticleEmitter
/**
* Constructor.
*/
- ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map);
+ ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map *map, int rotation = 0);
/**
* Copy Constructor (necessary for reference counting of particle images)
diff --git a/src/particleemitterprop.h b/src/particleemitterprop.h
index 70a04aee..f9c329a9 100644
--- a/src/particleemitterprop.h
+++ b/src/particleemitterprop.h
@@ -19,8 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <cstdlib>
#include <cmath>
+#include <cstdlib>
/**
* Returns a random numeric value that is larger than or equal min and smaller
diff --git a/src/party.cpp b/src/party.cpp
new file mode 100644
index 00000000..3df2eedc
--- /dev/null
+++ b/src/party.cpp
@@ -0,0 +1,216 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "beingmanager.h"
+#include "game.h"
+#include "localplayer.h"
+#include "party.h"
+
+#include "gui/chat.h"
+#include "gui/confirm_dialog.h"
+
+#include "net/messageout.h"
+#include "net/protocol.h"
+
+Party::Party(ChatWindow *chat, Network *network) :
+ mChat(chat), mNetwork(network), mInviteListener(network, &mInParty)
+{
+}
+
+void Party::respond(const std::string &command, const std::string &args)
+{
+ if (command == "new" || command == "create")
+ {
+ create(args);
+ return;
+ }
+ if (command == "leave")
+ {
+ leave(args);
+ return;
+ }
+ if (command == "settings")
+ {
+ mChat->chatLog("Not yet implemented!", BY_SERVER);
+ return;
+ /*
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_PARTY_SETTINGS);
+ outMsg.writeInt16(0); // Experience
+ outMsg.writeInt16(0); // Item
+ */
+ }
+ mChat->chatLog("Party command not known.", BY_SERVER);
+}
+
+void Party::create(const std::string &party)
+{
+ if (party == "")
+ {
+ mChat->chatLog("Party name is missing.", BY_SERVER);
+ return;
+ }
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_PARTY_CREATE);
+ outMsg.writeString(party.substr(0, 23), 24);
+ mCreating = true;
+}
+
+void Party::leave(const std::string &args)
+{
+ MessageOut outMsg(mNetwork);
+ outMsg.writeInt16(CMSG_PARTY_LEAVE);
+ mChat->chatLog("Left party.", BY_SERVER);
+ mInParty = false;
+}
+
+void Party::createResponse(bool ok)
+{
+ if (ok)
+ {
+ mChat->chatLog("Party successfully created.", BY_SERVER);
+ mInParty = true;
+ }
+ else
+ {
+ mChat->chatLog("Could not create party.", BY_SERVER);
+ }
+}
+
+void Party::inviteResponse(const std::string &nick, int status)
+{
+ switch (status)
+ {
+ case 0:
+ mChat->chatLog(nick + " is already a member of a party.",
+ BY_SERVER);
+ break;
+ case 1:
+ mChat->chatLog(nick + " refused your invitation.", BY_SERVER);
+ break;
+ case 2:
+ mChat->chatLog(nick + " is now a member of your party.",
+ BY_SERVER);
+ break;
+ }
+}
+
+void Party::invitedAsk(const std::string &nick, int gender,
+ const std::string &partyName)
+{
+ mPartyName = partyName; /* Quick and nasty - needs redoing */
+ if (nick == "")
+ {
+ mChat->chatLog("Something\'s wrong!", BY_SERVER);
+ return;
+ }
+ mCreating = false;
+ ConfirmDialog *dlg = new ConfirmDialog("Invite to party",
+ nick + " invites you to join " +
+ (gender == 0 ? "his" : "her") +
+ " party, " + partyName +
+ ", do you accept?");
+ 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(nick + " has left your party.", BY_SERVER);
+}
+
+void Party::receiveChat(Being *being, const std::string &msg)
+{
+ if (being == NULL)
+ {
+ return;
+ }
+ if (being->getType() != Being::PLAYER)
+ {
+ mChat->chatLog("Something\'s wrong!", BY_SERVER);
+ return;
+ }
+ being->setSpeech(msg, SPEECH_TIME);
+ mChat->chatLog(being->getName() + " : " + msg, BY_PARTY);
+}
+
+void Party::help()
+{
+ mChat->chatLog("/party <command> <params>: Party commands.", BY_SERVER);
+}
+
+void Party::help(const std::string &msg)
+{
+ if (msg == "")
+ {
+ mChat->chatLog("Command: /party <command> <args>", BY_SERVER);
+ mChat->chatLog("where <command> can be one of:", BY_SERVER);
+ mChat->chatLog(" /new", BY_SERVER);
+ mChat->chatLog(" /create", BY_SERVER);
+ mChat->chatLog(" /prefix", BY_SERVER);
+ mChat->chatLog(" /leave", BY_SERVER);
+ mChat->chatLog("This command implements the partying function.",
+ BY_SERVER);
+ mChat->chatLog("Type /help party <command> for further help.",
+ BY_SERVER);
+ return;
+ }
+ if (msg == "new" || msg == "create")
+ {
+ mChat->chatLog("Command: /party new <party-name>", BY_SERVER);
+ mChat->chatLog("Command: /party create <party-name>", BY_SERVER);
+ mChat->chatLog("These commands create a new party <party-name.",
+ BY_SERVER);
+ return;
+ }
+ if (msg == "prefix")
+ {
+ mChat->chatLog("Command: /party prefix <prefix-char>", BY_SERVER);
+ mChat->chatLog("This command sets the party prefix character.",
+ BY_SERVER);
+ mChat->chatLog("Any message preceded by <prefix-char> is sent to "
+ "the party instead of everyone.", BY_SERVER);
+ mChat->chatLog("Command: /party prefix", BY_SERVER);
+ mChat->chatLog("This command reports the current party prefix "
+ "character.", BY_SERVER);
+ return;
+ }
+ //if (msg == "settings")
+ //if (msg == "info")
+ if (msg == "leave")
+ {
+ mChat->chatLog("Command: /party leave", BY_SERVER);
+ mChat->chatLog("This command causes the player to leave the party.",
+ BY_SERVER);
+ return;
+ }
+ mChat->chatLog("Unknown /party command.", BY_SERVER);
+ mChat->chatLog("Type /help party for a list of options.", BY_SERVER);
+}
diff --git a/src/party.h b/src/party.h
new file mode 100644
index 00000000..0e1afc3c
--- /dev/null
+++ b/src/party.h
@@ -0,0 +1,73 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMW_PARTY_H
+#define _TMW_PARTY_H
+
+#include <string>
+
+#include <guichan/actionlistener.hpp>
+
+class PartyHandler;
+class Being;
+class ChatWindow;
+class Network;
+
+class Party
+{
+ public:
+ Party(ChatWindow *chat, Network *network);
+ void respond(const std::string &command, const std::string &args);
+
+ void create(const std::string &party);
+ void leave(const std::string &args);
+
+ void createResponse(bool ok);
+ void inviteResponse(const std::string &nick, int status);
+ void invitedAsk(const std::string &nick, int gender,
+ const std::string &partyName);
+ void leftResponse(const std::string &nick);
+ void receiveChat(Being *being, const std::string &msg);
+
+ void help();
+ void help(const std::string &msg);
+ private:
+ ChatWindow *mChat;
+ std::string mPartyName;
+ Network *mNetwork;
+ bool mInParty;
+ bool mCreating; /**< Used to give an appropriate response to
+ failure */
+ PartyHandler *handler;
+
+ class InviteListener : public gcn::ActionListener
+ {
+ public:
+ InviteListener(Network *network, bool *inParty) :
+ mNetwork(network), mInParty(inParty) {};
+ void action(const gcn::ActionEvent &event);
+ Network *mNetwork;
+ private:
+ bool *mInParty;
+ };
+ InviteListener mInviteListener;
+};
+#endif
diff --git a/src/player.cpp b/src/player.cpp
index f43e54d5..e6244bb5 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -19,21 +19,21 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "player.h"
+#include <iostream>
#include "animatedsprite.h"
#include "game.h"
#include "graphics.h"
#include "log.h"
+#include "player.h"
+
+#include "gui/gui.h"
#include "resources/itemdb.h"
#include "resources/iteminfo.h"
#include "utils/strprintf.h"
-#include "gui/gui.h"
-#include <iostream>
-
static const int NAME_X_OFFSET = 15;
static const int NAME_Y_OFFSET = 30;
@@ -41,6 +41,7 @@ Player::Player(int id, int job, Map *map):
Being(id, job, map)
{
mName = 0;
+ mIsGM = false;
}
Player::~Player()
@@ -55,9 +56,15 @@ 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,
- speechFont, gcn::Color(255, 255, 255));
+ if (mIsGM) {
+ mName = new FlashText("(GM) " + name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
+ gcn::Graphics::CENTER,
+ gmNameFont, gcn::Color(255, 255, 255));
+ } else {
+ mName = new FlashText(name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET,
+ gcn::Graphics::CENTER,
+ speechFont, gcn::Color(255, 255, 255));
+ }
Being::setName(name);
}
}
@@ -66,6 +73,18 @@ 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) {
@@ -138,13 +157,13 @@ void Player::setGender(int 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);
}
@@ -194,4 +213,3 @@ void Player::updateCoords()
}
}
-
diff --git a/src/player.h b/src/player.h
index 4676124c..c91ad3c2 100644
--- a/src/player.h
+++ b/src/player.h
@@ -80,7 +80,6 @@ class Player : public Being
protected:
void updateCoords();
-
private:
FlashText *mName;
};
diff --git a/src/player_relations.cpp b/src/player_relations.cpp
index c494dc74..ef00a738 100644
--- a/src/player_relations.cpp
+++ b/src/player_relations.cpp
@@ -19,12 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <algorithm>
+
#include "beingmanager.h"
-#include "player_relations.h"
#include "graphics.h"
-#include "gui/gui.h"
+#include "player_relations.h"
-#include <algorithm>
+#include "gui/gui.h"
#define PLAYER_IGNORE_STRATEGY_NOP "nop"
#define PLAYER_IGNORE_STRATEGY_EMOTE0 "emote0"
diff --git a/src/player_relations.h b/src/player_relations.h
index ec93b4dc..56f3d5a4 100644
--- a/src/player_relations.h
+++ b/src/player_relations.h
@@ -22,13 +22,14 @@
#ifndef TMW_PLAYER_RELATIONS_H_
#define TMW_PLAYER_RELATIONS_H_
-#include "being.h"
-#include "player.h"
-#include "configuration.h"
-#include <string>
+#include <list>
#include <map>
+#include <string>
#include <vector>
-#include <list>
+
+#include "being.h"
+#include "configuration.h"
+#include "player.h"
struct PlayerRelation
{
diff --git a/src/properties.h b/src/properties.h
index 2eafeeca..86fffea3 100644
--- a/src/properties.h
+++ b/src/properties.h
@@ -23,8 +23,8 @@
#define _TMW_PROPERTIES_H_
#include <map>
-#include <string>
#include <sstream>
+#include <string>
/**
* A class holding a set of properties.
diff --git a/src/recorder.cpp b/src/recorder.cpp
new file mode 100644
index 00000000..7bf618c5
--- /dev/null
+++ b/src/recorder.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "recorder.h"
+
+#include "gui/buttonbox.h"
+#include "gui/chat.h"
+
+#include "utils/trim.h"
+
+Recorder::Recorder(ChatWindow *chat) : mChat(chat)
+{
+ mButtonBox = new ButtonBox("Recording...", "Stop recording", this);
+ mButtonBox->setY(20);
+}
+
+void Recorder::record(const std::string &msg)
+{
+ if (mStream.is_open())
+ {
+ mStream << msg << std::endl;
+ }
+}
+
+void Recorder::respond(const std::string &msg)
+{
+ std::string msgCopy = msg;
+ trim(msgCopy);
+ if (msgCopy == "")
+ {
+ if (mStream.is_open())
+ {
+ mStream.close();
+ mButtonBox->setVisible(false);
+ /*
+ * Message should go after mStream is closed so that it isn't
+ * recorded.
+ */
+ mChat->chatLog("Finishing recording.", BY_SERVER);
+ }
+ else
+ {
+ mChat->chatLog("Not currently recording.", BY_SERVER);
+ }
+ return;
+ }
+ if (mStream.is_open())
+ {
+ mChat->chatLog("Already recording.", BY_SERVER);
+ }
+ else
+ {
+ /*
+ * Message should go before mStream is opened so that it isn't
+ * recorded.
+ */
+ mChat->chatLog("Starting to record...", BY_SERVER);
+ mStream.open(msg.c_str(), std::ios_base::trunc);
+ if (mStream.is_open())
+ {
+ mButtonBox->setVisible(true);
+ }
+ else
+ {
+ mChat->chatLog("Failed to start recording.", BY_SERVER);
+ }
+ }
+}
+
+void Recorder::help() const
+{
+ mChat->chatLog("/record <filename>: Start recording the chat.", BY_SERVER);
+}
+
+void Recorder::help(const std::string &args) const
+{
+ mChat->chatLog("Command: /record <filename>", BY_SERVER);
+ mChat->chatLog("This command starts recording the chat log to the file "
+ "<filename>.", BY_SERVER);
+ mChat->chatLog("Command: /record", BY_SERVER);
+ mChat->chatLog("This command finishes a recording session.", BY_SERVER);
+}
+
+void Recorder::buttonBoxRespond()
+{
+ respond("");
+}
+
+Recorder::~Recorder()
+{
+ delete mButtonBox;
+}
diff --git a/src/recorder.h b/src/recorder.h
new file mode 100644
index 00000000..9f30184f
--- /dev/null
+++ b/src/recorder.h
@@ -0,0 +1,48 @@
+/*
+ * 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 _TMW_RECORD_H
+#define _TMW_RECORD_H
+
+#include <fstream>
+#include <string>
+
+#include "gui/buttonbox.h"
+
+class ChatWindow;
+
+class Recorder : public ButtonBoxListener
+{
+ public:
+ Recorder(ChatWindow *chat);
+ void record(const std::string &msg);
+ void respond(const std::string &msg);
+ void help() const;
+ void help(const std::string &args) const;
+ void buttonBoxRespond();
+ bool isRecording() const {return mStream;}
+ virtual ~Recorder();
+ private:
+ ChatWindow *mChat;
+ std::ofstream mStream;
+ ButtonBox *mButtonBox;
+};
+#endif
diff --git a/src/resources/action.cpp b/src/resources/action.cpp
index ffbbffb2..f40d3109 100644
--- a/src/resources/action.cpp
+++ b/src/resources/action.cpp
@@ -20,22 +20,17 @@
*/
#include "action.h"
-
-#include <algorithm>
-
#include "animation.h"
#include "../utils/dtor.h"
-
Action::Action()
{
}
Action::~Action()
{
- std::for_each(mAnimations.begin(), mAnimations.end(),
- make_dtor(mAnimations));
+ delete_all(mAnimations);
}
Animation*
diff --git a/src/resources/ambientoverlay.cpp b/src/resources/ambientoverlay.cpp
index 9eee57f0..38d8fc46 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 d2794e61..596c5fac 100644
--- a/src/resources/animation.cpp
+++ b/src/resources/animation.cpp
@@ -19,10 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "animation.h"
-
#include <algorithm>
+#include "animation.h"
+
#include "../utils/dtor.h"
Animation::Animation():
diff --git a/src/resources/buddylist.cpp b/src/resources/buddylist.cpp
index c85105c5..1bd98680 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()
{
diff --git a/src/resources/colordb.cpp b/src/resources/colordb.cpp
new file mode 100644
index 00000000..3d2e15e0
--- /dev/null
+++ b/src/resources/colordb.cpp
@@ -0,0 +1,126 @@
+/*
+ * Aethyra
+ * Copyright 2008 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <cassert>
+#include <libxml/tree.h>
+
+#include "colordb.h"
+
+#include "../log.h"
+
+#include "../utils/dtor.h"
+#include "../utils/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");
+
+ logger->log("%d %s", id, mColors[id].c_str());
+ }
+ }
+
+ 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..2b750fa3
--- /dev/null
+++ b/src/resources/colordb.h
@@ -0,0 +1,52 @@
+/*
+ * Aethyra
+ * Copyright 2008 Aethyra Development Team
+ *
+ * This file is part of Aethyra.
+ *
+ * Aethyra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * Aethyra is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aethyra; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _AETHYRA_COLOR_MANAGER_H
+#define _AETHYRA_COLOR_MANAGER_H
+
+#include <map>
+#include <string>
+
+/**
+ * The class that holds the color information.
+ */
+namespace ColorDB
+{
+ /**
+ * Loads the color data from <code>colors.xml</code>.
+ */
+ void load();
+
+ /**
+ * Clear the color data
+ */
+ void unload();
+
+ std::string& get(int id);
+
+ int size();
+
+ // Color DB
+ typedef std::map<int, std::string> Colors;
+ typedef Colors::iterator ColorIterator;
+};
+
+#endif
diff --git a/src/resources/dye.h b/src/resources/dye.h
index 528a1d91..4fb8fd40 100644
--- a/src/resources/dye.h
+++ b/src/resources/dye.h
@@ -22,6 +22,7 @@
#ifndef _TMW_DYE_H
#define _TMW_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(std::string const &);
+ Palette(std::string const &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(std::string const &);
+ Dye(std::string const &dye);
/**
* Destroys the associated palettes.
diff --git a/src/resources/image.cpp b/src/resources/image.cpp
index 77d77f96..35b9c254 100644
--- a/src/resources/image.cpp
+++ b/src/resources/image.cpp
@@ -21,9 +21,8 @@
#include <SDL_image.h>
-#include "image.h"
-
#include "dye.h"
+#include "image.h"
#include "../log.h"
diff --git a/src/resources/image.h b/src/resources/image.h
index 3677696f..6eb33ed9 100644
--- a/src/resources/image.h
+++ b/src/resources/image.h
@@ -22,9 +22,10 @@
#ifndef _TMW_IMAGE_H
#define _TMW_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
diff --git a/src/resources/imageloader.cpp b/src/resources/imageloader.cpp
index 29458ba3..a7e813d7 100644
--- a/src/resources/imageloader.cpp
+++ b/src/resources/imageloader.cpp
@@ -21,12 +21,12 @@
#include <cassert>
#include <string>
+
#include <guichan/color.hpp>
#include <guichan/sdl/sdlpixel.hpp>
-#include "imageloader.h"
-
#include "image.h"
+#include "imageloader.h"
#include "resourcemanager.h"
ProxyImage::ProxyImage(SDL_Surface *s):
diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp
index d7398c17..b321439a 100644
--- a/src/resources/imageset.cpp
+++ b/src/resources/imageset.cpp
@@ -19,14 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
-
+#include "image.h"
#include "imageset.h"
#include "../log.h"
-#include "image.h"
-
#include "../utils/dtor.h"
ImageSet::ImageSet(Image *img, int width, int height)
@@ -44,11 +41,10 @@ ImageSet::ImageSet(Image *img, int width, int height)
ImageSet::~ImageSet()
{
- for_each(mImages.begin(), mImages.end(), make_dtor(mImages));
+ 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 58b7a8ea..26ce99ea 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 d6d8a6c2..36805646 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/itemdb.cpp b/src/resources/itemdb.cpp
index e6f2fd1f..f4ccc511 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -19,12 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
#include <cassert>
+
#include <libxml/tree.h>
#include "itemdb.h"
-
#include "iteminfo.h"
#include "resourcemanager.h"
@@ -83,7 +82,7 @@ void ItemDB::load()
}
int type = XML::getProperty(node, "type", 0);
- int weight = XML::getProperty(node, "weight", 0);
+ //int weight = XML::getProperty(node, "weight", 0);
int view = XML::getProperty(node, "view", 0);
std::string name = XML::getProperty(node, "name", "");
@@ -101,7 +100,7 @@ void ItemDB::load()
itemInfo->setEffect(effect);
itemInfo->setType(type);
itemInfo->setView(view);
- itemInfo->setWeight(weight);
+ //itemInfo->setWeight(weight);
itemInfo->setWeaponType(weaponType);
for_each_xml_child_node(itemChild, node)
@@ -126,7 +125,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);
@@ -144,7 +143,7 @@ void ItemDB::unload()
delete mUnknown;
mUnknown = NULL;
- for_each(mItemInfos.begin(), mItemInfos.end(), make_dtor(mItemInfos));
+ delete_all(mItemInfos);
mItemInfos.clear();
mLoaded = false;
}
@@ -175,7 +174,6 @@ void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node)
{
itemInfo->setSprite(filename, 0);
}
-
if (gender == "female" || gender == "unisex")
{
itemInfo->setSprite(filename, 1);
diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h
index 62a1e94c..9b661a60 100644
--- a/src/resources/itemdb.h
+++ b/src/resources/itemdb.h
@@ -22,10 +22,10 @@
#ifndef _TMW_ITEM_MANAGER_H
#define _TMW_ITEM_MANAGER_H
-#include "iteminfo.h"
-
#include <map>
+#include "iteminfo.h"
+
/**
* The namespace that holds the item information.
*/
diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp
index fb2c8ffe..5daeafe6 100644
--- a/src/resources/iteminfo.cpp
+++ b/src/resources/iteminfo.cpp
@@ -19,9 +19,8 @@
* 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(int gender) const
diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp
index 4c37c239..b4beb558 100644
--- a/src/resources/mapreader.cpp
+++ b/src/resources/mapreader.cpp
@@ -19,14 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "mapreader.h"
-
#include <cassert>
#include <iostream>
#include <zlib.h>
-#include "resourcemanager.h"
#include "image.h"
+#include "mapreader.h"
+#include "resourcemanager.h"
#include "../log.h"
#include "../map.h"
@@ -143,8 +142,7 @@ inflateMemory(unsigned char *in, unsigned int inLength,
return outLength;
}
-Map*
-MapReader::readMap(const std::string &filename)
+Map* MapReader::readMap(const std::string &filename)
{
// Load the file through resource manager
ResourceManager *resman = ResourceManager::getInstance();
@@ -207,14 +205,11 @@ 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)
{
@@ -238,8 +233,8 @@ 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)
{
@@ -289,8 +284,7 @@ MapReader::readMap(xmlNodePtr node, const std::string &path)
return map;
}
-void
-MapReader::readProperties(xmlNodePtr node, Properties* props)
+void MapReader::readProperties(xmlNodePtr node, Properties* props)
{
for_each_xml_child_node(childNode, node)
{
@@ -329,8 +323,8 @@ 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;
@@ -365,15 +359,15 @@ MapReader::readLayer(xmlNodePtr node, Map *map)
xmlNodePtr dataChild = childNode->xmlChildrenNode;
if (!dataChild)
continue;
-
+
int len = strlen((const char*)dataChild->content) + 1;
unsigned char *charData = new unsigned char[len + 1];
const char *charStart = (const char*)dataChild->content;
unsigned char *charIndex = charData;
-
+
while (*charStart) {
if (*charStart != ' ' && *charStart != '\t' &&
- *charStart != '\n')
+ *charStart != '\n')
{
*charIndex = *charStart;
charIndex++;
@@ -426,10 +420,10 @@ MapReader::readLayer(xmlNodePtr node, Map *map)
}
}
else {
- // Read plain XML map file
- for_each_xml_child_node(childNode2, childNode)
- {
- if (!xmlStrEqual(childNode2->name, BAD_CAST "tile"))
+ // Read plain XML map file
+ for_each_xml_child_node(childNode2, childNode)
+ {
+ if (!xmlStrEqual(childNode2->name, BAD_CAST "tile"))
continue;
const int gid = XML::getProperty(childNode2, "gid", -1);
@@ -443,12 +437,12 @@ MapReader::readLayer(xmlNodePtr node, Map *map)
}
}
}
-
+
if (y < h)
std::cerr << "TOO SMALL!\n";
if (x)
std::cerr << "TOO SMALL!\n";
-
+
// There can be only one data element
break;
}
@@ -459,13 +453,17 @@ MapReader::readTileset(xmlNodePtr node,
const std::string &path,
Map *map)
{
+ int firstGid = XML::getProperty(node, "firstgid", 0);
+ XML::Document* doc = NULL;
+
if (xmlHasProp(node, BAD_CAST "source"))
{
- logger->log("Warning: External tilesets not supported yet.");
- return NULL;
+ std::string filename = XML::getProperty(node, "source", "");
+ 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());
@@ -479,7 +477,8 @@ MapReader::readTileset(xmlNodePtr node,
if (!source.empty())
{
std::string sourceStr = source;
- sourceStr.erase(0, 3); // Remove "../"
+ while (sourceStr.substr(0, 3) == "../")
+ sourceStr.erase(0, 3); // Remove "../"
ResourceManager *resman = ResourceManager::getInstance();
Image* tilebmp = resman->getImage(sourceStr);
@@ -488,11 +487,11 @@ MapReader::readTileset(xmlNodePtr node,
{
Tileset *set = new Tileset(tilebmp, tw, th, firstGid);
tilebmp->decRef();
+ delete doc;
return set;
}
else {
- logger->log("Warning: Failed to load tileset (%s)",
- source.c_str());
+ logger->log("Warning: Failed to load tileset (%s)", source.c_str());
}
}
@@ -500,5 +499,7 @@ MapReader::readTileset(xmlNodePtr node,
break;
}
+ delete doc;
+
return NULL;
}
diff --git a/src/resources/mapreader.h b/src/resources/mapreader.h
index 0142eb45..ef52564e 100644
--- a/src/resources/mapreader.h
+++ b/src/resources/mapreader.h
@@ -26,8 +26,8 @@
#include <libxml/tree.h>
-class Properties;
class Map;
+class Properties;
class Tileset;
/**
diff --git a/src/resources/monsterdb.cpp b/src/resources/monsterdb.cpp
index 11b2baf7..4d52b8ad 100644
--- a/src/resources/monsterdb.cpp
+++ b/src/resources/monsterdb.cpp
@@ -19,10 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
-
#include "monsterdb.h"
-
#include "resourcemanager.h"
#include "../log.h"
@@ -126,6 +123,12 @@ MonsterDB::load()
}
}
+ 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(
@@ -141,8 +144,7 @@ MonsterDB::load()
void
MonsterDB::unload()
{
- for_each(mMonsterInfos.begin(), mMonsterInfos.end(),
- make_dtor(mMonsterInfos));
+ delete_all(mMonsterInfos);
mMonsterInfos.clear();
mLoaded = false;
diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp
index 7661c86b..4a71a122 100644
--- a/src/resources/monsterinfo.cpp
+++ b/src/resources/monsterinfo.cpp
@@ -19,8 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <algorithm>
-
#include "monsterinfo.h"
#include "../utils/dtor.h"
@@ -33,8 +31,7 @@ MonsterInfo::MonsterInfo()
MonsterInfo::~MonsterInfo()
{
// kill vectors in mSoundEffects
- for_each (mSounds.begin(), mSounds.end(),
- make_dtor(mSounds));
+ delete_all(mSounds);
mSounds.clear();
}
diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h
index 84b131c6..05a78c5a 100644
--- a/src/resources/monsterinfo.h
+++ b/src/resources/monsterinfo.h
@@ -22,14 +22,13 @@
#ifndef _TMW_MONSTERINFO_H_
#define _TMW_MONSTERINFO_H_
+#include <list>
#include <map>
#include <string>
#include <vector>
-#include <list>
#include "../being.h"
-
enum MonsterSoundEvent
{
MONSTER_EVENT_HIT,
@@ -85,11 +84,19 @@ class MonsterInfo
std::string
getSound(MonsterSoundEvent event) const;
+ std::string
+ getAttackParticleEffect() const { return mAttackParticle; }
+
+ void
+ addAttackParticleEffect(const std::string &particleEffect)
+ { mAttackParticle = particleEffect; }
+
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/npcdb.cpp b/src/resources/npcdb.cpp
index 2f8d78d4..3ae58067 100644
--- a/src/resources/npcdb.cpp
+++ b/src/resources/npcdb.cpp
@@ -20,7 +20,6 @@
*/
#include "npcdb.h"
-
#include "resourcemanager.h"
#include "../log.h"
diff --git a/src/resources/npcdb.h b/src/resources/npcdb.h
index 00b4f99b..b4539866 100644
--- a/src/resources/npcdb.h
+++ b/src/resources/npcdb.h
@@ -22,8 +22,8 @@
#ifndef _TMW_NPC_DB_H
#define _TMW_NPC_DB_H
-#include <map>
#include <list>
+#include <map>
#include <string>
struct NPCsprite
diff --git a/src/resources/resource.cpp b/src/resources/resource.cpp
index 449caf55..e9310905 100644
--- a/src/resources/resource.cpp
+++ b/src/resources/resource.cpp
@@ -22,7 +22,6 @@
#include <cassert>
#include "resource.h"
-
#include "resourcemanager.h"
Resource::~Resource()
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index 90b29374..510a16bd 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()
@@ -208,7 +206,7 @@ ResourceManager::getPath(const std::string &file)
// get the real path to the file
const char* tmp = PHYSFS_getRealDir(file.c_str());
std::string path;
-
+
// if the file is not in the search path, then its NULL
if (tmp)
{
@@ -217,9 +215,9 @@ 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(AETHYRA_DATADIR) + std::string("data") + "/" + file;
}
-
+
return path;
}
diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h
index 66813a9c..c814d752 100644
--- a/src/resources/resourcemanager.h
+++ b/src/resources/resourcemanager.h
@@ -27,11 +27,11 @@
#include <string>
#include <vector>
-class Resource;
class Image;
+class ImageSet;
class Music;
+class Resource;
class SoundEffect;
-class ImageSet;
class SpriteDef;
struct SDL_Surface;
diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp
index 289df2e5..b4193fd3 100644
--- a/src/resources/spritedef.cpp
+++ b/src/resources/spritedef.cpp
@@ -21,14 +21,13 @@
#include <set>
-#include "spritedef.h"
-
#include "action.h"
#include "animation.h"
#include "dye.h"
#include "image.h"
#include "imageset.h"
#include "resourcemanager.h"
+#include "spritedef.h"
#include "../log.h"
#include "../utils/xml.h"
diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h
index c7b94d9a..4b712340 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;
diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp
index e8c26df1..544d02b5 100644
--- a/src/simpleanimation.cpp
+++ b/src/simpleanimation.cpp
@@ -19,15 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "simpleanimation.h"
-
#include "graphics.h"
#include "log.h"
+#include "simpleanimation.h"
#include "resources/image.h"
-#include "resources/resourcemanager.h"
#include "resources/imageset.h"
-
+#include "resources/resourcemanager.h"
SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode):
mAnimationTime(0),
diff --git a/src/sound.cpp b/src/sound.cpp
index 888dcc31..6d440134 100644
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -19,11 +19,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "sound.h"
-
#include <SDL.h>
#include "log.h"
+#include "sound.h"
+
#include "resources/resourcemanager.h"
#include "resources/soundeffect.h"
diff --git a/src/sound.h b/src/sound.h
index 0c2af74b..72180607 100644
--- a/src/sound.h
+++ b/src/sound.h
@@ -23,7 +23,6 @@
#define _TMW_SOUND_H
#include <SDL_mixer.h>
-
#include <string>
/** Sound engine
diff --git a/src/text.cpp b/src/text.cpp
index 22228ccb..4d36b8fc 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -1,30 +1,29 @@
-/*
- * The Mana World
- * Copyright 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 "text.h"
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
#include <cstring>
#include <guichan/font.hpp>
+#include "text.h"
#include "textmanager.h"
int Text::mInstances = 0;
diff --git a/src/text.h b/src/text.h
index 995b9a58..173a5686 100644
--- a/src/text.h
+++ b/src/text.h
@@ -1,28 +1,29 @@
-/*
- * The Mana World
- * Copyright 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
- */
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
-#ifndef _TMW_TEXT_H
-#define _TMW_TEXT_H
+#ifndef _AETHYRA_TEXT_H
+#define _AETHYRA_TEXT_H
#include "graphics.h"
+#include "guichanfwd.h"
#include <list>
@@ -75,17 +76,21 @@ class FlashText : public Text
gcn::Color colour);
/**
- * Flash the text for so many refreshes.
+ * Remove the text from the screen
+ */
+ virtual ~FlashText() {}
+
+ /**
+ * Flash the text for so many refreshes
*/
void flash(int time) {mTime = time; }
/**
- * Draws the text.
+ * Draws the text
*/
virtual void draw(Graphics *graphics, int xOff, int yOff);
private:
- int mTime; /**< Time left for flashing. */
+ int mTime; /**< Time left for flashing */
};
-
-#endif // _TMW_TEXT_H
+#endif
diff --git a/src/textmanager.cpp b/src/textmanager.cpp
index 49ad1824..cb5d0bf2 100644
--- a/src/textmanager.cpp
+++ b/src/textmanager.cpp
@@ -1,29 +1,28 @@
-/*
- * The Mana World
- * Copyright 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 "textmanager.h"
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
#include <cstring>
#include "text.h"
+#include "textmanager.h"
TextManager *textManager = 0;
diff --git a/src/textmanager.h b/src/textmanager.h
index ec82c61f..5b21ba81 100644
--- a/src/textmanager.h
+++ b/src/textmanager.h
@@ -1,26 +1,26 @@
-/*
- * The Mana World
- * Copyright 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
- */
+/***************************************************************************
+ * Copyright (C) 2008 by Douglas Boffey *
+ * *
+ * DougABoffey@netscape.net *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed with The Mana Experiment *
+ * in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
-#ifndef _TMW_TEXTMANAGER_H
-#define _TMW_TEXTMANAGER_H
+#ifndef _AETHYRA_TEXTMANAGER_H
+#define _AETHYRA_TEXTMANAGER_H
#include <list>
@@ -72,5 +72,4 @@ class TextManager
};
extern TextManager *textManager;
-
-#endif // _TMW_TEXTMANAGER_H
+#endif
diff --git a/src/textparticle.cpp b/src/textparticle.cpp
index 308c043d..ed9d5717 100644
--- a/src/textparticle.cpp
+++ b/src/textparticle.cpp
@@ -19,9 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "textparticle.h"
-
#include "graphics.h"
+#include "textparticle.h"
TextParticle::TextParticle(Map *map, const std::string &text,
int colorR, int colorG, int colorB,
diff --git a/src/textparticle.h b/src/textparticle.h
index 3a0ba674..f662621f 100644
--- a/src/textparticle.h
+++ b/src/textparticle.h
@@ -22,11 +22,10 @@
#ifndef _TEXTPARTICLE_H
#define _TEXTPARTICLE_H
-#include "particle.h"
-
#include <guichan/color.hpp>
#include "guichanfwd.h"
+#include "particle.h"
class TextParticle : public Particle
{
diff --git a/src/utils/base64.cpp b/src/utils/base64.cpp
index 8cea60f9..9d8ba836 100644
--- a/src/utils/base64.cpp
+++ b/src/utils/base64.cpp
@@ -27,8 +27,8 @@
+----------------------------------------------------------------------+
*/
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include "base64.h"
diff --git a/src/utils/dtor.h b/src/utils/dtor.h
index f7c790c6..514ea9e7 100644
--- a/src/utils/dtor.h
+++ b/src/utils/dtor.h
@@ -22,6 +22,7 @@
#ifndef _TMW_UTILS_DTOR_H
#define _TMW_UTILS_DTOR_H
+#include <algorithm>
#include <functional>
#include <utility>
@@ -44,4 +45,11 @@ inline dtor<typename Cont::value_type> make_dtor(Cont const&)
return dtor<typename Cont::value_type>();
}
+template<typename Container>
+inline void delete_all(Container &c)
+{
+ std::for_each(c.begin(), c.end(), make_dtor(c));
+}
+
+
#endif
diff --git a/src/utils/strprintf.cpp b/src/utils/strprintf.cpp
index c5d7a595..c532dd0d 100644
--- a/src/utils/strprintf.cpp
+++ b/src/utils/strprintf.cpp
@@ -45,3 +45,4 @@ std::string strprintf(char const *format, ...)
delete [] buf2;
return res;
}
+
diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp
index 47f1bd04..e511ced3 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
diff --git a/src/utils/xml.h b/src/utils/xml.h
index 5a5c756b..9e691963 100644
--- a/src/utils/xml.h
+++ b/src/utils/xml.h
@@ -22,10 +22,10 @@
#ifndef _TMW_XML_H
#define _TMW_XML_H
-#include <libxml/tree.h>
-
#include <string>
+#include <libxml/tree.h>
+
/**
* XML helper functions.
*/
diff --git a/src/vector.cpp b/src/vector.cpp
new file mode 100644
index 00000000..7d5f055a
--- /dev/null
+++ b/src/vector.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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 "vector.h"
+
+std::ostream& operator <<(std::ostream &os, const Vector &v)
+{
+ os << "Vector(" << v.x << ", " << v.y << ", " << v.z << ")";
+ return os;
+}
diff --git a/src/vector.h b/src/vector.h
index b19f6c64..f32b201a 100644
--- a/src/vector.h
+++ b/src/vector.h
@@ -22,6 +22,10 @@
#ifndef _TMW_VECTOR_H_
#define _TMW_VECTOR_H_
+#include <math.h>
+
+#include <iostream>
+
/**
* Vector class. Represents either a 3D point in space, a velocity or a force.
* Provides several convenient operator overloads.
@@ -41,7 +45,7 @@ class Vector
/**
* Constructor.
*/
- Vector(float x, float y, float z):
+ Vector(float x, float y, float z = 0.0f):
x(x),
y(y),
z(z)
@@ -69,11 +73,12 @@ class Vector
/**
* In-place scale vector operator.
*/
- void operator*=(float c)
+ Vector &operator*=(float c)
{
x *= c;
y *= c;
z *= c;
+ return *this;
}
/**
@@ -87,6 +92,17 @@ class Vector
}
/**
+ * In-place scale vector operator.
+ */
+ Vector &operator/=(float c)
+ {
+ x /= c;
+ y /= c;
+ z /= c;
+ return *this;
+ }
+
+ /**
* Add vector operator.
*/
Vector operator+(const Vector &v) const
@@ -99,11 +115,12 @@ class Vector
/**
* In-place add vector operator.
*/
- void operator+=(const Vector &v)
+ Vector &operator+=(const Vector &v)
{
x += v.x;
y += v.y;
z += v.z;
+ return *this;
}
/**
@@ -119,14 +136,55 @@ class Vector
/**
* In-place substract vector operator.
*/
- void operator-=(const Vector &v)
+ Vector &operator-=(const Vector &v)
{
x -= v.x;
y -= v.y;
z -= v.z;
+ return *this;
+ }
+
+ /**
+ * Returns the length of this vector. This method does a relatively
+ * slow square root.
+ */
+ float length() const
+ {
+ return sqrtf(x * x + y * y + z * z);
+ }
+
+ /**
+ * Returns the squared length of this vector. Avoids the square root.
+ */
+ float squaredLength() const
+ {
+ return x * x + y * y + z * z;
+ }
+
+ /**
+ * Returns the manhattan length of this vector.
+ */
+ float manhattanLength() const
+ {
+ return fabsf(x) + fabsf(y) + fabsf(z);
+ }
+
+ /**
+ * Returns a normalized version of this vector. This is a unit vector
+ * running parallel to it.
+ */
+ Vector normalized() const
+ {
+ const float l = length();
+ return Vector(x / l, y / l, z / l);
}
float x, y, z;
};
-#endif
+/**
+ * Appends a string representation of a vector to the output stream.
+ */
+std::ostream& operator <<(std::ostream &os, const Vector &v);
+
+#endif // _TMW_VECTOR_H_
diff --git a/src/winver.h b/src/winver.h
index 4452784e..f56d0c6b 100644
--- a/src/winver.h
+++ b/src/winver.h
@@ -1,6 +1,6 @@
-/* VERSION DEFINITIONS */
-#define VER_MAJOR 0
-#define VER_MINOR 0
-#define VER_RELEASE 26
-#define VER_BUILD 0
-#define PACKAGE_VERSION "0.0.26"
+/* VERSION DEFINITIONS */
+#define VER_MAJOR 0
+#define VER_MINOR 0
+#define VER_RELEASE 27
+#define VER_BUILD 0
+#define PACKAGE_VERSION "0.0.27"