diff options
Diffstat (limited to 'src')
374 files changed, 24967 insertions, 6217 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b1dd0e9..94688e66 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ FIND_PACKAGE(SDL REQUIRED) FIND_PACKAGE(SDL_image REQUIRED) FIND_PACKAGE(SDL_mixer REQUIRED) +FIND_PACKAGE(SDL_net REQUIRED) FIND_PACKAGE(SDL_ttf REQUIRED) FIND_PACKAGE(ENet REQUIRED) FIND_PACKAGE(CURL REQUIRED) @@ -28,6 +29,7 @@ INCLUDE_DIRECTORIES( ${SDL_INCLUDE_DIR} ${SDLIMAGE_INCLUDE_DIR} ${SDLMIXER_INCLUDE_DIR} + ${SDLNET_INCLUDE_DIR} ${SDLTTF_INCLUDE_DIR} ${ENET_INCLUDE_DIR} ${PNG_INCLUDE_DIR} @@ -45,6 +47,8 @@ MARK_AS_ADVANCED(SDLIMAGE_LIBRARY) MARK_AS_ADVANCED(SDLMAIN_LIBRARY) MARK_AS_ADVANCED(SDLMIXER_INCLUDE_DIR) MARK_AS_ADVANCED(SDLMIXER_LIBRARY) +MARK_AS_ADVANCED(SDLNET_INCLUDE_DIR) +MARK_AS_ADVANCED(SDLNET_LIBRARY) MARK_AS_ADVANCED(SDL_INCLUDE_DIR) MARK_AS_ADVANCED(SDL_LIBRARY) @@ -57,12 +61,12 @@ SET(SRCS gui/widgets/resizegrip.h gui/widgets/layout.cpp gui/widgets/layout.h + gui/widgets/layouthelper.cpp + gui/widgets/layouthelper.h gui/widgets/tab.cpp gui/widgets/tab.h gui/widgets/tabbedarea.cpp gui/widgets/tabbedarea.h - gui/box.cpp - gui/box.h gui/browserbox.cpp gui/browserbox.h gui/buddywindow.cpp @@ -77,6 +81,8 @@ SET(SRCS gui/changeemaildialog.h gui/changepassworddialog.cpp gui/changepassworddialog.h + gui/char_server.cpp + gui/char_server.h gui/char_select.cpp gui/char_select.h gui/chat.cpp @@ -85,12 +91,20 @@ SET(SRCS gui/chatinput.h gui/checkbox.cpp gui/checkbox.h + gui/color.cpp + gui/color.h gui/confirm_dialog.cpp gui/confirm_dialog.h gui/connection.cpp gui/connection.h gui/debugwindow.cpp gui/debugwindow.h + gui/emotecontainer.cpp + gui/emotecontainer.h + gui/emoteshortcutcontainer.cpp + gui/emoteshortcutcontainer.h + gui/emotewindow.cpp + gui/emotewindow.h gui/equipmentwindow.cpp gui/equipmentwindow.h gui/focushandler.cpp @@ -103,18 +117,14 @@ SET(SRCS gui/guildlistbox.h gui/guildwindow.cpp gui/guildwindow.h - gui/hbox.cpp - gui/hbox.h gui/help.cpp gui/help.h gui/icon.cpp gui/icon.h - gui/inttextbox.cpp - gui/inttextbox.h + gui/inttextfield.cpp + gui/inttextfield.h gui/inventorywindow.cpp gui/inventorywindow.h - gui/item_amount.cpp - gui/item_amount.h gui/itemcontainer.cpp gui/itemcontainer.h gui/itemlinkhandler.cpp @@ -122,9 +132,9 @@ SET(SRCS gui/itempopup.cpp gui/itempopup.h gui/itemshortcutcontainer.cpp - gui/itemshortcutcontainer.h - gui/itemshortcutwindow.cpp - gui/itemshortcutwindow.h + gui/itemshortcutcontainer.h\ + gui/item_amount.cpp + gui/item_amount.h gui/linkhandler.h gui/listbox.cpp gui/listbox.h @@ -138,8 +148,12 @@ SET(SRCS gui/minimap.h gui/ministatus.cpp gui/ministatus.h + gui/npcintegerdialog.cpp + gui/npcintegerdialog.h gui/npclistdialog.cpp gui/npclistdialog.h + gui/npcstringdialog.cpp + gui/npcstringdialog.h gui/npcpostdialog.cpp gui/npcpostdialog.h gui/npc_text.cpp @@ -160,6 +174,8 @@ SET(SRCS gui/quitdialog.h gui/radiobutton.cpp gui/radiobutton.h + gui/recorder.cpp + gui/recorder.h gui/register.cpp gui/register.h gui/scrollarea.cpp @@ -170,14 +186,18 @@ SET(SRCS gui/sell.h gui/serverdialog.cpp gui/serverdialog.h - gui/setup_audio.cpp - gui/setup_audio.h gui/setup.cpp gui/setup.h + gui/setup_audio.cpp + gui/setup_audio.h + gui/setup_colors.cpp + gui/setup_colors.h gui/setup_joystick.cpp gui/setup_joystick.h gui/setup_keyboard.cpp gui/setup_keyboard.h + gui/setup_players.cpp + gui/setup_players.h gui/setuptab.h gui/setup_video.cpp gui/setup_video.h @@ -185,6 +205,10 @@ SET(SRCS gui/shop.h gui/shoplistbox.cpp gui/shoplistbox.h + gui/shortcutwindow.cpp + gui/shortcutwindow.h + gui/shortcutcontainer.cpp + gui/shortcutcontainer.h gui/skill.cpp gui/skill.h gui/slider.cpp @@ -193,6 +217,10 @@ SET(SRCS gui/speechbubble.h gui/status.cpp gui/status.h + gui/table.cpp + gui/table.h + gui/table_model.cpp + gui/table_model.h gui/textbox.cpp gui/textbox.h gui/textdialog.cpp @@ -207,8 +235,6 @@ SET(SRCS gui/unregisterdialog.h gui/updatewindow.cpp gui/updatewindow.h - gui/vbox.cpp - gui/vbox.h gui/viewport.cpp gui/viewport.h gui/window.cpp @@ -225,6 +251,8 @@ SET(SRCS net/chathandler.h net/connection.cpp net/connection.h + net/equipmenthandler.cpp + net/equipmenthandler.h net/guildhandler.cpp net/guildhandler.h net/internal.cpp @@ -237,6 +265,8 @@ SET(SRCS net/loginhandler.h net/logouthandler.cpp net/logouthandler.h + net/maploginhandler.cpp + net/maploginhandler.h net/messagehandler.cpp net/messagehandler.h net/messagein.cpp @@ -251,7 +281,10 @@ SET(SRCS net/partyhandler.h net/playerhandler.cpp net/playerhandler.h + net/protocol.cpp net/protocol.h + net/skillhandler.cpp + net/skillhandler.h net/tradehandler.cpp net/tradehandler.h net/effecthandler.cpp @@ -284,8 +317,12 @@ SET(SRCS resources/animation.h resources/buddylist.cpp resources/buddylist.h + resources/colordb.cpp + resources/colordb.h resources/dye.cpp resources/dye.h + resources/emotedb.cpp + resources/emotedb.h resources/image.cpp resources/image.h resources/imageloader.cpp @@ -321,13 +358,12 @@ SET(SRCS utils/dtor.h utils/fastsqrt.h utils/gettext.h - utils/minmax.h utils/sha256.h utils/sha256.cpp + utils/stringutils.cpp + utils/stringutils.h utils/strprintf.cpp utils/strprintf.h - utils/tostring.h - utils/trim.h utils/xml.cpp utils/xml.h animatedsprite.cpp @@ -347,6 +383,10 @@ SET(SRCS configlistener.h configuration.cpp configuration.h + effectmanager.cpp + effectmanager.h + emoteshortcut.cpp + emoteshortcut.h engine.cpp engine.h equipment.cpp @@ -392,10 +432,17 @@ SET(SRCS openglgraphics.h particle.cpp particle.h + particlecontainer.cpp + particlecontainer.h particleemitter.cpp particleemitter.h + particleemitterprop.h + party.cpp + party.h player.cpp player.h + player_relations.cpp + player_relations.h position.cpp position.h properties.h @@ -407,6 +454,10 @@ SET(SRCS sound.cpp sound.h sprite.h + text.cpp + text.h + textmanager.cpp + textmanager.h textparticle.cpp textparticle.h tileset.h @@ -422,6 +473,7 @@ TARGET_LINK_LIBRARIES(tmw ${SDL_LIBRARY} ${SDLIMAGE_LIBRARY} ${SDLMIXER_LIBRARY} + ${SDLNET_LIBRARY} ${SDLTTF_LIBRARY} ${ENET_LIBRARIES} ${PNG_LIBRARIES} diff --git a/src/Makefile.am b/src/Makefile.am index d3926a70..ce51b12d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,34 +1,32 @@ AUTOMAKE_OPTIONS = subdir-objects bin_PROGRAMS = tmw + +tmw_CXXFLAGS = -DPKG_DATADIR=\""$(pkgdatadir)/"\" \ + -DLOCALEDIR=\""$(localedir)"\" + tmw_SOURCES = gui/widgets/avatar.cpp \ - gui/widgets/avatar.h \ - gui/widgets/dropdown.cpp \ + gui/widgets/avatar.h \ + gui/widgets/dropdown.cpp \ gui/widgets/dropdown.h \ gui/widgets/layout.cpp \ gui/widgets/layout.h \ + gui/widgets/layouthelper.cpp \ + gui/widgets/layouthelper.h \ gui/widgets/resizegrip.cpp \ gui/widgets/resizegrip.h \ gui/widgets/tab.cpp \ gui/widgets/tab.h \ gui/widgets/tabbedarea.cpp \ gui/widgets/tabbedarea.h \ - gui/box.h \ - gui/box.cpp \ gui/browserbox.cpp \ gui/browserbox.h \ - gui/buddywindow.cpp \ - gui/buddywindow.h \ gui/button.cpp \ gui/button.h \ gui/buy.cpp \ gui/buy.h \ gui/buysell.cpp \ gui/buysell.h \ - gui/changeemaildialog.cpp \ - gui/changeemaildialog.h \ - gui/changepassworddialog.cpp \ - gui/changepassworddialog.h \ gui/char_select.cpp \ gui/char_select.h \ gui/chat.cpp \ @@ -37,12 +35,18 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/chatinput.h \ gui/checkbox.cpp \ gui/checkbox.h \ + gui/color.cpp \ + gui/color.h \ gui/confirm_dialog.cpp \ gui/confirm_dialog.h \ - gui/connection.cpp \ - gui/connection.h \ gui/debugwindow.cpp \ gui/debugwindow.h \ + gui/emotecontainer.cpp \ + gui/emotecontainer.h \ + gui/emoteshortcutcontainer.cpp \ + gui/emoteshortcutcontainer.h \ + gui/emotewindow.cpp \ + gui/emotewindow.h \ gui/equipmentwindow.cpp \ gui/equipmentwindow.h \ gui/focushandler.cpp \ @@ -51,30 +55,22 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/gccontainer.h \ gui/gui.cpp \ gui/gui.h \ - gui/guildwindow.cpp \ - gui/guildwindow.h \ - gui/guildlistbox.cpp \ - gui/guildlistbox.h \ - gui/hbox.h \ - gui/hbox.cpp \ gui/help.cpp \ gui/help.h \ - gui/icon.h \ gui/icon.cpp \ - gui/inttextbox.h \ - gui/inttextbox.cpp \ + gui/icon.h \ + gui/inttextfield.cpp \ + gui/inttextfield.h \ gui/inventorywindow.cpp \ gui/inventorywindow.h \ gui/itemcontainer.cpp \ gui/itemcontainer.h \ - gui/itemlinkhandler.cpp \ - gui/itemlinkhandler.h \ + gui/itemlinkhandler.cpp \ + gui/itemlinkhandler.h \ gui/itempopup.cpp \ gui/itempopup.h \ gui/itemshortcutcontainer.cpp \ gui/itemshortcutcontainer.h \ - gui/itemshortcutwindow.cpp \ - gui/itemshortcutwindow.h \ gui/item_amount.cpp \ gui/item_amount.h \ gui/linkhandler.h \ @@ -82,26 +78,22 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/listbox.h \ gui/login.cpp \ gui/login.h \ - gui/magic.cpp \ - gui/magic.h \ gui/menuwindow.cpp \ gui/menuwindow.h \ gui/minimap.cpp \ gui/minimap.h \ gui/ministatus.cpp \ gui/ministatus.h \ + gui/npcintegerdialog.cpp \ + gui/npcintegerdialog.h \ gui/npclistdialog.cpp \ gui/npclistdialog.h \ - gui/npcpostdialog.cpp \ - gui/npcpostdialog.h \ + gui/npcstringdialog.cpp \ + gui/npcstringdialog.h \ gui/npc_text.cpp \ gui/npc_text.h \ gui/ok_dialog.cpp \ gui/ok_dialog.h \ - gui/truetypefont.cpp \ - gui/truetypefont.h \ - gui/partywindow.h \ - gui/partywindow.cpp \ gui/passwordfield.cpp \ gui/passwordfield.h \ gui/playerbox.cpp \ @@ -110,10 +102,10 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/popupmenu.h \ gui/progressbar.cpp \ gui/progressbar.h \ - gui/quitdialog.cpp \ - gui/quitdialog.h \ gui/radiobutton.cpp \ gui/radiobutton.h \ + gui/recorder.cpp \ + gui/recorder.h \ gui/register.cpp \ gui/register.h \ gui/scrollarea.cpp \ @@ -122,16 +114,18 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/sdlinput.h \ gui/sell.cpp \ gui/sell.h \ - gui/serverdialog.cpp \ - gui/serverdialog.h \ - gui/setup_audio.cpp \ - gui/setup_audio.h \ gui/setup.cpp \ gui/setup.h \ + gui/setup_audio.cpp \ + gui/setup_audio.h \ + gui/setup_colors.cpp \ + gui/setup_colors.h \ gui/setup_joystick.cpp \ gui/setup_joystick.h \ gui/setup_keyboard.cpp \ gui/setup_keyboard.h \ + gui/setup_players.cpp \ + gui/setup_players.h \ gui/setuptab.h \ gui/setup_video.cpp \ gui/setup_video.h \ @@ -139,14 +133,18 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/shop.h \ gui/shoplistbox.cpp \ gui/shoplistbox.h \ - gui/skill.cpp \ - gui/skill.h \ + gui/shortcutwindow.cpp \ + gui/shortcutwindow.h \ + gui/shortcutcontainer.cpp \ + gui/shortcutcontainer.h \ gui/slider.cpp \ gui/slider.h \ gui/speechbubble.cpp \ gui/speechbubble.h \ - gui/status.cpp \ - gui/status.h \ + gui/table.cpp \ + gui/table.h \ + gui/table_model.cpp \ + gui/table_model.h \ gui/textbox.cpp \ gui/textbox.h \ gui/textdialog.cpp \ @@ -155,87 +153,36 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ gui/textfield.h \ gui/trade.cpp \ gui/trade.h \ - gui/unregisterdialog.cpp \ - gui/unregisterdialog.h \ - gui/updatewindow.h \ + gui/truetypefont.cpp \ + gui/truetypefont.h \ gui/updatewindow.cpp \ - gui/vbox.h \ - gui/vbox.cpp \ + gui/updatewindow.h \ gui/viewport.cpp \ gui/viewport.h \ gui/window.cpp \ gui/window.h \ gui/windowcontainer.cpp \ gui/windowcontainer.h \ - net/beinghandler.h \ - net/beinghandler.cpp \ - net/buysellhandler.h \ - net/buysellhandler.cpp \ - net/charserverhandler.h \ - net/charserverhandler.cpp \ - net/chathandler.h \ - net/chathandler.cpp \ - net/connection.h \ - net/connection.cpp \ - net/guildhandler.cpp \ - net/guildhandler.h \ - net/internal.h \ - net/internal.cpp \ - net/inventoryhandler.h \ - net/inventoryhandler.cpp \ net/itemhandler.h \ net/itemhandler.cpp \ - net/loginhandler.h \ - net/loginhandler.cpp \ - net/logouthandler.cpp \ - net/logouthandler.h \ net/messagehandler.cpp \ net/messagehandler.h \ net/messagein.cpp \ net/messagein.h \ net/messageout.cpp \ net/messageout.h \ - net/network.cpp \ - net/network.h \ - net/npchandler.cpp \ - net/npchandler.h \ - net/partyhandler.cpp \ - net/partyhandler.h \ - net/playerhandler.cpp \ - net/playerhandler.h \ - net/protocol.h \ - net/tradehandler.cpp \ - net/tradehandler.h \ - net/effecthandler.h \ - net/effecthandler.cpp \ - net/accountserver/account.cpp \ - net/accountserver/account.h \ - net/accountserver/accountserver.cpp \ - net/accountserver/accountserver.h \ - net/accountserver/internal.cpp \ - net/accountserver/internal.h \ - net/chatserver/chatserver.cpp \ - net/chatserver/chatserver.h \ - net/chatserver/internal.cpp \ - net/chatserver/internal.h \ - net/chatserver/guild.cpp \ - net/chatserver/guild.h \ - net/chatserver/party.cpp \ - net/chatserver/party.h \ - net/gameserver/gameserver.cpp \ - net/gameserver/gameserver.h \ - net/gameserver/internal.cpp \ - net/gameserver/internal.h \ - net/gameserver/player.cpp \ - net/gameserver/player.h \ resources/action.cpp \ resources/action.h \ resources/ambientoverlay.cpp \ resources/ambientoverlay.h \ resources/animation.cpp \ resources/animation.h \ + resources/colordb.cpp \ + resources/colordb.h \ resources/dye.cpp \ resources/dye.h \ + resources/emotedb.cpp \ + resources/emotedb.h \ resources/image.cpp \ resources/image.h \ resources/imageloader.cpp \ @@ -266,20 +213,17 @@ tmw_SOURCES = gui/widgets/avatar.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 \ utils/fastsqrt.h \ utils/gettext.h \ - utils/minmax.h \ - utils/sha256.h \ utils/sha256.cpp \ + utils/sha256.h \ + utils/stringutils.cpp \ + utils/stringutils.h \ utils/strprintf.cpp \ utils/strprintf.h \ - utils/tostring.h \ - utils/trim.h \ utils/mutex.h \ utils/xml.cpp \ utils/xml.h \ @@ -295,11 +239,13 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ channel.h \ channelmanager.cpp \ channelmanager.h \ - commandhandler.cpp \ - commandhandler.h \ configlistener.h \ configuration.cpp \ configuration.h \ + effectmanager.cpp \ + effectmanager.h \ + emoteshortcut.cpp \ + emoteshortcut.h \ engine.cpp \ engine.h \ equipment.cpp \ @@ -312,8 +258,6 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ game.h \ graphics.cpp \ graphics.h \ - guild.cpp \ - guild.h \ guichanfwd.h \ imageparticle.cpp \ imageparticle.h \ @@ -345,10 +289,15 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ openglgraphics.h \ particle.cpp \ particle.h \ + particlecontainer.cpp \ + particlecontainer.h \ particleemitter.cpp \ particleemitter.h \ + particleemitterprop.h \ player.cpp \ player.h \ + player_relations.cpp \ + player_relations.h \ position.cpp \ position.h \ properties.h \ @@ -360,16 +309,154 @@ tmw_SOURCES = gui/widgets/avatar.cpp \ sound.cpp \ sound.h \ sprite.h \ + statuseffect.cpp \ + statuseffect.h \ + text.cpp \ + text.h \ + textmanager.cpp \ + textmanager.h \ textparticle.cpp \ textparticle.h \ tileset.h \ + units.cpp \ + units.h \ vector.cpp \ - vector.h \ - effectmanager.cpp \ - effectmanager.h + vector.h + +if SERVER_TMWSERV +tmw_CXXFLAGS += -DTMWSERV_SUPPORT +tmw_SOURCES += \ + gui/buddywindow.cpp \ + gui/buddywindow.h \ + gui/changeemaildialog.cpp \ + gui/changeemaildialog.h \ + gui/changepassworddialog.cpp \ + gui/changepassworddialog.h \ + gui/connection.cpp \ + gui/connection.h \ + gui/guildlistbox.cpp \ + gui/guildlistbox.h \ + gui/guildwindow.cpp \ + gui/guildwindow.h \ + gui/magic.cpp \ + gui/magic.h \ + gui/npcpostdialog.cpp \ + gui/npcpostdialog.h \ + gui/partywindow.cpp \ + gui/partywindow.h \ + gui/quitdialog.cpp \ + gui/quitdialog.h \ + gui/serverdialog.cpp \ + gui/serverdialog.h \ + gui/skilldialog.cpp \ + gui/skilldialog.h \ + gui/statuswindow.cpp \ + gui/statuswindow.h \ + gui/unregisterdialog.cpp \ + gui/unregisterdialog.h \ + net/accountserver/account.cpp \ + net/accountserver/account.h \ + net/accountserver/accountserver.cpp \ + net/accountserver/accountserver.h \ + net/accountserver/internal.cpp \ + net/accountserver/internal.h \ + net/chatserver/chatserver.cpp \ + net/chatserver/chatserver.h \ + net/chatserver/guild.cpp \ + net/chatserver/guild.h \ + net/chatserver/internal.cpp \ + net/chatserver/internal.h \ + net/chatserver/party.cpp \ + net/chatserver/party.h \ + net/gameserver/gameserver.cpp \ + net/gameserver/gameserver.h \ + net/gameserver/internal.cpp \ + net/gameserver/internal.h \ + net/gameserver/player.cpp \ + net/gameserver/player.h \ + net/beinghandler.cpp \ + net/beinghandler.h \ + net/buysellhandler.cpp \ + net/buysellhandler.h \ + net/charserverhandler.cpp \ + net/charserverhandler.h \ + net/chathandler.cpp \ + net/chathandler.h \ + net/connection.cpp \ + net/connection.h \ + net/effecthandler.cpp \ + net/effecthandler.h \ + net/guildhandler.cpp \ + net/guildhandler.h \ + net/internal.cpp \ + net/internal.h \ + net/inventoryhandler.cpp \ + net/inventoryhandler.h \ + net/loginhandler.cpp \ + net/loginhandler.h \ + net/logouthandler.cpp \ + net/logouthandler.h \ + net/network.cpp \ + net/network.h \ + net/npchandler.cpp \ + net/npchandler.h \ + net/partyhandler.cpp \ + net/partyhandler.h \ + net/playerhandler.cpp \ + net/playerhandler.h \ + net/protocol.h \ + net/tradehandler.cpp \ + net/tradehandler.h \ + resources/buddylist.cpp \ + resources/buddylist.h \ + commandhandler.cpp \ + commandhandler.h \ + guild.cpp \ + guild.h +endif + +if SERVER_EATHENA +tmw_CXXFLAGS += -DEATHENA_SUPPORT +tmw_SOURCES += \ + gui/char_server.cpp \ + gui/char_server.h \ + gui/skill.cpp \ + gui/skill.h \ + gui/status.cpp \ + gui/status.h \ + net/ea/beinghandler.cpp \ + net/ea/beinghandler.h \ + net/ea/buysellhandler.cpp \ + net/ea/buysellhandler.h \ + net/ea/charserverhandler.cpp \ + net/ea/charserverhandler.h \ + net/ea/chathandler.cpp \ + net/ea/chathandler.h \ + net/ea/equipmenthandler.cpp \ + net/ea/equipmenthandler.h \ + net/ea/inventoryhandler.cpp \ + net/ea/inventoryhandler.h \ + net/ea/loginhandler.cpp \ + net/ea/loginhandler.h \ + net/ea/maploginhandler.cpp \ + net/ea/maploginhandler.h \ + net/ea/network.cpp \ + net/ea/network.h \ + net/ea/npchandler.cpp \ + net/ea/npchandler.h \ + net/ea/partyhandler.cpp \ + net/ea/partyhandler.h \ + net/ea/playerhandler.cpp \ + net/ea/playerhandler.h \ + net/ea/protocol.cpp \ + net/ea/protocol.h \ + net/ea/skillhandler.cpp \ + net/ea/skillhandler.h \ + net/ea/tradehandler.cpp \ + net/ea/tradehandler.h \ + party.cpp \ + party.h +endif # set the include path found by configure -INCLUDES = \ - $(all_includes) \ - -DTMW_DATADIR=\""$(pkgdatadir)/"\" \ - -DLOCALEDIR=\""$(localedir)"\" +INCLUDES = $(all_includes) diff --git a/src/SDLMain.h b/src/SDLMain.h new file mode 100644 index 00000000..4683df57 --- /dev/null +++ b/src/SDLMain.h @@ -0,0 +1,11 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser <dwaliss1@purdue.edu> + Non-NIB-Code & other changes: Max Horn <max@quendi.de> + + Feel free to customize this file to suit your needs +*/ + +#import <Cocoa/Cocoa.h> + +@interface SDLMain : NSObject +@end diff --git a/src/SDLMain.m b/src/SDLMain.m new file mode 100644 index 00000000..3d02719c --- /dev/null +++ b/src/SDLMain.m @@ -0,0 +1,383 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser <dwaliss1@purdue.edu> + Non-NIB-Code & other changes: Max Horn <max@quendi.de> + + Feel free to customize this file to suit your needs + */ + +#import "SDL.h" +#import "SDLMain.h" +#import <sys/param.h> /* for MAXPATHLEN */ +#import <unistd.h> + +/* For some reaon, Apple removed setAppleMenu from the headers in 10.4, + but the method still is there and works. To avoid warnings, we declare + it ourselves here. */ +@interface NSApplication(SDL_Missing_Methods) +- (void)setAppleMenu:(NSMenu *)menu; +@end + +/* Use this flag to determine whether we use SDLMain.nib or not */ +#define SDL_USE_NIB_FILE 0 + +/* Use this flag to determine whether we use CPS (docking) or not */ +#define SDL_USE_CPS 1 +#ifdef SDL_USE_CPS +/* Portions of CPS.h */ +typedef struct CPSProcessSerNum + { + UInt32 lo; + UInt32 hi; + } CPSProcessSerNum; + +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); + +#endif /* SDL_USE_CPS */ + +static int gArgc; +static char **gArgv; +static BOOL gFinderLaunch; +static BOOL gCalledAppMainline = FALSE; + +static NSString *getApplicationName(void) +{ + NSDictionary *dict; + NSString *appName = 0; + + /* Determine the application name */ + dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); + if (dict) + appName = [dict objectForKey: @"CFBundleName"]; + + if (![appName length]) + appName = [[NSProcessInfo processInfo] processName]; + + return appName; +} + +#if SDL_USE_NIB_FILE +/* A helper category for NSString */ +@interface NSString (ReplaceSubString) +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; +@end +#endif + +@interface SDLApplication : NSApplication +@end + +@implementation SDLApplication +/* Invoked from the Quit menu item */ +- (void)terminate:(id)sender +{ + /* Post a SDL_QUIT event */ + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); +} +@end + +/* The main class of the application, the application's delegate */ +@implementation SDLMain + +/* Set the working directory to the .app's parent directory */ +- (void) setupWorkingDirectory:(BOOL)shouldChdir +{ + if (shouldChdir) + { + char parentdir[MAXPATHLEN]; + CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); + if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { + assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ + } + CFRelease(url); + CFRelease(url2); + } + +} + +#if SDL_USE_NIB_FILE + +/* Fix menu to contain the real app name instead of "SDL App" */ +- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName +{ + NSRange aRange; + NSEnumerator *enumerator; + NSMenuItem *menuItem; + + aRange = [[aMenu title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; + + enumerator = [[aMenu itemArray] objectEnumerator]; + while ((menuItem = [enumerator nextObject])) + { + aRange = [[menuItem title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; + if ([menuItem hasSubmenu]) + [self fixMenu:[menuItem submenu] withAppName:appName]; + } + [ aMenu sizeToFit ]; +} + +#else + +static void setApplicationMenu(void) +{ + /* warning: this code is very odd */ + NSMenu *appleMenu; + NSMenuItem *menuItem; + NSString *title; + NSString *appName; + + appName = getApplicationName(); + appleMenu = [[NSMenu alloc] initWithTitle:@""]; + + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Hide " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + + + /* Put menu into the menubar */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:appleMenu]; + [[NSApp mainMenu] addItem:menuItem]; + + /* Tell the application object that this is now the application menu */ + [NSApp setAppleMenu:appleMenu]; + + /* Finally give up our references to the objects */ + [appleMenu release]; + [menuItem release]; +} + +/* Create a window menu */ +static void setupWindowMenu(void) +{ + NSMenu *windowMenu; + NSMenuItem *windowMenuItem; + NSMenuItem *menuItem; + + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + + /* "Minimize" item */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + [windowMenu addItem:menuItem]; + [menuItem release]; + + /* Put menu into the menubar */ + windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; + [windowMenuItem setSubmenu:windowMenu]; + [[NSApp mainMenu] addItem:windowMenuItem]; + + /* Tell the application object that this is now the window menu */ + [NSApp setWindowsMenu:windowMenu]; + + /* Finally give up our references to the objects */ + [windowMenu release]; + [windowMenuItem release]; +} + +/* Replacement for NSApplicationMain */ +static void CustomApplicationMain (int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + SDLMain *sdlMain; + + /* Ensure the application object is initialised */ + [SDLApplication sharedApplication]; + +#ifdef SDL_USE_CPS + { + CPSProcessSerNum PSN; + /* Tell the dock about us */ + if (!CPSGetCurrentProcess(&PSN)) + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) + if (!CPSSetFrontProcess(&PSN)) + [SDLApplication sharedApplication]; + } +#endif /* SDL_USE_CPS */ + + /* Set up the menubar */ + [NSApp setMainMenu:[[NSMenu alloc] init]]; + setApplicationMenu(); + setupWindowMenu(); + + /* Create SDLMain and make it the app delegate */ + sdlMain = [[SDLMain alloc] init]; + [NSApp setDelegate:sdlMain]; + + /* Start the main event loop */ + [NSApp run]; + + [sdlMain release]; + [pool release]; +} + +#endif + + +/* + * Catch document open requests...this lets us notice files when the app + * was launched by double-clicking a document, or when a document was + * dragged/dropped on the app's icon. You need to have a + * CFBundleDocumentsType section in your Info.plist to get this message, + * apparently. + * + * Files are added to gArgv, so to the app, they'll look like command line + * arguments. Previously, apps launched from the finder had nothing but + * an argv[0]. + * + * This message may be received multiple times to open several docs on launch. + * + * This message is ignored once the app's mainline has been called. + */ +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename +{ + const char *temparg; + size_t arglen; + char *arg; + char **newargv; + + if (!gFinderLaunch) /* MacOS is passing command line args. */ + return FALSE; + + if (gCalledAppMainline) /* app has started, ignore this document. */ + return FALSE; + + temparg = [filename UTF8String]; + arglen = SDL_strlen(temparg) + 1; + arg = (char *) SDL_malloc(arglen); + if (arg == NULL) + return FALSE; + + newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); + if (newargv == NULL) + { + SDL_free(arg); + return FALSE; + } + gArgv = newargv; + + SDL_strlcpy(arg, temparg, arglen); + gArgv[gArgc++] = arg; + gArgv[gArgc] = NULL; + return TRUE; +} + + +/* Called when the internal event loop has just started running */ +- (void) applicationDidFinishLaunching: (NSNotification *) note +{ + int status; + + /* Set the working directory to the .app's parent directory */ + [self setupWorkingDirectory:gFinderLaunch]; + +#if SDL_USE_NIB_FILE + /* Set the main menu to contain the real app name instead of "SDL App" */ + [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; +#endif + + /* Hand off to main application code */ + gCalledAppMainline = TRUE; + status = SDL_main (gArgc, gArgv); + + /* We're done, thank you for playing */ + exit(status); +} +@end + + +@implementation NSString (ReplaceSubString) + +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString +{ + unsigned int bufferSize; + unsigned int selfLen = [self length]; + unsigned int aStringLen = [aString length]; + unichar *buffer; + NSRange localRange; + NSString *result; + + bufferSize = selfLen + aStringLen - aRange.length; + buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); + + /* Get first part into buffer */ + localRange.location = 0; + localRange.length = aRange.location; + [self getCharacters:buffer range:localRange]; + + /* Get middle part into buffer */ + localRange.location = 0; + localRange.length = aStringLen; + [aString getCharacters:(buffer+aRange.location) range:localRange]; + + /* Get last part into buffer */ + localRange.location = aRange.location + aRange.length; + localRange.length = selfLen - localRange.location; + [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; + + /* Build output string */ + result = [NSString stringWithCharacters:buffer length:bufferSize]; + + NSDeallocateMemoryPages(buffer, bufferSize); + + return result; +} + +@end + + + +#ifdef main +# undef main +#endif + + +/* Main entry point to executable - should *not* be SDL_main! */ +int main (int argc, char **argv) +{ + /* Copy the arguments into a global variable */ + /* This is passed if we are launched by double-clicking */ + if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { + gArgv = (char **) SDL_malloc(sizeof (char *) * 2); + gArgv[0] = argv[0]; + gArgv[1] = NULL; + gArgc = 1; + gFinderLaunch = YES; + } else { + int i; + gArgc = argc; + gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); + for (i = 0; i <= argc; i++) + gArgv[i] = argv[i]; + gFinderLaunch = NO; + } + +#if SDL_USE_NIB_FILE + [SDLApplication poseAsClass:[NSApplication class]]; + NSApplicationMain (argc, argv); +#else + CustomApplicationMain (argc, argv); +#endif + return 0; +} diff --git a/src/animatedsprite.cpp b/src/animatedsprite.cpp index 203a82af..aa2fb4ee 100644 --- a/src/animatedsprite.cpp +++ b/src/animatedsprite.cpp @@ -1,26 +1,25 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "animatedsprite.h" - #include "graphics.h" #include "log.h" diff --git a/src/animatedsprite.h b/src/animatedsprite.h index 41857d8f..43248731 100644 --- a/src/animatedsprite.h +++ b/src/animatedsprite.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ANIMATEDSPRITE_H -#define _TMW_ANIMATEDSPRITE_H +#ifndef ANIMATEDSPRITE_H +#define ANIMATEDSPRITE_H #include "resources/spritedef.h" diff --git a/src/animationparticle.cpp b/src/animationparticle.cpp index eb260157..9c1f7ccb 100644 --- a/src/animationparticle.cpp +++ b/src/animationparticle.cpp @@ -1,26 +1,25 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "animationparticle.h" - #include "graphics.h" #include "simpleanimation.h" diff --git a/src/animationparticle.h b/src/animationparticle.h index eabc2742..03065eb7 100644 --- a/src/animationparticle.h +++ b/src/animationparticle.h @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/being.cpp b/src/being.cpp index 442c08ef..7f5a7d33 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -1,109 +1,160 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "being.h" -#include <cassert> -#include <cmath> - #include "animatedsprite.h" -#include "equipment.h" +#include "configuration.h" +#include "effectmanager.h" #include "game.h" #include "graphics.h" +#include "localplayer.h" #include "log.h" #include "map.h" #include "particle.h" +#include "simpleanimation.h" #include "sound.h" -#include "localplayer.h" +#include "text.h" +#include "statuseffect.h" +#include "gui/speechbubble.h" + +#include "resources/colordb.h" +#include "resources/emotedb.h" +#include "resources/image.h" #include "resources/itemdb.h" -#include "resources/resourcemanager.h" -#include "resources/imageset.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/gettext.h" +#include "utils/stringutils.h" #include "utils/xml.h" +#include <cassert> +#include <cmath> + namespace { const bool debug_movement = true; } -#define HAIR_FILE "hair.xml" - -#include "utils/xml.h" #define BEING_EFFECTS_FILE "effects.xml" +#define HAIR_FILE "hair.xml" int Being::instances = 0; -ImageSet *Being::emotionSet = NULL; +int Being::mNumberOfHairstyles = 1; +std::vector<AnimatedSprite*> Being::emotionSet; + +static const int X_SPEECH_OFFSET = 18; +static const int Y_SPEECH_OFFSET = 60; + +static const int DEFAULT_WIDTH = 32; +static const int DEFAULT_HEIGHT = 32; Being::Being(int id, int job, Map *map): +#ifdef EATHENA_SUPPORT + mX(0), mY(0), + mWalkTime(0), +#endif mEmotion(0), mEmotionTime(0), mAttackSpeed(350), mAction(STAND), mJob(job), mId(id), - mSpriteDirection(DIRECTION_DOWN), mDirection(DOWN), + mDirection(DOWN), +#ifdef TMWSERV_SUPPORT + mSpriteDirection(DIRECTION_DOWN), +#endif mMap(NULL), + mName(""), + mIsGM(false), + mParticleEffects(config.getValue("particleeffects", 1)), mEquippedWeapon(NULL), +#ifdef TMWSERV_SUPPORT mHairStyle(0), +#else + mHairStyle(1), +#endif mHairColor(0), mGender(GENDER_UNSPECIFIED), mSpeechTime(0), + mPx(0), mPy(0), + mStunMode(0), mSprites(VECTOREND_SPRITE, NULL), mSpriteIDs(VECTOREND_SPRITE, 0), mSpriteColors(VECTOREND_SPRITE, ""), - mWalkSpeed(100) + mStatusParticleEffects(&mStunParticleEffects, false), + mChildParticleEffects(&mStatusParticleEffects, false), + mMustResetParticles(false), +#ifdef TMWSERV_SUPPORT + mWalkSpeed(100), +#else + mWalkSpeed(150), +#endif + mUsedTargetCursor(NULL) { setMap(map); - mSpeechBubble = new SpeechBubble(); + mSpeechBubble = new SpeechBubble; if (instances == 0) { - // Load the emotion set - ResourceManager *rm = ResourceManager::getInstance(); - emotionSet = rm->getImageSet("graphics/sprites/emotions.png", 30, 32); - if (!emotionSet) - logger->error("Unable to load emotions!"); + // Setup emote sprites + for (int i = 0; i <= EmoteDB::getLast(); i++) + { + EmoteInfo info = EmoteDB::get(i); + + std::string file = "graphics/sprites/" + info.sprites.front()->sprite; + int variant = info.sprites.front()->variant; + emotionSet.push_back(AnimatedSprite::load(file, variant)); + } + + // Hairstyles are encoded as negative numbers. Count how far negative + // we can go. + int hairstyles = 1; + while (ItemDB::get(-hairstyles).getSprite(GENDER_MALE) != "error.xml") + { + hairstyles++; + } + mNumberOfHairstyles = hairstyles; } instances++; + mSpeech = ""; + mNameColor = 0x202020; + mText = 0; } Being::~Being() { + mUsedTargetCursor = NULL; delete_all(mSprites); clearPath(); - for ( std::list<Particle *>::iterator i = mChildParticleEffects.begin(); - i != mChildParticleEffects.end(); - i++) - { - (*i)->kill(); - } + if (player_node && player_node->getTarget() == this) + player_node->setTarget(NULL); setMap(NULL); @@ -111,11 +162,11 @@ Being::~Being() if (instances == 0) { - emotionSet->decRef(); - emotionSet = NULL; + delete_all(emotionSet); } delete mSpeechBubble; + delete mText; } void Being::setPosition(const Vector &pos) @@ -125,6 +176,15 @@ void Being::setPosition(const Vector &pos) mPath.clear(); } +#ifdef EATHENA_SUPPORT +void Being::setDestination(Uint16 destX, Uint16 destY) +{ + if (mMap) + setPath(mMap->findPath(mX, mY, destX, destY, getWalkMask())); +} +#endif + +#ifdef TMWSERV_SUPPORT void Being::adjustCourse(int srcX, int srcY, int dstX, int dstY) { if (debug_movement) @@ -289,6 +349,7 @@ void Being::setDestination(int destX, int destY) adjustCourse((int) mPos.x, (int) mPos.y, destX, destY); } +#endif // TMWSERV_SUPPORT void Being::clearPath() { @@ -297,14 +358,22 @@ void Being::clearPath() void Being::setPath(const Path &path) { - std::cout << this << " New path: " << path << std::endl; mPath = path; +#ifdef TMWSERV_SUPPORT + std::cout << this << " New path: " << path << std::endl; +#else + if (mAction != WALK && mAction != DEAD) + { + nextStep(); + mWalkTime = tick_time; + } +#endif } 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, const std::string &color) @@ -317,7 +386,43 @@ void Being::setSprite(int slot, int id, const std::string &color) void Being::setSpeech(const std::string &text, Uint32 time) { mSpeech = text; - mSpeechTime = 500; + + // Trim whitespace + trim(mSpeech); + + // check for links + std::string::size_type start = mSpeech.find('['); + std::string::size_type end = mSpeech.find(']', start); + + while (start != std::string::npos && end != std::string::npos) + { + // Catch multiple embeds and ignore them so it doesn't crash the client. + while ((mSpeech.find('[', start + 1) != std::string::npos) && + (mSpeech.find('[', start + 1) < end)) + { + start = mSpeech.find('[', start + 1); + } + + std::string::size_type position = mSpeech.find('|'); + if (mSpeech[start + 1] == '@' && mSpeech[start + 2] == '@') + { + mSpeech.erase(end, 1); + mSpeech.erase(start, (position - start) + 1); + } + position = mSpeech.find('@'); + + while (position != std::string::npos) + { + mSpeech.erase(position, 2); + position = mSpeech.find('@'); + } + + start = mSpeech.find('[', start + 1); + end = mSpeech.find(']', start); + } + + if (!mSpeech.empty()) + mSpeechTime = time <= SPEECH_MAX_TIME ? time : SPEECH_MAX_TIME; } void Being::takeDamage(int amount) @@ -327,69 +432,71 @@ void Being::takeDamage(int amount) // Selecting the right color if (damage == "miss") - { font = hitYellowFont; - } else { - // Hit particle effect - controlParticle(particleEngine->addEffect( - "graphics/particles/hit.particle.xml", mPos.x, mPos.y)); - if (getType() == MONSTER) - { font = hitBlueFont; - } else - { font = hitRedFont; - } } // Show damage number particleEngine->addTextSplashEffect(damage, 255, 255, 255, font, +#ifdef TMWSERV_SUPPORT (int) mPos.x + 16, (int) mPos.y + 16); +#else + mPx + 16, mPy + 16); +#endif + effectManager->trigger(26, this); } +void Being::showCrit() +{ + effectManager->trigger(28, this); + +} + +#ifdef TMWSERV_SUPPORT void Being::handleAttack() +#else +void Being::handleAttack(Being *victim, int damage) +#endif { setAction(Being::ATTACK); +#ifdef EATHENA_SUPPORT + mFrame = 0; + mWalkTime = tick_time; +#endif } void Being::setMap(Map *map) { // Remove sprite from potential previous map if (mMap) - { mMap->removeSprite(mSpriteIterator); - } mMap = map; // Add sprite to potential new map if (mMap) - { mSpriteIterator = mMap->addSprite(this); - } // Clear particle effect list because child particles became invalid mChildParticleEffects.clear(); + mMustResetParticles = true; // Reset status particles on next redraw } void Being::controlParticle(Particle *particle) { - if (particle) - { - // The effect may not die without the beings permission or we segfault - particle->disableAutoDelete(); - mChildParticleEffects.push_back(particle); - } + mChildParticleEffects.addLocally(particle); } void Being::setAction(Action action, int attackType) { SpriteAction currentAction = ACTION_INVALID; + switch (action) { case WALK: @@ -403,15 +510,14 @@ void Being::setAction(Action action, int attackType) { currentAction = mEquippedWeapon->getAttackType(); } - else { + else + { currentAction = ACTION_ATTACK; } for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i]) - { mSprites[i]->reset(); - } } break; case HURT: @@ -432,20 +538,18 @@ void Being::setAction(Action action, int attackType) for (int i = 0; i < VECTOREND_SPRITE; i++) { if (mSprites[i]) - { mSprites[i]->play(currentAction); - } } mAction = action; } } - void Being::setDirection(Uint8 direction) { if (mDirection == direction) return; +#ifdef TMWSERV_SUPPORT // if the direction does not change much, keep the common component int mFaceDirection = mDirection & direction; if (!mFaceDirection) @@ -462,16 +566,93 @@ void Being::setDirection(Uint8 direction) else dir = DIRECTION_LEFT; mSpriteDirection = dir; +#else + mDirection = direction; + SpriteDirection dir = getSpriteDirection(); +#endif for (int i = 0; i < VECTOREND_SPRITE; i++) { - if (mSprites[i] != NULL) - mSprites[i]->setDirection(dir); + if (mSprites[i]) + mSprites[i]->setDirection(dir); + } +} + +#ifdef EATHENA_SUPPORT +SpriteDirection Being::getSpriteDirection() const +{ + SpriteDirection dir; + + if (mDirection & UP) + { + dir = DIRECTION_UP; + } + else if (mDirection & DOWN) + { + dir = DIRECTION_DOWN; + } + else if (mDirection & RIGHT) + { + dir = DIRECTION_RIGHT; + } + else + { + dir = DIRECTION_LEFT; } + + return dir; } +void Being::nextStep() +{ + if (mPath.empty()) + { + setAction(STAND); + return; + } + + Position pos = mPath.front(); + mPath.pop_front(); + + int dir = 0; + if (pos.x > mX) + dir |= RIGHT; + else if (pos.x < mX) + dir |= LEFT; + if (pos.y > mY) + dir |= DOWN; + else if (pos.y < mY) + dir |= UP; + + setDirection(dir); + + if (!mMap->getWalk(pos.x, pos.y, getWalkMask())) + { + setAction(STAND); + return; + } + + mX = pos.x; + mY = pos.y; + setAction(WALK); + mWalkTime += mWalkSpeed / 10; +} +#endif + void Being::logic() { + // Reduce the time that speech is still displayed + if (mSpeechTime > 0) + mSpeechTime--; + + // Remove text if speech boxes aren't being used + if (mSpeechTime == 0 && mText) + { + delete mText; + mText = 0; + } + +#ifdef TMWSERV_SUPPORT const Vector dest = (mPath.empty()) ? mDest : Vector(mPath.front().x * 32 + 16, mPath.front().y * 32 + 16); @@ -506,56 +687,83 @@ void Being::logic() } else if (mAction == WALK) { setAction(STAND); } +#else + int oldPx = mPx; + int oldPy = mPy; - // Reduce the time that speech is still displayed - if (mSpeechTime > 0) - mSpeechTime--; + // Update pixel coordinates + mPx = mX * 32 + getXOffset(); + mPy = mY * 32 + getYOffset(); + + if (mPx != oldPx || mPy != oldPy) + { + updateCoords(); + } +#endif if (mEmotion != 0) { mEmotionTime--; - if (mEmotionTime == 0) { + if (mEmotionTime == 0) mEmotion = 0; - } } // Update sprite animations + if (mUsedTargetCursor) + mUsedTargetCursor->update(tick_time * 10); + for (int i = 0; i < VECTOREND_SPRITE; i++) { - if (mSprites[i] != NULL) - { + if (mSprites[i]) mSprites[i]->update(tick_time * 10); - } } - // Update particle effects - for (std::list<Particle *>::iterator i = mChildParticleEffects.begin(); - i != mChildParticleEffects.end();) - { - (*i)->setPosition(mPos.x, mPos.y); - if ((*i)->isExtinct()) - { - (*i)->kill(); - i = mChildParticleEffects.erase(i); - } - else { - i++; + // Restart status/particle effects, if needed + if (mMustResetParticles) { + mMustResetParticles = false; + for (std::set<int>::iterator it = mStatusEffects.begin(); + it != mStatusEffects.end(); it++) { + const StatusEffect *effect = StatusEffect::getStatusEffect(*it, true); + if (effect && effect->particleEffectIsPersistent()) + updateStatusEffect(*it, true); } } + + // Update particle effects +#ifdef TMWSERV_SUPPORT + mChildParticleEffects.moveTo((float) mPx + 16.0f, + (float) mPy + 32.0f); +#else + mChildParticleEffects.moveTo(mPos.x, mPos.y); +#endif } void Being::draw(Graphics *graphics, int offsetX, int offsetY) const { +#ifdef TMWSERV_SUPPORT int px = (int) mPos.x + offsetX; int py = (int) mPos.y + offsetY; +#else + int px = mPx + offsetX; + int py = mPy + offsetY; +#endif + + if (mUsedTargetCursor) + { + mUsedTargetCursor->draw(graphics, px, py); + } for (int i = 0; i < VECTOREND_SPRITE; i++) { - if (mSprites[i] != NULL) + if (mSprites[i]) { +#ifdef TMWSERV_SUPPORT // TODO: Eventually, we probably should fix all sprite offsets so // that this translation isn't necessary anymore. mSprites[i]->draw(graphics, px - 16, py - 32); +#else + mSprites[i]->draw(graphics, px, py); +#endif } } } @@ -565,26 +773,69 @@ void Being::drawEmotion(Graphics *graphics, int offsetX, int offsetY) if (!mEmotion) return; +#ifdef TMWSERV_SUPPORT const int px = (int) mPos.x + offsetX + 3; const int py = (int) mPos.y + offsetY - 60; +#else + const int px = mPx + offsetX + 3; + const int py = mPy + offsetY - 60; +#endif const int emotionIndex = mEmotion - 1; - if (emotionIndex >= 0 && emotionIndex < (int) emotionSet->size()) - graphics->drawImage(emotionSet->get(emotionIndex), px, py); + if (emotionIndex >= 0 && emotionIndex <= EmoteDB::getLast()) + emotionSet[emotionIndex]->draw(graphics, px, py); } -void Being::drawSpeech(Graphics *graphics, int offsetX, int offsetY) +void Being::drawSpeech(int offsetX, int offsetY) { +#ifdef TMWSERV_SUPPORT int px = (int) mPos.x + offsetX; int py = (int) mPos.y + offsetY; +#else + const int px = mPx + offsetX; + const int py = mPy + offsetY; +#endif + const int speech = (int) config.getValue("speech", NAME_IN_BUBBLE); // Draw speech above this being - if (mSpeechTime > 0) + if (mSpeechTime > 0 && (speech == NAME_IN_BUBBLE || + speech == NO_NAME_IN_BUBBLE)) { - mSpeechBubble->setPosition(px - 50, py - 80 - (mSpeechBubble->getNumRows()*14) ); - mSpeechBubble->setText( mSpeech ); + const bool showName = (speech == NAME_IN_BUBBLE); + + if (mText) + { + delete mText; + mText = 0; + } + + mSpeechBubble->setCaption(showName ? mName : "", mNameColor); + + // Not quite centered, but close enough. However, it's not too important + // to get it right right now, as it doesn't take bubble collision into + // account yet. + mSpeechBubble->setText(mSpeech, showName); + mSpeechBubble->setPosition(px - (mSpeechBubble->getWidth() * 4 / 11), + py - 40 - (mSpeechBubble->getHeight())); mSpeechBubble->setVisible(true); } + else if (mSpeechTime > 0 && speech == TEXT_OVERHEAD) + { + mSpeechBubble->setVisible(false); + // don't introduce a memory leak + if (mText) + delete mText; + + mText = new Text(mSpeech, mPx + X_SPEECH_OFFSET, mPy - Y_SPEECH_OFFSET, + gcn::Graphics::CENTER, gcn::Color(255, 255, 255)); + } + else if (speech == NO_SPEECH) + { + mSpeechBubble->setVisible(false); + if (mText) + delete mText; + mText = NULL; + } else if (mSpeechTime == 0) { mSpeechBubble->setVisible(false); @@ -596,115 +847,125 @@ Being::Type Being::getType() const return UNKNOWN; } -int Being::getWidth() const +void Being::setStatusEffectBlock(int offset, Uint16 newEffects) { - if (mSprites[BASE_SPRITE]) - { - return mSprites[BASE_SPRITE]->getWidth(); - } - else { - return Being::DEFAULT_WIDTH; - } -} + for (int i = 0; i < STATUS_EFFECTS; i++) { + int index = StatusEffect::blockEffectIndexToEffectIndex(offset + i); -int Being::getHeight() const -{ - if (mSprites[BASE_SPRITE]) - { - return mSprites[BASE_SPRITE]->getHeight(); - } - else { - return Being::DEFAULT_HEIGHT; + if (index != -1) + setStatusEffect(index, (newEffects & (1 << i)) > 0); } } +void Being::handleStatusEffect(StatusEffect *effect, int effectId) +{ + if (!effect) + return; + // TODO: Find out how this is meant to be used + // (SpriteAction != Being::Action) + //SpriteAction action = effect->getAction(); + //if (action != ACTION_INVALID) + // setAction(action); + Particle *particle = effect->getParticle(); -static int hairStylesNr; -static int hairColorsNr; -static std::vector<std::string> hairColors; - -static void -initializeHair(void); + if (effectId >= 0) + mStatusParticleEffects.setLocally(effectId, particle); + else { + mStunParticleEffects.clearLocally(); + if (particle) + mStunParticleEffects.addLocally(particle); + } +} -int -Being::getHairStylesNr(void) +void Being::updateStunMode(int oldMode, int newMode) { - initializeHair(); - return hairStylesNr; + handleStatusEffect(StatusEffect::getStatusEffect(oldMode, false), -1); + handleStatusEffect(StatusEffect::getStatusEffect(newMode, true), -1); } -int -Being::getHairColorsNr(void) +void Being::updateStatusEffect(int index, bool newStatus) { - initializeHair(); - return hairColorsNr; + handleStatusEffect(StatusEffect::getStatusEffect(index, newStatus), index); } -std::string -Being::getHairColor(int index) +void Being::setStatusEffect(int index, bool active) { - initializeHair(); - if (index < 0 || index >= hairColorsNr) - return "#000000"; + const bool wasActive = mStatusEffects.find(index) != mStatusEffects.end(); - return hairColors[index]; + if (active != wasActive) { + updateStatusEffect(index, active); + if (active) + mStatusEffects.insert(index); + else + mStatusEffects.erase(index); + } } -static bool hairInitialized = false; - -static void -initializeHair(void) +#ifdef EATHENA_SUPPORT +int Being::getOffset(char pos, char neg) const { - if (hairInitialized) - return; - - // Hairstyles are encoded as negative numbers. Count how far negative we can go. - int hairstylesCtr = -1; - while (ItemDB::get(hairstylesCtr).getSprite(GENDER_MALE) != "error.xml") - --hairstylesCtr; - - hairStylesNr = -hairstylesCtr; // done. - if (hairStylesNr == 0) - hairStylesNr = 1; // No hair style -> no hair + // Check whether we're walking in the requested direction + if (mAction != WALK || !(mDirection & (pos | neg))) + { + return 0; + } - hairColorsNr = 0; + int offset = (get_elapsed_time(mWalkTime) * 32) / mWalkSpeed; - XML::Document doc(HAIR_FILE); - xmlNodePtr root = doc.rootNode(); + // We calculate the offset _from_ the _target_ location + offset -= 32; + if (offset > 0) + { + offset = 0; + } - if (!root || !xmlStrEqual(root->name, BAD_CAST "colors")) + // Going into negative direction? Invert the offset. + if (mDirection & pos) { - 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", ""); + offset = -offset; + } - if (index >= 0 && value != "") { - if (index >= hairColorsNr) { - hairColorsNr = index + 1; - hairColors.resize(hairColorsNr, "#000000"); - } - hairColors[index] = value; - } - } - } - } // done initializing + return offset; +} +#endif - if (hairColorsNr == 0) { // No colours -> black only - hairColorsNr = 1; - hairColors.resize(hairColorsNr, "#000000"); +int Being::getWidth() const +{ + if (mSprites[BASE_SPRITE]) + { + const int width = mSprites[BASE_SPRITE]->getWidth() > DEFAULT_WIDTH ? + mSprites[BASE_SPRITE]->getWidth() : + DEFAULT_WIDTH; + return width; + } + else + { + return DEFAULT_WIDTH; } - - hairInitialized = 1; } +int Being::getHeight() const +{ + if (mSprites[BASE_SPRITE]) + { + const int height = mSprites[BASE_SPRITE]->getHeight() > DEFAULT_HEIGHT ? + mSprites[BASE_SPRITE]->getHeight() : + DEFAULT_HEIGHT; + return height; + } + else + { + return DEFAULT_HEIGHT; + } +} +void Being::setTargetAnimation(SimpleAnimation* animation) +{ + mUsedTargetCursor = animation; + mUsedTargetCursor->reset(); +} struct EffectDescription { std::string mGFXEffect; @@ -715,8 +976,7 @@ static EffectDescription *default_effect = NULL; static std::map<int, EffectDescription *> effects; static bool effects_initialized = false; -static EffectDescription * -getEffectDescription(xmlNodePtr node, int *id) +static EffectDescription *getEffectDescription(xmlNodePtr node, int *id) { EffectDescription *ed = new EffectDescription; @@ -727,8 +987,7 @@ getEffectDescription(xmlNodePtr node, int *id) return ed; } -static EffectDescription * -getEffectDescription(int effectId) +static EffectDescription *getEffectDescription(int effectId) { if (!effects_initialized) { @@ -774,8 +1033,7 @@ getEffectDescription(int effectId) return ed; } -void -Being::internalTriggerEffect(int effectId, bool sfx, bool gfx) +void Being::internalTriggerEffect(int effectId, bool sfx, bool gfx) { logger->log("Special effect #%d on %s", effectId, getId() == player_node->getId() ? "self" : "other"); @@ -787,14 +1045,96 @@ Being::internalTriggerEffect(int effectId, bool sfx, bool gfx) return; } - if (gfx && ed->mGFXEffect != "") { + if (gfx && !ed->mGFXEffect.empty()) { Particle *selfFX; selfFX = particleEngine->addEffect(ed->mGFXEffect, 0, 0); controlParticle(selfFX); } - if (sfx && ed->mSFXEffect != "") { + if (sfx && !ed->mSFXEffect.empty()) { sound.playSfx(ed->mSFXEffect); } } + + + + +static int hairStylesNr; +static int hairColorsNr; +static std::vector<std::string> hairColors; + +static void initializeHair(); + +int Being::getHairStylesNr() +{ + initializeHair(); + return hairStylesNr; +} + +int Being::getHairColorsNr() +{ + 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() +{ + if (hairInitialized) + return; + + // Hairstyles are encoded as negative numbers. Count how far negative we + // can go. + int hairstylesCtr = -1; + while (ItemDB::get(hairstylesCtr).getSprite(GENDER_MALE) != "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.empty()) { + if (index >= hairColorsNr) { + hairColorsNr = index + 1; + hairColors.resize(hairColorsNr, "#000000"); + } + hairColors[index] = value; + } + } + } + } // done initializing + + if (hairColorsNr == 0) { // No colors -> black only + hairColorsNr = 1; + hairColors.resize(hairColorsNr, "#000000"); + } + + hairInitialized = 1; +} diff --git a/src/being.h b/src/being.h index cd317859..a704b3df 100644 --- a/src/being.h +++ b/src/being.h @@ -1,49 +1,68 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_BEING_H -#define _TMW_BEING_H +#ifndef BEING_H +#define BEING_H + +#include <guichan/color.hpp> -#include <list> -#include <string> #include <SDL_types.h> + +#include <set> +#include <string> #include <vector> +#include "map.h" +#include "particlecontainer.h" #include "position.h" #include "sprite.h" -#include "map.h" -#include "animatedsprite.h" #include "vector.h" +#include "resources/spritedef.h" + +#define FIRST_IGNORE_EMOTE 14 +#define STATUS_EFFECTS 32 + +#define SPEECH_TIME 500 +#define SPEECH_MAX_TIME 1000 + class AnimatedSprite; -class Equipment; +class Image; class ItemInfo; class Item; class Map; class Graphics; -class ImageSet; class Particle; +class Position; +class SimpleAnimation; class SpeechBubble; +class Text; + +class StatusEffect; -enum Gender { +typedef std::list<Sprite*> Sprites; +typedef Sprites::iterator SpriteIterator; + +enum Gender +{ GENDER_MALE = 0, GENDER_FEMALE = 1, GENDER_UNSPECIFIED = 2 @@ -52,7 +71,8 @@ enum Gender { class Being : public Sprite { public: - enum Type { + enum Type + { UNKNOWN, PLAYER, NPC, @@ -64,7 +84,8 @@ class Being : public Sprite * WARNING: Has to be in sync with the same enum in the Being class * of the server! */ - enum Action { + enum Action + { STAND, WALK, ATTACK, @@ -73,33 +94,59 @@ class Being : public Sprite HURT }; - enum Sprite { + enum Sprite + { BASE_SPRITE = 0, SHOE_SPRITE, BOTTOMCLOTHES_SPRITE, TOPCLOTHES_SPRITE, +#ifdef EATHENA_SUPPORT + MISC1_SPRITE, + MISC2_SPRITE, +#endif HAIR_SPRITE, HAT_SPRITE, +#ifdef EATHENA_SUPPORT + CAPE_SPRITE, + GLOVES_SPRITE, +#endif WEAPON_SPRITE, +#ifdef EATHENA_SUPPORT + SHIELD_SPRITE, +#endif VECTOREND_SPRITE }; - enum TargetCursorSize { + enum TargetCursorSize + { TC_SMALL = 0, TC_MEDIUM, TC_LARGE, NUM_TC }; + enum Speech + { + NO_SPEECH = 0, + TEXT_OVERHEAD, + NO_NAME_IN_BUBBLE, + NAME_IN_BUBBLE, + NUM_SPEECH + }; /** * Directions, to be used as bitmask values */ enum { DOWN = 1, LEFT = 2, UP = 4, RIGHT = 8 }; - std::string mName; /**< Name of character */ +#ifdef EATHENA_SUPPORT + Uint16 mX, mY; /**< Tile coordinates */ + Uint16 mFrame; + Uint16 mWalkTime; +#endif Uint8 mEmotion; /**< Currently showing emotion */ Uint8 mEmotionTime; /**< Time until emotion disappears */ + Uint16 mAttackSpeed; /**< Attack speed */ Action mAction; /**< Action the being is performing */ Uint16 mJob; /**< Job (player job, npc, monster, creature ) */ @@ -122,6 +169,9 @@ class Being : public Sprite /** * Sets a new destination for this being to walk to. */ +#ifdef EATHENA_SUPPORT + virtual void setDestination(Uint16 destX, Uint16 destY); +#else void setDestination(int x, int y); /** @@ -138,6 +188,7 @@ class Being : public Sprite * Adjusts course to expected start and end points. */ void adjustCourse(int srcX, int srcY, int destX, int destY); +#endif /** * Puts a "speech balloon" above this being for the specified amount @@ -146,7 +197,7 @@ class Being : public Sprite * @param text The text that should appear. * @param time The amount of time the text should stay in milliseconds. */ - void setSpeech(const std::string &text, Uint32 time); + void setSpeech(const std::string &text, Uint32 time = 500); /** * Puts a damage bubble above this being. @@ -156,9 +207,21 @@ class Being : public Sprite virtual void takeDamage(int amount); /** + * Puts a crit notification bubble above this being. + */ + virtual void showCrit(); + + /** * Handles an attack of another being by this being. + * + * @param victim The attacked being. + * @param damage The amount of damage dealt (0 means miss). */ +#ifdef TMWSERV_SUPPORT virtual void handleAttack(); +#else + virtual void handleAttack(Being *victim, int damage); +#endif /** * Returns the name of the being. @@ -171,12 +234,8 @@ class Being : public Sprite * * @param name The name that should appear. */ - void setName(const std::string &name) { mName = name; } - - /** - * Sets the gender for this being. - */ - virtual void setGender(Gender gender) { mGender = gender; } + virtual void setName(const std::string &name) + { mName = name; } /** * Gets the hair color for this being. @@ -191,12 +250,12 @@ 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. - * - * NOTE: This method was necessary for convenience in the 0.0 client. - * It should be removed here since the server can provide the hair ID - * and coloring the same way it does for other equipment pieces. Then - * Being::setSprite can be used instead. */ virtual void setHairStyle(int style, int color); @@ -207,6 +266,31 @@ class Being : public Sprite const std::string &color = ""); /** + * Sets the gender of this being. + */ + virtual void setGender(Gender gender) { mGender = gender; } + + /** + * Gets the gender of this being. + */ + Gender getGender() const { return mGender; } + +#ifdef EATHENA_SUPPORT + /** + * Makes this being take the next step of his path. + */ + virtual void nextStep(); +#endif + + /** + * Triggers whether or not to show the name as a GM name. + * NOTE: This doesn't mean that just anyone can use this. + * If the server doesn't acknowlege you, you won't be shown + * as a GM on other people's clients. + */ + virtual void setGM() { mIsGM = true; } + + /** * Performs being logic. */ virtual void logic(); @@ -214,7 +298,7 @@ class Being : public Sprite /** * Draws the speech text above the being. */ - void drawSpeech(Graphics* graphics, int offsetX, int offsetY); + void drawSpeech(int offsetX, int offsetY); /** * Draws the emotion picture above the being. @@ -222,11 +306,6 @@ class Being : public Sprite void drawEmotion(Graphics *graphics, int offsetX, int offsetY); /** - * Draws the name text below the being. - */ - virtual void drawName(Graphics *, int, int) {}; - - /** * Returns the type of the being. */ virtual Type getType() const; @@ -245,12 +324,12 @@ class Being : public Sprite /** * Gets the being id. */ - Uint16 getId() const { return mId; } + Uint32 getId() const { return mId; } /** * Sets the sprite id. */ - void setId(Uint16 id) { mId = id; } + void setId(Uint32 id) { mId = id; } /** * Sets the map the being is on @@ -268,16 +347,32 @@ class Being : public Sprite bool isAlive() { return mAction != DEAD; } /** - * Returns the direction the being is facing. + * Returns the current direction. */ - SpriteDirection getSpriteDirection() const - { return SpriteDirection(mSpriteDirection); } + Uint8 getDirection() const { return mDirection; } /** * Sets the current direction. */ void setDirection(Uint8 direction); +#ifdef EATHENA_SUPPORT + /** + * Gets the current action. + */ + int getWalkTime() { return mWalkTime; } +#endif + + /** + * Returns the direction the being is facing. + */ +#ifdef TMWSERV_SUPPORT + SpriteDirection getSpriteDirection() const + { return SpriteDirection(mSpriteDirection); } +#else + SpriteDirection getSpriteDirection() const; +#endif + /** * Draws this being to the given graphics context. * @@ -288,14 +383,36 @@ class Being : public Sprite /** * Returns the pixel X coordinate. */ +#ifdef TMWSERV_SUPPORT int getPixelX() const { return (int) mPos.x; } +#else + int getPixelX() const { return mPx; } +#endif /** * Returns the pixel Y coordinate. * * @see Sprite::getPixelY() */ +#ifdef TMWSERV_SUPPORT int getPixelY() const { return (int) mPos.y; } +#else + int getPixelY() const { return mPy; } +#endif + +#ifdef EATHENA_SUPPORT + /** + * Get the current X pixel offset. + */ + int getXOffset() const + { return getOffset(LEFT, RIGHT); } + + /** + * Get the current Y pixel offset. + */ + int getYOffset() const + { return getOffset(UP, DOWN); } +#endif /** * Sets the position of this being. When the being was walking, it also @@ -318,6 +435,7 @@ class Being : public Sprite */ const Vector &getPosition() const { return mPos; } + /** * Returns the horizontal size of the current base sprite of the being. */ @@ -352,21 +470,68 @@ class Being : public Sprite const Path &getPath() const { return mPath; } /** + * Sets the target animation for this being. + */ + void setTargetAnimation(SimpleAnimation* animation); + + /** + * Untargets the being + */ + void untarget() { mUsedTargetCursor = NULL; } + + AnimatedSprite* getEmote(int index) { return emotionSet[index]; } + + void setEmote(Uint8 emotion, Uint8 emote_time) + { + mEmotion = emotion; + mEmotionTime = emote_time; + } + + /** + * Sets the being's stun mode. If zero, the being is `normal', + * otherwise it is `stunned' in some fashion. + */ + void setStunMode(int stunMode) + { + if (mStunMode != stunMode) + updateStunMode(mStunMode, stunMode); + mStunMode = stunMode; + }; + + void setStatusEffect(int index, bool active); + + /** + * A status effect block is a 16 bit mask of status effects. + * We assign each such flag a block ID of offset + bitnr. + * + * These are NOT the same as the status effect indices. + */ + void setStatusEffectBlock(int offset, Uint16 flags); + + /** * 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); } + virtual void triggerEffect(int effectId) + { + internalTriggerEffect(effectId, false, true); + } + + // Target cursor being used by the being + Image *mTargetCursor; - static int getHairColorsNr(void); + static int getHairColorsNr(); - static int getHairStylesNr(void); + static int getHairStylesNr(); static std::string getHairColor(int index); + virtual AnimatedSprite* getSprite(int index) const + { return mSprites[index]; } + protected: /** * Sets the new path for this being. @@ -374,6 +539,11 @@ class Being : public Sprite void setPath(const Path &path); /** + * Let the sub-classes react to a replacement + */ + virtual void updateCoords() {} + + /** * Gets the way the object blocks pathfinding for other objects */ virtual Map::BlockType getBlockType() const @@ -386,34 +556,80 @@ class Being : public Sprite * \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); - Uint16 mId; /**< Unique being id */ + /** + * Notify self that the stun mode has been updated. Invoked by + * setStunMode if something changed. + */ + virtual void updateStunMode(int oldMode, int newMode); + + /** + * Notify self that a status effect has flipped. + * The new flag is passed. + */ + virtual void updateStatusEffect(int index, bool newStatus); + + /** + * Handle an update to a status or stun effect + * + * \param The StatusEffect to effect + * \param effectId -1 for stun, otherwise the effect index + */ + virtual void handleStatusEffect(StatusEffect *effect, int effectId); + + Uint32 mId; /**< Unique sprite id */ + Uint8 mDirection; /**< Facing direction */ +#ifdef TMWSERV_SUPPORT Uint8 mSpriteDirection; /**< Facing direction */ - Uint8 mDirection; /**< Walking direction */ +#endif Map *mMap; /**< Map on which this being resides */ + std::string mName; /**< Name of character */ SpriteIterator mSpriteIterator; + bool mIsGM; + bool mParticleEffects; /**< Whether to display particles or not */ /** Engine-related infos about weapon. */ const ItemInfo* mEquippedWeapon; + static int mNumberOfHairstyles; /** Number of hair styles in use */ + Path mPath; std::string mSpeech; + Text *mText; int mHairStyle; int mHairColor; Gender mGender; Uint32 mSpeechTime; + Sint32 mPx, mPy; /**< Pixel coordinates */ + Uint16 mStunMode; /**< Stun mode; zero if not stunned */ + std::set<int> mStatusEffects; /**< set of active status effects */ + + gcn::Color mNameColor; std::vector<AnimatedSprite*> mSprites; std::vector<int> mSpriteIDs; std::vector<std::string> mSpriteColors; - std::list<Particle *> mChildParticleEffects; + ParticleList mStunParticleEffects; + ParticleVector mStatusParticleEffects; + ParticleList mChildParticleEffects; private: +#ifdef EATHENA_SUPPORT + /** + * Calculates the offset in the given directions. + * If walking in direction 'neg' the value is negated. + */ + int getOffset(char pos, char neg) const; +#endif + /** Reset particle status effects on next redraw? */ + bool mMustResetParticles; + +#ifdef TMWSERV_SUPPORT static const int DEFAULT_WIDTH = 32; static const int DEFAULT_HEIGHT = 32; +#endif // Speech Bubble components SpeechBubble *mSpeechBubble; @@ -423,8 +639,11 @@ class Being : public Sprite Vector mPos; Vector mDest; - static int instances; /**< Number of Being instances */ - static ImageSet *emotionSet; /**< Emoticons used by beings */ + // Target cursor being used + SimpleAnimation* mUsedTargetCursor; + + static int instances; /**< Number of Being instances */ + static std::vector<AnimatedSprite*> emotionSet; /**< Emoticons used by beings */ }; #endif diff --git a/src/beingmanager.cpp b/src/beingmanager.cpp index 7f3d8845..e9d598c7 100644 --- a/src/beingmanager.cpp +++ b/src/beingmanager.cpp @@ -1,26 +1,24 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cassert> - #include "beingmanager.h" #include "localplayer.h" @@ -28,18 +26,31 @@ #include "npc.h" #include "player.h" +#ifdef EATHENA_SUPPORT +#include "net/messageout.h" +#include "net/ea/protocol.h" +#else #include "net/protocol.h" +#endif + #include "utils/dtor.h" +#include <cassert> + class FindBeingFunctor { public: bool operator() (Being *being) { Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0); +#ifdef TMWSERV_SUPPORT const Vector &pos = being->getPosition(); return ((int) pos.x / 32 == x && ((int) pos.y / 32 == y || (int) pos.y / 32 == other_y) && +#else + return (being->mX == x && + (being->mY == y || being->mY == other_y) && +#endif being->mAction != Being::DEAD && (type == Being::UNKNOWN || being->getType() == type)); } @@ -48,6 +59,13 @@ class FindBeingFunctor Being::Type type; } beingFinder; +#ifdef EATHENA_SUPPORT +BeingManager::BeingManager(Network *network): + mNetwork(network) +{ +} +#endif + void BeingManager::setMap(Map *map) { mMap = map; @@ -61,10 +79,15 @@ void BeingManager::setPlayer(LocalPlayer *player) mBeings.push_back(player); } +#ifdef TMWSERV_SUPPORT Being* BeingManager::createBeing(int id, int type, int subtype) +#else +Being* BeingManager::createBeing(Uint32 id, Uint16 job) +#endif { Being *being; +#ifdef TMWSERV_SUPPORT switch (type) { case OBJECT_PLAYER: @@ -79,6 +102,24 @@ Being* BeingManager::createBeing(int id, int type, int subtype) default: assert(false); } +#else + if (job < 10) + being = new Player(id, job, mMap); + else if (job >= 50 && job < 1002) + being = new NPC(id, job, mMap, mNetwork); + else if (job >= 1002 && job < 1500) + being = new Monster(id, job, mMap); + else + being = new Being(id, job, mMap); + + // Player or NPC + if (job < 1002) + { + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0094); + outMsg.writeInt32(id);//readLong(2)); + } +#endif mBeings.push_back(being); return being; @@ -87,12 +128,14 @@ Being* BeingManager::createBeing(int id, int type, int subtype) void BeingManager::destroyBeing(Being *being) { mBeings.remove(being); +#ifdef TMWSERV_SUPPORT if(being == player_node->getTarget()) player_node->setTarget(NULL); +#endif delete being; } -Being* BeingManager::findBeing(Uint16 id) +Being* BeingManager::findBeing(Uint32 id) { for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++) { @@ -123,9 +166,12 @@ Being* BeingManager::findBeingByPixel(Uint16 x, Uint16 y) for (; itr != itr_end; ++itr) { Being *being = (*itr); + int xtol = being->getWidth() / 2; int uptol = being->getHeight(); - if ((being != player_node) && + + if ((being->mAction != Being::DEAD) && + (being != player_node) && (being->getPixelX() - xtol <= x) && (being->getPixelX() + xtol >= x) && (being->getPixelY() - uptol <= y) && @@ -138,6 +184,19 @@ Being* BeingManager::findBeingByPixel(Uint16 x, Uint16 y) return NULL; } +Being* BeingManager::findBeingByName(std::string name, Being::Type type) +{ + for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++) + { + Being *being = (*i); + if (being->getName() == name + && (type == Being::UNKNOWN + || type == being->getType())) + return being; + } + return NULL; +} + Beings& BeingManager::getAll() { return mBeings; @@ -152,13 +211,15 @@ void BeingManager::logic() being->logic(); - /* +#ifdef EATHENA_SUPPORT if (being->mAction == Being::DEAD && being->mFrame >= 20) { delete being; i = mBeings.erase(i); } - else*/ { + else +#endif + { i++; } } @@ -186,6 +247,7 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist, Being *closestBeing = NULL; int dist = 0; +#ifdef TMWSERV_SUPPORT //Why do we do this: //For some reason x,y passed to this function is always //in map coords, while down below its in pixels @@ -195,12 +257,20 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist, x = x * 32; y = y * 32; maxdist = maxdist * 32; +#endif - 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); +#ifdef TMWSERV_SUPPORT const Vector &pos = being->getPosition(); int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y); +#else + int d = abs(being->mX - x) + abs(being->mY - y); +#endif if ((being->getType() == type || type == Being::UNKNOWN) && (d < dist || closestBeing == NULL) // it is closer @@ -218,6 +288,38 @@ Being* BeingManager::findNearestLivingBeing(Uint16 x, Uint16 y, int maxdist, Being* BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist, Being::Type type) { - const Vector &aroundBeingPos = aroundBeing->getPosition(); - return findNearestLivingBeing((int) aroundBeingPos.x,(int) aroundBeingPos.y,maxdist,type); + Being *closestBeing = NULL; + int dist = 0; +#ifdef TMWSERV_SUPPORT + const Vector &apos = aroundBeing->getPosition(); + int x = apos.x; + int y = apos.y; + maxdist = maxdist * 32; +#else + int x = aroundBeing->mX; + int y = aroundBeing->mY; +#endif + + for (BeingIterator i = mBeings.begin(); i != mBeings.end(); i++) + { + Being *being = (*i); +#ifdef TMWSERV_SUPPORT + const Vector &pos = being->getPosition(); + int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y); +#else + int d = abs(being->mX - x) + abs(being->mY - y); +#endif + + if ((being->getType() == type || type == Being::UNKNOWN) + && (d < dist || closestBeing == NULL) // it is closer + && being->mAction != Being::DEAD // no dead beings + && being != aroundBeing + ) + { + dist = d; + closestBeing = being; + } + } + + return (maxdist >= dist) ? closestBeing : NULL; } diff --git a/src/beingmanager.h b/src/beingmanager.h index d3fb9888..726a73ec 100644 --- a/src/beingmanager.h +++ b/src/beingmanager.h @@ -1,31 +1,34 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_BEINGMANAGER_H -#define _TMW_BEINGMANAGER_H +#ifndef BEINGMANAGER_H +#define BEINGMANAGER_H #include "being.h" class LocalPlayer; class Map; +#ifdef EATHENA_SUPPORT +class Network; +#endif typedef std::list<Being*> Beings; typedef Beings::iterator BeingIterator; @@ -33,6 +36,10 @@ typedef Beings::iterator BeingIterator; class BeingManager { public: +#ifdef EATHENA_SUPPORT + BeingManager(Network *network); +#endif + /** * Sets the map on which beings are created */ @@ -46,7 +53,11 @@ class BeingManager /** * Create a being and add it to the list of beings. */ +#ifdef TMWSERV_SUPPORT Being *createBeing(int id, int type, int subtype); +#else + Being *createBeing(Uint32 id, Uint16 job); +#endif /** * Remove a Being. @@ -56,7 +67,7 @@ class BeingManager /** * Returns a specific id Being. */ - Being* findBeing(Uint16 id); + Being* findBeing(Uint32 id); /** * Returns a being at specific coordinates. @@ -77,6 +88,11 @@ class BeingManager Being::Type type = Being::UNKNOWN); /** + * Finds a being by name and (optionally) by type. + */ + Being* findBeingByName(std::string name, Being::Type type = Being::UNKNOWN); + + /** * Returns a being nearest to another being. * * \param maxdist maximal distance. If minimal distance is larger, @@ -103,6 +119,9 @@ class BeingManager protected: Beings mBeings; Map *mMap; +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif }; extern BeingManager *beingManager; diff --git a/src/configlistener.h b/src/configlistener.h index b740720f..ec7d6a2c 100644 --- a/src/configlistener.h +++ b/src/configlistener.h @@ -1,29 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_CONFIGLISTENER_H -#define _TMW_CONFIGLISTENER_H - -#include <iosfwd> +#ifndef CONFIGLISTENER_H +#define CONFIGLISTENER_H +#include <string> /** * The listener interface for receiving notifications about changes to diff --git a/src/configuration.cpp b/src/configuration.cpp index e801083f..3c3ae1d5 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -1,35 +1,131 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * 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" +#include "utils/stringutils.h" #include "utils/xml.h" +void ConfigurationObject::setValue(const std::string &key, std::string value) +{ + mOptions[key] = value; +} + +void ConfigurationObject::setValue(const std::string &key, float value) +{ + setValue(key, toString((value == (int)value) ? (int)value : value)); +} + +void Configuration::setValue(const std::string &key, float value) +{ + setValue(key, toString((value == (int)value) ? (int)value : value)); +} + +void Configuration::setValue(const std::string &key, std::string value) +{ + ConfigurationObject::setValue(key, value); + + // Notify listeners + ListenerMapIterator list = mListenerMap.find(key); + if (list != mListenerMap.end()) { + Listeners listeners = list->second; + for (ListenerIterator i = listeners.begin(); i != listeners.end(); i++) + { + (*i)->optionChanged(key); + } + } +} + +std::string ConfigurationObject::getValue(const std::string &key, + std::string deflt) +{ + OptionIterator iter = mOptions.find(key); + return ((iter != mOptions.end()) ? iter->second : deflt); +} + +float ConfigurationObject::getValue(const std::string &key, float deflt) +{ + OptionIterator iter = mOptions.find(key); + return (iter != mOptions.end()) ? atof(iter->second.c_str()) : deflt; +} + +void ConfigurationObject::deleteList(const std::string &name) +{ + for (ConfigurationList::const_iterator + it = mContainerOptions[name].begin(); it != mContainerOptions[name].end(); it++) + delete *it; + + mContainerOptions[name].clear(); +} + +void ConfigurationObject::clear() +{ + for (std::map<std::string, ConfigurationList>::const_iterator + it = mContainerOptions.begin(); it != mContainerOptions.end(); it++) + deleteList(it->first); + mOptions.clear(); +} + +ConfigurationObject::~ConfigurationObject() +{ + clear(); +} + +void ConfigurationObject::initFromXML(xmlNodePtr parent_node) +{ + clear(); + + for_each_xml_child_node(node, parent_node) + { + if (xmlStrEqual(node->name, BAD_CAST "list")) { + // list option handling + + std::string name = XML::getProperty(node, "name", std::string()); + + for_each_xml_child_node(subnode, node) + { + if (xmlStrEqual(subnode->name, BAD_CAST name.c_str()) + && subnode->type == XML_ELEMENT_NODE) { + ConfigurationObject *cobj = new ConfigurationObject; + + cobj->initFromXML(subnode); // recurse + + mContainerOptions[name].push_back(cobj); + } + } + + } else if (xmlStrEqual(node->name, BAD_CAST "option")) { + // single option handling + + std::string name = XML::getProperty(node, "name", std::string()); + std::string value = XML::getProperty(node, "value", std::string()); + + if (!name.empty() && !value.empty()) + mOptions[name] = value; + } // otherwise ignore + } +} + void Configuration::init(const std::string &filename) { mConfigPath = filename; @@ -55,21 +151,41 @@ void Configuration::init(const std::string &filename) return; } - for_each_xml_child_node(node, rootNode) + initFromXML(rootNode); + + xmlFreeDoc(doc); +} + +void ConfigurationObject::writeToXML(xmlTextWriterPtr writer) +{ + for (OptionIterator i = mOptions.begin(); i != mOptions.end(); i++) { - if (!xmlStrEqual(node->name, BAD_CAST "option")) - continue; + xmlTextWriterStartElement(writer, BAD_CAST "option"); + xmlTextWriterWriteAttribute(writer, + BAD_CAST "name", BAD_CAST i->first.c_str()); + xmlTextWriterWriteAttribute(writer, + BAD_CAST "value", BAD_CAST i->second.c_str()); + xmlTextWriterEndElement(writer); + } - std::string name = XML::getProperty(node, "name", std::string()); - std::string value = XML::getProperty(node, "value", std::string()); + for (std::map<std::string, ConfigurationList>::const_iterator + it = mContainerOptions.begin(); it != mContainerOptions.end(); it++) { + const char *name = it->first.c_str(); - if (!name.empty() && !value.empty()) - { - mOptions[name] = value; + xmlTextWriterStartElement(writer, BAD_CAST "list"); + xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name); + + // recurse on all elements + for (ConfigurationList::const_iterator + elt_it = it->second.begin(); elt_it != it->second.end(); elt_it++) { + + xmlTextWriterStartElement(writer, BAD_CAST name); + (*elt_it)->writeToXML(writer); + xmlTextWriterEndElement(writer); } - } - xmlFreeDoc(doc); + xmlTextWriterEndElement(writer); + } } void Configuration::write() @@ -98,52 +214,12 @@ void Configuration::write() xmlTextWriterStartDocument(writer, NULL, NULL, NULL); xmlTextWriterStartElement(writer, BAD_CAST "configuration"); - for (OptionIterator i = mOptions.begin(); i != mOptions.end(); i++) - { - xmlTextWriterStartElement(writer, BAD_CAST "option"); - xmlTextWriterWriteAttribute(writer, - BAD_CAST "name", BAD_CAST i->first.c_str()); - xmlTextWriterWriteAttribute(writer, - BAD_CAST "value", BAD_CAST i->second.c_str()); - xmlTextWriterEndElement(writer); - } + writeToXML(writer); xmlTextWriterEndDocument(writer); xmlFreeTextWriter(writer); } -void Configuration::setValue(const std::string &key, std::string value) -{ - mOptions[key] = value; - - // Notify listeners - ListenerMapIterator list = mListenerMap.find(key); - if (list != mListenerMap.end()) { - Listeners listeners = list->second; - for (ListenerIterator i = listeners.begin(); i != listeners.end(); i++) - { - (*i)->optionChanged(key); - } - } -} - -void Configuration::setValue(const std::string &key, float value) -{ - setValue(key, toString((value == (int)value) ? (int)value : value)); -} - -std::string Configuration::getValue(const std::string &key, std::string deflt) -{ - OptionIterator iter = mOptions.find(key); - return ((iter != mOptions.end()) ? iter->second : deflt); -} - -float Configuration::getValue(const std::string &key, float deflt) -{ - OptionIterator iter = mOptions.find(key); - return (iter != mOptions.end()) ? atof(iter->second.c_str()) : deflt; -} - void Configuration::addListener( const std::string &key, ConfigListener *listener) { diff --git a/src/configuration.h b/src/configuration.h index 72ae866c..0134f29a 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -1,52 +1,78 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_CONFIGURATION_H -#define _TMW_CONFIGURATION_H +#ifndef CONFIGURATION_H +#define CONFIGURATION_H -#include <map> +#include <libxml/xmlwriter.h> + +#include <cassert> #include <list> +#include <map> #include <string> class ConfigListener; +class ConfigurationObject; /** - * Configuration handler for reading (and writing). + * Configuration list manager interface; responsible for serlialising/deserialising + * configuration choices in containers. * - * \ingroup CORE + * \param T Type of the container elements to serialise + * \param CONT Type of the container we (de)serialise */ -class Configuration +template <class T, class CONT> +class ConfigurationListManager { public: /** - * Reads config file and parse all options into memory. + * Writes a value into a configuration object * - * \param filename path to config file + * \param value The value to write out + * \param obj The configuation object to write to + * \return obj, or otherwise NULL to indicate that this option should be skipped */ - void init(const std::string &filename); + virtual ConfigurationObject *writeConfigItem(T value, ConfigurationObject *obj) = 0; /** - * Writes the current settings back to the config file. + * Reads a value from a configuration object + * + * \param obj The configuration object to read from + * \param container The container to insert the object to */ - void write(); + virtual CONT readConfigItem(ConfigurationObject *obj, CONT container) = 0; +}; + +/** + * Configuration object, mapping values to names and possibly containing + * lists of further configuration objects + * + * \ingroup CORE + */ +class ConfigurationObject +{ + friend class Configuration; + + public: + virtual ~ConfigurationObject(); /** * Sets an option using a string value. @@ -54,7 +80,7 @@ class Configuration * \param key Option identifier. * \param value Value. */ - void setValue(const std::string &key, std::string value); + virtual void setValue(const std::string &key, std::string value); /** * Sets an option using a numeric value. @@ -62,7 +88,7 @@ class Configuration * \param key Option identifier. * \param value Value. */ - void setValue(const std::string &key, float value); + virtual void setValue(const std::string &key, float value); /** * Gets a value as string. @@ -81,6 +107,102 @@ class Configuration float getValue(const std::string &key, float deflt); /** + * Re-sets all data in the configuration + */ + virtual void clear(); + + /** + * Serialises a container into a list of configuration options + * + * \param IT Iterator type over CONT + * \param T Elements that IT iterates over + * \param CONT The associated container type + * + * \param name Name of the list the elements should be stored under + * \param begin Iterator start + * \param end Iterator end + * \param manager An object capable of serialising T items + */ + template <class IT, class T, class CONT> + void setList(const std::string &name, IT begin, IT end, ConfigurationListManager<T, CONT> *manager) + { + ConfigurationObject *nextobj = new ConfigurationObject; + deleteList(name); + ConfigurationList *list = &(mContainerOptions[name]); + + for (IT it = begin; it != end; it++) { + ConfigurationObject *wrobj = manager->writeConfigItem(*it, nextobj); + if (wrobj) { // wrote something + assert (wrobj == nextobj); + nextobj = new ConfigurationObject; + list->push_back(wrobj); + } else + nextobj->clear(); // you never know... + } + + delete nextobj; + } + + /** + * Serialises a container into a list of configuration options + * + * \param IT Iterator type over CONT + * \param T Elements that IT iterates over + * \param CONT The associated container type + * + * \param name Name of the list the elements should be read from under + * \param empty Initial (empty) container to write to + * \param manager An object capable of deserialising items into CONT + */ + template<class T, class CONT> + CONT getList(const std::string &name, CONT empty, ConfigurationListManager<T, CONT> *manager) + { + ConfigurationList *list = &(mContainerOptions[name]); + CONT container = empty; + + for (ConfigurationList::const_iterator it = list->begin(); it != list->end(); it++) + container = manager->readConfigItem(*it, container); + + return container; + } + + protected: + virtual void initFromXML(xmlNodePtr node); + virtual void writeToXML(xmlTextWriterPtr writer); + + void deleteList(const std::string &name); + + typedef std::map<std::string, std::string> Options; + typedef Options::iterator OptionIterator; + Options mOptions; + + typedef std::list<ConfigurationObject *> ConfigurationList; + std::map<std::string, ConfigurationList> mContainerOptions; +}; + +/** + * Configuration handler for reading (and writing). + * + * \ingroup CORE + */ +class Configuration : public ConfigurationObject +{ + public: + virtual ~Configuration() {} + + /** + * Reads config file and parse all options into memory. + * + * \param filename path to config file + */ + void init(const std::string &filename); + + /** + * Writes the current settings back to the config file. + */ + void write(); + + /** * Adds a listener to the listen list of the specified config option. */ void addListener(const std::string &key, ConfigListener *listener); @@ -91,11 +213,10 @@ class Configuration */ void removeListener(const std::string &key, ConfigListener *listener); - private: - typedef std::map<std::string, std::string> Options; - typedef Options::iterator OptionIterator; - Options mOptions; + virtual void setValue(const std::string &key, std::string value); + virtual void setValue(const std::string &key, float value); + private: typedef std::list<ConfigListener*> Listeners; typedef Listeners::iterator ListenerIterator; typedef std::map<std::string, Listeners> ListenerMap; diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp index 52f1eb31..d9234f66 100644 --- a/src/effectmanager.cpp +++ b/src/effectmanager.cpp @@ -1,33 +1,33 @@ /* - * The Mana World - * Copyright 2004 The Mana World Development Team + * An effects manager + * Copyright (C) 2008 Fate <fate.tmw@googlemail.com> + * Copyright (C) 2008 Chuck Miller <shadowmil@gmail.com> * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "being.h" #include "effectmanager.h" - -#include "particle.h" #include "log.h" +#include "particle.h" #include "sound.h" #include "utils/xml.h" - EffectManager::EffectManager() { XML::Document doc("effects.xml"); @@ -60,22 +60,42 @@ EffectManager::~EffectManager() { } +bool EffectManager::trigger(int id, Being* being) +{ + bool rValue = false; + for (std::list<EffectDescription>::iterator i = mEffects.begin(); i != mEffects.end(); ++i) + { + if ((*i).id == id) + { + rValue = true; + if (!(*i).GFX.empty()) + { + Particle *selfFX; + selfFX = particleEngine->addEffect((*i).GFX, 0, 0); + being->controlParticle(selfFX); + } + if (!(*i).SFX.empty()) + sound.playSfx((*i).SFX); + break; + } + } + return rValue; +} + bool EffectManager::trigger(int id, int x, int y) { bool rValue = false; - for (std::list<EffectDescription>::iterator i = mEffects.begin(); - i != mEffects.end(); ++i) + for (std::list<EffectDescription>::iterator i = mEffects.begin(); i != mEffects.end(); ++i) { if ((*i).id == id) { rValue = true; - if ((*i).GFX != "") + if (!(*i).GFX.empty()) particleEngine->addEffect((*i).GFX, x, y); - if ((*i).SFX != "") + if (!(*i).SFX.empty()) sound.playSfx((*i).SFX); break; } } return rValue; } - diff --git a/src/effectmanager.h b/src/effectmanager.h index 4b349471..01c5a6b8 100644 --- a/src/effectmanager.h +++ b/src/effectmanager.h @@ -1,34 +1,38 @@ /* - * The Mana World - * Copyright 2004 The Mana World Development Team + * An effects manager + * Copyright (C) 2008 Fate <fate.tmw@googlemail.com> + * Copyright (C) 2008 Chuck Miller <shadowmil@gmail.com> * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _EFFECT_MANAGER_H -#define _EFFECT_MANAGER_H +#ifndef EFFECT_MANAGER_H +#define EFFECT_MANAGER_H -#include <string> #include <list> +#include <string> + +class Being; class EffectManager { public: - struct EffectDescription { + struct EffectDescription + { int id; std::string GFX; std::string SFX; @@ -38,16 +42,21 @@ class EffectManager ~EffectManager(); /** - * Triggers a effect with the id, at x,y - * returns true if ID exists + * Triggers a effect with the id, at + * the specified being. */ - bool trigger(int id, int x = 0, int y = 0); + bool trigger(int id, Being* being); + + /** + * Triggers a effect with the id, at + * the specified x and y coordinate. + */ + bool trigger(int id, int x, int y); private: std::list<EffectDescription> mEffects; - }; extern EffectManager *effectManager; -#endif // _EFFECT_MANAGER_H +#endif // EFFECT_MANAGER_H diff --git a/src/emoteshortcut.cpp b/src/emoteshortcut.cpp new file mode 100644 index 00000000..46e13782 --- /dev/null +++ b/src/emoteshortcut.cpp @@ -0,0 +1,77 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "emoteshortcut.h" + +#include "configuration.h" +#include "localplayer.h" + +#include "utils/stringutils.h" + +EmoteShortcut::EmoteShortcut *emoteShortcut; + +EmoteShortcut::EmoteShortcut(): + mEmoteSelected(0) +{ + for (int i = 0; i < SHORTCUT_EMOTES; i++) + { + mEmotes[i] = i + 1; + } + load(); +} + +EmoteShortcut::~EmoteShortcut() +{ + save(); +} + +void EmoteShortcut::load() +{ + for (int i = 0; i < SHORTCUT_EMOTES; i++) + { + int emoteId = (int) config.getValue("emoteshortcut" + toString(i), i + 1); + + if (emoteId) + { + mEmotes[i] = emoteId; + } + } +} + +void EmoteShortcut::save() +{ + for (int i = 0; i < SHORTCUT_EMOTES; i++) + { + const int emoteId = mEmotes[i] ? mEmotes[i] : 0; + config.setValue("emoteshortcut" + toString(i), emoteId); + } +} + +void EmoteShortcut::useEmote(int index) +{ + if ((index > 0) && (index <= SHORTCUT_EMOTES)) + { + if (mEmotes[index - 1] > 0) + { + player_node->emote(mEmotes[index - 1]); + } + } +} diff --git a/src/emoteshortcut.h b/src/emoteshortcut.h new file mode 100644 index 00000000..ceb51a9b --- /dev/null +++ b/src/emoteshortcut.h @@ -0,0 +1,125 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EMOTESHORTCUT_H +#define EMOTESHORTCUT_H + +#define SHORTCUT_EMOTES 12 + +/** + * The class which keeps track of the emote shortcuts. + */ +class EmoteShortcut +{ + public: + /** + * Constructor. + */ + EmoteShortcut(); + + /** + * Destructor. + */ + ~EmoteShortcut(); + + /** + * Load the configuration information. + */ + void load(); + + /** + * Returns the shortcut Emote ID specified by the index. + * + * @param index Index of the shortcut Emote. + */ + int getEmote(int index) const + { return mEmotes[index]; } + + /** + * Returns the amount of shortcut Emotes. + */ + int getEmoteCount() const + { return SHORTCUT_EMOTES; } + + /** + * Returns the emote ID that is currently selected. + */ + int getEmoteSelected() const + { return mEmoteSelected; } + + /** + * Adds the selected emote ID to the emotes specified by the index. + * + * @param index Index of the emotes. + */ + void setEmote(int index) + { mEmotes[index] = mEmoteSelected; } + + /** + * Adds a emoticon to the emotes store specified by the index. + * + * @param index Index of the emote. + * @param emoteId ID of the emote. + */ + void setEmotes(int index, int emoteId) + { mEmotes[index] = emoteId; } + + /** + * Set the Emote that is selected. + * + * @param emoteId The ID of the emote that is to be assigned. + */ + void setEmoteSelected(int emoteId) + { mEmoteSelected = emoteId; } + + /** + * A flag to check if the Emote is selected. + */ + bool isEmoteSelected() + { return mEmoteSelected; } + + /** + * Remove a Emote from the shortcut. + */ + void removeEmote(int index) + { mEmotes[index] = 0; } + + /** + * Try to use the Emote specified by the index. + * + * @param index Index of the emote shortcut. + */ + void useEmote(int index); + + private: + /** + * Save the configuration information. + */ + void save(); + + int mEmotes[SHORTCUT_EMOTES]; /**< The emote stored. */ + int mEmoteSelected; /**< The emote held by cursor. */ + +}; + +extern EmoteShortcut *emoteShortcut; + +#endif diff --git a/src/engine.cpp b/src/engine.cpp index f191280e..872ecd57 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -1,35 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "engine.h" - -#include <list> - -#include "being.h" #include "beingmanager.h" -#include "configuration.h" +#include "engine.h" #include "flooritemmanager.h" #include "game.h" -#include "graphics.h" -#include "main.h" #include "localplayer.h" #include "log.h" #include "map.h" @@ -40,19 +33,27 @@ #include "gui/minimap.h" #include "gui/viewport.h" +#ifdef EATHENA_SUPPORT +#include "net/messageout.h" +#include "net/ea/protocol.h" +#endif + #include "resources/mapreader.h" #include "resources/monsterdb.h" #include "resources/resourcemanager.h" -#include "utils/dtor.h" -#include "utils/tostring.h" - -extern Minimap *minimap; +#include "utils/stringutils.h" char itemCurrenyQ[10] = "0"; +#ifdef TMWSERV_SUPPORT Engine::Engine(): mCurrentMap(NULL) +#else +Engine::Engine(Network *network): + mCurrentMap(NULL), + mNetwork(network) +#endif { } @@ -63,32 +64,60 @@ Engine::~Engine() void Engine::changeMap(const std::string &mapPath) { - // Clean up floor items + // Clean up floor items, beings and particles floorItemManager->clear(); - beingManager->clear(); particleEngine->clear(); + // Unset the map of the player so that its particles are cleared before + // being deleted in the next step + if (player_node) + player_node->setMap(0); + + particleEngine->clear(); + // Store full map path in global var +#ifdef TMWSERV_SUPPORT map_path = "maps/" + mapPath + ".tmx"; +#else + map_path = "maps/" + mapPath.substr(0, mapPath.rfind(".")) + ".tmx"; +#endif ResourceManager *resman = ResourceManager::getInstance(); if (!resman->exists(map_path)) - { map_path += ".gz"; - } // Attempt to load the new map Map *newMap = MapReader::readMap(map_path); - if (!newMap) { + if (!newMap) logger->error("Could not find map file"); - } // Notify the minimap and beingManager about the map change Image *mapImage = NULL; if (newMap->hasProperty("minimap")) { mapImage = resman->getImage(newMap->getProperty("minimap")); + + // Set the title for the Minimap + if (newMap->hasProperty("mapname")) + minimap->setCaption(newMap->getProperty("mapname")); + else if (newMap->hasProperty("name")) + minimap->setCaption(newMap->getProperty("name")); + else + { + minimap->setCaption("Unknown"); + logger->log("WARNING: Map file '%s' defines a minimap image but " + "does not define a 'mapname' property", + map_path.c_str()); + } + + // How many pixels equal one tile. .5 (which is the TMW default) is + // 2 tiles to a pixel, while 1 is 1 tile to 1 pixel + if (newMap->hasProperty("minimapproportion")) + minimap->setProportion(atof( + newMap->getProperty("minimapproportion").c_str())); + else + minimap->setProportion(0.5); } if (newMap->hasProperty("name")) { @@ -107,24 +136,32 @@ void Engine::changeMap(const std::string &mapPath) // Start playing new music file when necessary std::string oldMusic = ""; - if (mCurrentMap) { + if (mCurrentMap) + { oldMusic = mCurrentMap->getProperty("music"); delete mCurrentMap; } std::string newMusic = newMap->getProperty("music"); - if (newMusic != oldMusic) { + if (newMusic != oldMusic) sound.playMusic(newMusic, -1); - } mCurrentMap = newMap; mMapName = mapPath; + +#ifdef EATHENA_SUPPORT + // Send "map loaded" + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_MAP_LOADED); +#endif } void Engine::logic() { beingManager->logic(); particleEngine->update(); + if (mCurrentMap) + mCurrentMap->update(); gui->logic(); } diff --git a/src/engine.h b/src/engine.h index f676a271..60b1f6c8 100644 --- a/src/engine.h +++ b/src/engine.h @@ -1,31 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _ENGINE_H #define _ENGINE_H -#include <iosfwd> #include <string> class Map; +#ifdef EATHENA_SUPPORT +class Network; +#endif /** * Game engine. Actually hardly does anything anymore except keeping track of @@ -37,7 +39,11 @@ class Engine /** * Constructor. */ +#ifdef EATHENA_SUPPORT + Engine(Network *network); +#else Engine(); +#endif /** * Destructor. @@ -51,7 +57,6 @@ class Engine const std::string &getCurrentMapName() { return mMapName; } - /** * Sets the currently active map. */ @@ -64,6 +69,9 @@ class Engine private: Map *mCurrentMap; +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif std::string mMapName; }; diff --git a/src/equipment.cpp b/src/equipment.cpp index aa56b791..63743263 100644 --- a/src/equipment.cpp +++ b/src/equipment.cpp @@ -1,34 +1,47 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - #include "equipment.h" #include "item.h" +#ifdef EATHENA_SUPPORT +#include "inventory.h" +#include "localplayer.h" +#endif + +#include <algorithm> Equipment::Equipment() +#ifdef EATHENA_SUPPORT + : mArrows(0) +#endif { +#ifdef TMWSERV_SUPPORT std::fill_n(mEquipment, EQUIPMENT_SIZE, (Item*) 0); +#else + std::fill_n(mEquipment, EQUIPMENT_SIZE, 0); +#endif } +#ifdef TMWSERV_SUPPORT + Equipment::~Equipment() { clear(); @@ -50,3 +63,15 @@ void Equipment::setEquipment(int index, int id) delete mEquipment[index]; mEquipment[index] = (id > 0) ? new Item(id) : 0; } + +#else + +void Equipment::setEquipment(int index, int inventoryIndex) +{ + mEquipment[index] = inventoryIndex; + Item* item = player_node->getInventory()->getItem(inventoryIndex); + if (item) + item->setEquipped(true); +} + +#endif diff --git a/src/equipment.h b/src/equipment.h index 736074dd..7605175a 100644 --- a/src/equipment.h +++ b/src/equipment.h @@ -1,28 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_EQUIPMENT_H_ -#define _TMW_EQUIPMENT_H_ +#ifndef EQUIPMENT_H +#define EQUIPMENT_H +#ifdef TMWSERV_SUPPORT #define EQUIPMENT_SIZE 11 +#else +#define EQUIPMENT_SIZE 10 +#endif class Item; @@ -34,29 +38,63 @@ class Equipment */ Equipment(); +#ifdef TMWSERV_SUPPORT /** * Destructor. */ ~Equipment(); - - /** - * Clears equipment. - */ - void clear(); +#endif /** * Get equipment at the given slot. */ +#ifdef TMWSERV_SUPPORT Item* getEquipment(int index) +#else + int getEquipment(int index) const +#endif { return mEquipment[index]; } +#ifdef TMWSERV_SUPPORT + /** + * Clears equipment. + */ + void clear(); +#endif + /** * Set equipment at the given slot. */ +#ifdef TMWSERV_SUPPORT void setEquipment(int index, int id); +#else + void setEquipment(int index, int inventoryIndex); +#endif + +#ifdef EATHENA_SUPPORT + /** + * Remove equipment from the given slot. + */ + void removeEquipment(int index) { if (index >= 0 && index < EQUIPMENT_SIZE) mEquipment[index] = 0; } + + /** + * Returns the item used in the arrow slot. + */ + int getArrows() const { return mArrows; } + + /** + * Set the item used in the arrow slot. + */ + void setArrows(int arrows) { mArrows = arrows; } +#endif private: +#ifdef TMWSERV_SUPPORT Item* mEquipment[EQUIPMENT_SIZE]; +#else + int mEquipment[EQUIPMENT_SIZE]; + int mArrows; +#endif }; #endif diff --git a/src/floor_item.cpp b/src/floor_item.cpp index 7ad3c0c0..fbe606b4 100644 --- a/src/floor_item.cpp +++ b/src/floor_item.cpp @@ -1,28 +1,31 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "floor_item.h" - +#include "graphics.h" +#include "item.h" #include "map.h" +#include "resources/image.h" + FloorItem::FloorItem(unsigned int id, unsigned int itemId, unsigned short x, @@ -47,3 +50,15 @@ FloorItem::~FloorItem() delete mItem; } + +unsigned int FloorItem::getItemId() const +{ + return mItem->getId(); +} + +void FloorItem::draw(Graphics *graphics, int offsetX, int offsetY) const +{ + graphics->drawImage(mItem->getImage(), + mX * 32 + offsetX, + mY * 32 + offsetY); +} diff --git a/src/floor_item.h b/src/floor_item.h index b747310b..444c756a 100644 --- a/src/floor_item.h +++ b/src/floor_item.h @@ -1,32 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_FLOORITEM_H_ -#define _TMW_FLOORITEM_H_ +#ifndef FLOORITEM_H +#define FLOORITEM_H + +#include <list> -#include "graphics.h" -#include "item.h" -#include "map.h" #include "sprite.h" -#include "resources/image.h" + +class Graphics; +class Image; +class Item; +class Map; + +typedef std::list<Sprite*> Sprites; /** * An item lying on the floor. @@ -51,47 +56,36 @@ class FloorItem : public Sprite /** * Returns instance id of this item. */ - unsigned int - getId() const { return mId; } + unsigned int getId() const { return mId; } /** * Returns the item id. */ - unsigned int - getItemId() const { return mItem->getId(); } + unsigned int getItemId() const; /** * Returns the x coordinate. */ - unsigned short - getX() const { return mX; } + unsigned short getX() const { return mX; } /** * Returns the y coordinate. */ - unsigned short - getY() const { return mY; } + unsigned short getY() const { return mY; } /** * Returns the pixel y coordinate. * * @see Sprite::getPixelY() */ - int - getPixelY() const { return mY * 32; } + int getPixelY() const { return mY * 32; } /** * Draws this floor item to the given graphics context. * * @see Sprite::draw(Graphics, int, int) */ - void - draw(Graphics *graphics, int offsetX, int offsetY) const - { - graphics->drawImage(mItem->getImage(), - mX * 32 + offsetX, - mY * 32 + offsetY); - } + void draw(Graphics *graphics, int offsetX, int offsetY) const; private: unsigned int mId; diff --git a/src/flooritemmanager.cpp b/src/flooritemmanager.cpp index 68c84b5b..65556abb 100644 --- a/src/flooritemmanager.cpp +++ b/src/flooritemmanager.cpp @@ -1,27 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "flooritemmanager.h" - #include "floor_item.h" +#include "flooritemmanager.h" #include "utils/dtor.h" diff --git a/src/flooritemmanager.h b/src/flooritemmanager.h index 3dbaf988..3f96b587 100644 --- a/src/flooritemmanager.h +++ b/src/flooritemmanager.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_FLOORITEMMANAGER_H -#define _TMW_FLOORITEMMANAGER_H +#ifndef FLOORITEMMANAGER_H +#define FLOORITEMMANAGER_H #include <list> diff --git a/src/game.cpp b/src/game.cpp index 942c517c..cf1aa220 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,26 +1,24 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "game.h" - #include <fstream> #include <physfs.h> #include <sstream> @@ -29,11 +27,16 @@ #include <guichan/exception.hpp> #include "beingmanager.h" +#ifdef TMWSERV_SUPPORT #include "channelmanager.h" #include "commandhandler.h" +#endif #include "configuration.h" +#include "effectmanager.h" +#include "emoteshortcut.h" #include "engine.h" #include "flooritemmanager.h" +#include "game.h" #include "graphics.h" #include "itemshortcut.h" #include "joystick.h" @@ -42,30 +45,29 @@ #include "log.h" #include "npc.h" #include "particle.h" -#include "effectmanager.h" +#include "player_relations.h" -#include "gui/buddywindow.h" #include "gui/buy.h" #include "gui/buysell.h" #include "gui/chat.h" #include "gui/confirm_dialog.h" #include "gui/debugwindow.h" +#include "gui/emoteshortcutcontainer.h" +#include "gui/emotewindow.h" #include "gui/equipmentwindow.h" #include "gui/gui.h" -#include "gui/guildwindow.h" #include "gui/help.h" #include "gui/inventorywindow.h" -#include "gui/itemshortcutwindow.h" -#include "gui/magic.h" +#include "gui/shortcutwindow.h" +#include "gui/itemshortcutcontainer.h" #include "gui/menuwindow.h" #include "gui/minimap.h" #include "gui/ministatus.h" +#include "gui/npcintegerdialog.h" #include "gui/npclistdialog.h" -#include "gui/npcpostdialog.h" +#include "gui/npcstringdialog.h" #include "gui/npc_text.h" #include "gui/ok_dialog.h" -#include "gui/partywindow.h" -#include "gui/quitdialog.h" #include "gui/sdlinput.h" #include "gui/sell.h" #include "gui/setup.h" @@ -73,23 +75,42 @@ #include "gui/status.h" #include "gui/trade.h" #include "gui/viewport.h" +#ifdef TMWSERV_SUPPORT +#include "gui/buddywindow.h" +#include "gui/guildwindow.h" +#include "gui/magic.h" +#include "gui/npcpostdialog.h" +#include "gui/partywindow.h" +#include "gui/quitdialog.h" +#endif -#include "net/beinghandler.h" -#include "net/buysellhandler.h" #include "net/chathandler.h" -#include "net/guildhandler.h" -#include "net/inventoryhandler.h" #include "net/itemhandler.h" -#include "net/network.h" #include "net/npchandler.h" -#include "net/partyhandler.h" #include "net/playerhandler.h" #include "net/tradehandler.h" +#ifdef TMWSERV_SUPPORT +#include "net/network.h" +#include "net/beinghandler.h" +#include "net/buysellhandler.h" #include "net/effecthandler.h" +#include "net/guildhandler.h" +#include "net/inventoryhandler.h" +#include "net/partyhandler.h" +#else +#include "net/ea/network.h" +#include "net/ea/beinghandler.h" +#include "net/ea/buysellhandler.h" +#include "net/ea/equipmenthandler.h" +#include "net/ea/inventoryhandler.h" +#include "net/ea/protocol.h" +#include "net/ea/skillhandler.h" +#include "net/messageout.h" +#endif #include "resources/imagewriter.h" -extern Graphics *graphics; +#include "utils/gettext.h" class Map; @@ -98,12 +119,17 @@ std::string map_path; bool done = false; volatile int tick_time; volatile int fps = 0, frame = 0; + Engine *engine = NULL; Joystick *joystick = NULL; extern Window *weightNotice; extern Window *deathNotice; +#ifdef TMWSERV_SUPPORT QuitDialog *quitDialog = NULL; +#else +ConfirmDialog *exitConfirm = NULL; +#endif OkDialog *disconnectedDialog = NULL; ChatWindow *chatWindow; @@ -114,34 +140,41 @@ BuyDialog *buyDialog; SellDialog *sellDialog; BuySellDialog *buySellDialog; InventoryWindow *inventoryWindow; +EmoteWindow *emoteWindow; +NpcIntegerDialog *npcIntegerDialog; NpcListDialog *npcListDialog; NpcTextDialog *npcTextDialog; -NpcPostDialog *npcPostDialog; +NpcStringDialog *npcStringDialog; SkillDialog *skillDialog; +#ifdef TMWSERV_SUPPORT +BuddyWindow *buddyWindow; +GuildWindow *guildWindow; MagicDialog *magicDialog; +NpcPostDialog *npcPostDialog; +PartyWindow *partyWindow; +#endif Setup* setupWindow; Minimap *minimap; EquipmentWindow *equipmentWindow; TradeWindow *tradeWindow; -BuddyWindow *buddyWindow; -GuildWindow *guildWindow; HelpWindow *helpWindow; DebugWindow *debugWindow; -ItemShortcutWindow *itemShortcutWindow; -PartyWindow *partyWindow; +ShortcutWindow *itemShortcutWindow; +ShortcutWindow *emoteShortcutWindow; BeingManager *beingManager = NULL; FloorItemManager *floorItemManager = NULL; +#ifdef TMWSERV_SUPPORT ChannelManager *channelManager = NULL; CommandHandler *commandHandler = NULL; +#endif +Particle* particleEngine = NULL; EffectManager *effectManager = NULL; -Particle *particleEngine = NULL; - const int MAX_TIME = 10000; /** - * Listener used for exitting handling. + * Listener used for exiting handling. */ namespace { struct ExitListener : public gcn::ActionListener @@ -151,6 +184,9 @@ namespace { if (event.getId() == "yes" || event.getId() == "ok") { done = true; } +#ifdef EATHENA_SUPPORT + exitConfirm = NULL; +#endif disconnectedDialog = NULL; } } exitListener; @@ -173,15 +209,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; } } @@ -189,49 +228,67 @@ int get_elapsed_time(int start_time) /** * Create all the various globally accessible gui windows */ +#ifdef TMWSERV_SUPPORT void createGuiWindows() +#else +void createGuiWindows(Network *network) +#endif { // Create dialogs +#ifdef TMWSERV_SUPPORT chatWindow = new ChatWindow; - menuWindow = new MenuWindow(); - statusWindow = new StatusWindow(player_node); - miniStatusWindow = new MiniStatusWindow(); buyDialog = new BuyDialog; sellDialog = new SellDialog; - buySellDialog = new BuySellDialog(); - inventoryWindow = new InventoryWindow(); - npcTextDialog = new NpcTextDialog(); - npcListDialog = new NpcListDialog(); + tradeWindow = new TradeWindow; npcPostDialog = new NpcPostDialog(); - skillDialog = new SkillDialog(); magicDialog = new MagicDialog(); - setupWindow = new Setup(); - minimap = new Minimap(); equipmentWindow = new EquipmentWindow(player_node->mEquipment.get()); - tradeWindow = new TradeWindow; buddyWindow = new BuddyWindow(); guildWindow = new GuildWindow(); - helpWindow = new HelpWindow(); - debugWindow = new DebugWindow(); - itemShortcutWindow = new ItemShortcutWindow(); partyWindow = new PartyWindow(); - - // Initialize window positions - //buddyWindow->setPosition(10, minimap->getHeight() + 30); +#else + chatWindow = new ChatWindow(network); + buyDialog = new BuyDialog(network); + sellDialog = new SellDialog(network); + tradeWindow = new TradeWindow(network); + equipmentWindow = new EquipmentWindow; +#endif + menuWindow = new MenuWindow; + statusWindow = new StatusWindow(player_node); + miniStatusWindow = new MiniStatusWindow; + buySellDialog = new BuySellDialog; + inventoryWindow = new InventoryWindow; + emoteWindow = new EmoteWindow; + npcTextDialog = new NpcTextDialog; + npcIntegerDialog = new NpcIntegerDialog; + npcListDialog = new NpcListDialog; + npcStringDialog = new NpcStringDialog; + skillDialog = new SkillDialog; + setupWindow = new Setup; + minimap = new Minimap; + helpWindow = new HelpWindow; + debugWindow = new DebugWindow; + itemShortcutWindow = new ShortcutWindow("ItemShortcut",new ItemShortcutContainer); + emoteShortcutWindow = new ShortcutWindow("emoteShortcut",new EmoteShortcutContainer); // Set initial window visibility chatWindow->setVisible((bool) config.getValue( chatWindow->getWindowName() + "Visible", true)); miniStatusWindow->setVisible((bool) config.getValue( - miniStatusWindow->getWindowName() + "Visible", - true)); + miniStatusWindow->getWindowName() + "Visible", true)); buyDialog->setVisible(false); sellDialog->setVisible(false); + minimap->setVisible((bool) config.getValue( + minimap->getWindowName() + "Visible", true)); tradeWindow->setVisible(false); menuWindow->setVisible((bool) config.getValue( menuWindow->getWindowName() + "Visible", true)); itemShortcutWindow->setVisible((bool) config.getValue( itemShortcutWindow->getWindowName() + "Visible", true)); + emoteShortcutWindow->setVisible((bool) config.getValue( + emoteShortcutWindow->getWindowName() + "Visible", true)); + minimap->setVisible((bool) config.getValue( + minimap->getWindowName() + "Visible", true)); if (config.getValue("logToChat", 0)) { @@ -244,6 +301,7 @@ void createGuiWindows() */ void destroyGuiWindows() { + logger->setChatWindow(NULL); delete chatWindow; delete statusWindow; delete miniStatusWindow; @@ -252,47 +310,71 @@ void destroyGuiWindows() delete sellDialog; delete buySellDialog; delete inventoryWindow; + delete emoteWindow; + delete npcIntegerDialog; delete npcListDialog; delete npcTextDialog; + delete npcStringDialog; +#ifdef TMWSERV_SUPPORT delete npcPostDialog; - delete skillDialog; delete magicDialog; + delete buddyWindow; + delete guildWindow; + delete partyWindow; +#endif + delete skillDialog; delete setupWindow; delete minimap; delete equipmentWindow; delete tradeWindow; - delete buddyWindow; - delete guildWindow; delete helpWindow; delete debugWindow; delete itemShortcutWindow; - delete partyWindow; + delete emoteShortcutWindow; } +#ifdef TMWSERV_SUPPORT Game::Game(): mBeingHandler(new BeingHandler()), - mBuySellHandler(new BuySellHandler()), - mChatHandler(new ChatHandler()), mGuildHandler(new GuildHandler()), - mInventoryHandler(new InventoryHandler()), - mItemHandler(new ItemHandler()), - mNpcHandler(new NPCHandler()), mPartyHandler(new PartyHandler()), - mPlayerHandler(new PlayerHandler()), - mTradeHandler(new TradeHandler()), mEffectHandler(new EffectHandler()), +#else +Game::Game(Network *network): + mNetwork(network), + mBeingHandler(new BeingHandler(config.getValue("EnableSync", 0) == 1)), + mEquipmentHandler(new EquipmentHandler), + mSkillHandler(new SkillHandler), +#endif + mBuySellHandler(new BuySellHandler), + mChatHandler(new ChatHandler), + mInventoryHandler(new InventoryHandler), + mItemHandler(new ItemHandler), + mNpcHandler(new NPCHandler), + mPlayerHandler(new PlayerHandler), + mTradeHandler(new TradeHandler), mLogicCounterId(0), mSecondsCounterId(0) { done = false; +#ifdef TMWSERV_SUPPORT createGuiWindows(); engine = new Engine; beingManager = new BeingManager; - floorItemManager = new FloorItemManager(); +#else + createGuiWindows(network); + engine = new Engine(network); + + beingManager = new BeingManager(network); +#endif + + floorItemManager = new FloorItemManager; +#ifdef TMWSERV_SUPPORT channelManager = new ChannelManager(); commandHandler = new CommandHandler(); - effectManager = new EffectManager(); +#endif + effectManager = new EffectManager; particleEngine = new Particle(NULL); particleEngine->setupEngine(); @@ -308,6 +390,9 @@ Game::Game(): // Initialize beings beingManager->setPlayer(player_node); +#ifdef EATHENA_SUPPORT + player_node->setNetwork(network); +#endif Joystick::init(); // TODO: The user should be able to choose which one to use @@ -315,6 +400,7 @@ Game::Game(): if (Joystick::getNumberOfJoysticks() > 0) joystick = new Joystick(0); +#ifdef TMWSERV_SUPPORT Net::registerHandler(mBeingHandler.get()); Net::registerHandler(mBuySellHandler.get()); Net::registerHandler(mChatHandler.get()); @@ -326,19 +412,50 @@ Game::Game(): Net::registerHandler(mPlayerHandler.get()); Net::registerHandler(mTradeHandler.get()); Net::registerHandler(mEffectHandler.get()); +#else + network->registerHandler(mBeingHandler.get()); + network->registerHandler(mBuySellHandler.get()); + network->registerHandler(mChatHandler.get()); + network->registerHandler(mEquipmentHandler.get()); + network->registerHandler(mInventoryHandler.get()); + network->registerHandler(mItemHandler.get()); + network->registerHandler(mNpcHandler.get()); + network->registerHandler(mPlayerHandler.get()); + network->registerHandler(mSkillHandler.get()); + network->registerHandler(mTradeHandler.get()); + + /* + * 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 + * + * 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); + msg.writeInt32(tick_time); + + engine->changeMap(map_path); +#endif } Game::~Game() { +#ifdef TMWSERV_SUPPORT Net::clearHandlers(); +#endif delete player_node; destroyGuiWindows(); delete beingManager; delete floorItemManager; +#ifdef TMWSERV_SUPPORT delete channelManager; delete commandHandler; +#endif delete joystick; delete particleEngine; delete engine; @@ -387,12 +504,12 @@ static bool saveScreenshot() if (success) { std::stringstream chatlogentry; - chatlogentry << "Screenshot saved to ~/" << filenameSuffix.str(); + chatlogentry << _("Screenshot saved to ~/") << filenameSuffix.str(); chatWindow->chatLog(chatlogentry.str(), BY_SERVER); } else { - chatWindow->chatLog("Saving screenshot failed!", BY_SERVER); + chatWindow->chatLog(_("Saving screenshot failed!"), BY_SERVER); logger->log("Error: could not save screenshot."); } @@ -438,7 +555,7 @@ void Game::logic() // Draw a frame if either frames are not limited or enough time has // passed since the last frame. if (!mMinFrameTime || - get_elapsed_time(mDrawTime / 10) > mMinFrameTime) + get_elapsed_time(mDrawTime / 10) > mMinFrameTime) { frame++; gui->draw(); @@ -461,20 +578,25 @@ void Game::logic() } // Handle network stuff +#ifdef TMWSERV_SUPPORT Net::flush(); - // TODO: Fix notification when the connection is lost - if (false /*!mNetwork->isConnected() */) +#else + mNetwork->flush(); + mNetwork->dispatchMessages(); + + if (!mNetwork->isConnected()) { if (!disconnectedDialog) { - disconnectedDialog = new OkDialog("Network Error", - "The connection to the server was lost, " - "the program will now quit"); + disconnectedDialog = new OkDialog(_("Network Error"), + _("The connection to the server was lost, " + "the program will now quit")); disconnectedDialog->addActionListener(&exitListener); disconnectedDialog->requestMoveToTop(); } } +#endif } } @@ -495,7 +617,7 @@ void Game::handleInput() gcn::Window *requestedWindow = NULL; if (setupWindow->isVisible() && - keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) + keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) { keyboard.setNewKey((int) event.key.keysym.sym); keyboard.callbackNewKey(); @@ -503,6 +625,7 @@ void Game::handleInput() return; } +#ifdef TMWSERV_SUPPORT // send straight to gui for certain windows if (npcPostDialog->isVisible()) { @@ -517,61 +640,118 @@ void Game::handleInput() } return; } +#endif - switch (event.key.keysym.sym) + // Mode switch to emotes + if (keyboard.isKeyActive(keyboard.KEY_EMOTE)) { - case SDLK_F1: - // In-game Help - if (helpWindow->isVisible()) - { - helpWindow->setVisible(false); - } - else - { - helpWindow->loadHelp("index"); - helpWindow->requestMoveToTop(); - } + // Emotions + int emotion = keyboard.getKeyEmoteOffset(event.key.keysym.sym); + if (emotion) + { + emoteShortcut->useEmote(emotion); used = true; - break; - - case SDLK_RETURN: - // Input chat window - if (chatWindow->isInputFocused() || - deathNotice != NULL || - weightNotice != NULL) - { - break; - } + return; + } + } + if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT) || + keyboard.isKeyActive(keyboard.KEY_OK)) + { + // Input chat window + if (!(chatWindow->isInputFocused() || + deathNotice || + weightNotice)) + { +#ifdef TMWSERV_SUPPORT // Don not focus chat input when quit dialog is active - if(quitDialog != NULL && quitDialog->isVisible()) - break; - + if (quitDialog != NULL && quitDialog->isVisible()) + continue; +#else + // Quit by pressing Enter if the exit confirm is there + if (exitConfirm && + keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT)) + done = true; +#endif // Close the Browser if opened - if (helpWindow->isVisible()) - { + else if (helpWindow->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) helpWindow->setVisible(false); - } // Close the config window, cancelling changes if opened - else if (setupWindow->isVisible()) - { + else if (setupWindow->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) setupWindow->action(gcn::ActionEvent(NULL, "cancel")); - } + // Submits the text and proceeds to the next dialog + else if (npcStringDialog->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) + npcStringDialog->action(gcn::ActionEvent(NULL, "ok")); + // Proceed to the next dialog option, or close the window + else if (npcTextDialog->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) + npcTextDialog->action(gcn::ActionEvent(NULL, "ok")); + // Choose the currently highlighted dialogue option + else if (npcListDialog->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) + npcListDialog->action(gcn::ActionEvent(NULL, "ok")); + // Submits the text and proceeds to the next dialog + else if (npcIntegerDialog->isVisible() && + keyboard.isKeyActive(keyboard.KEY_OK)) + npcIntegerDialog->action(gcn::ActionEvent(NULL, "ok")); /* else if (guildWindow->isVisible()) { // TODO: Check if a dialog is open and close it if so } */ - // Else, open the chat edit box - else + else if (!(keyboard.getKeyValue( + KeyboardConfig::KEY_TOGGLE_CHAT) == + keyboard.getKeyValue( + KeyboardConfig::KEY_OK) && + (helpWindow->isVisible() || + setupWindow->isVisible() || + npcStringDialog->isVisible() || + npcTextDialog->isVisible() || + npcListDialog->isVisible() || + npcIntegerDialog->isVisible()))) { chatWindow->requestChatFocus(); used = true; } + } + } + + const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); + switch (tKey) + { + case KeyboardConfig::KEY_SCROLL_CHAT_UP: + if (chatWindow->isVisible()) + { + chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); + used = true; + } + break; + case KeyboardConfig::KEY_SCROLL_CHAT_DOWN: + if (chatWindow->isVisible()) + { + chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); + used = true; + return; + } break; - // Quitting confirmation dialog - case SDLK_ESCAPE: + case KeyboardConfig::KEY_WINDOW_HELP: + // In-game Help + if (helpWindow->isVisible()) + helpWindow->setVisible(false); + else + { + helpWindow->loadHelp("index"); + helpWindow->requestMoveToTop(); + } + used = true; + break; + // Quitting confirmation dialog + case KeyboardConfig::KEY_QUIT: +#ifdef TMWSERV_SUPPORT if (!quitDialog) { quitDialog = new QuitDialog(&done, &quitDialog); @@ -581,37 +761,58 @@ void Game::handleInput() { quitDialog->action(gcn::ActionEvent(NULL, "cancel")); } +#else + 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"))); + } +#endif break; - default: break; } - if (keyboard.isEnabled() && !chatWindow->isInputFocused() - && !guildWindow->isWindowFocused()) + && !npcStringDialog->isInputFocused()) { const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); + // Do not activate shortcuts if tradewindow is visible if (!tradeWindow->isVisible()) { // Checks if any item shortcut is pressed. - for (int i = KeyboardConfig::KEY_SHORTCUT_0; - i <= KeyboardConfig::KEY_SHORTCUT_9; - i++) + for (int i = KeyboardConfig::KEY_SHORTCUT_1; + i <= KeyboardConfig::KEY_SHORTCUT_12; + i++) { - if (tKey == i && !used) { + if (tKey == i && !used) + { itemShortcut->useItem( - i - KeyboardConfig::KEY_SHORTCUT_0); + i - KeyboardConfig::KEY_SHORTCUT_1); break; } } } - switch (tKey) { + + switch (tKey) + { case KeyboardConfig::KEY_PICKUP: { +#ifdef TMWSERV_SUPPORT const Vector &pos = player_node->getPosition(); Uint16 x = (int) pos.x / 32; Uint16 y = (int) pos.y / 32; +#else + Uint16 x = player_node->mX; + Uint16 y = player_node->mY; +#endif FloorItem *item = floorItemManager->findByCoordinates(x, y); @@ -630,8 +831,8 @@ void Game::handleInput() default: break; } - item = - floorItemManager->findByCoordinates(x, y); + item = floorItemManager->findByCoordinates( + x, y); } if (item) @@ -640,35 +841,29 @@ void Game::handleInput() used = true; } break; - - case KeyboardConfig::KEY_ATTACK: - player_node->attack(); - used = true; - break; - case KeyboardConfig::KEY_SIT: // Player sit action player_node->toggleSit(); used = true; break; - case KeyboardConfig::KEY_HIDE_WINDOWS: - // Hide certain windows + // Hide certain windows if (!chatWindow->isInputFocused()) { statusWindow->setVisible(false); inventoryWindow->setVisible(false); + emoteWindow->setVisible(false); skillDialog->setVisible(false); - magicDialog->setVisible(false); setupWindow->setVisible(false); equipmentWindow->setVisible(false); helpWindow->setVisible(false); debugWindow->setVisible(false); +#ifdef TMWSERV_SUPPORT guildWindow->setVisible(false); buddyWindow->setVisible(false); +#endif } break; - case KeyboardConfig::KEY_WINDOW_STATUS: requestedWindow = statusWindow; break; @@ -682,6 +877,7 @@ void Game::handleInput() requestedWindow = skillDialog; break; case KeyboardConfig::KEY_WINDOW_MINIMAP: + minimap->toggle(); requestedWindow = minimap; break; case KeyboardConfig::KEY_WINDOW_CHAT: @@ -696,83 +892,55 @@ void Game::handleInput() case KeyboardConfig::KEY_WINDOW_DEBUG: requestedWindow = debugWindow; break; - } - } - - if (requestedWindow) - { - requestedWindow->setVisible(!requestedWindow->isVisible()); - if (requestedWindow->isVisible()) - { - requestedWindow->requestMoveToTop(); - } - used = true; - } - - // Keys pressed together with Alt/Meta - // Emotions and some internal gui windows -#ifndef __APPLE__ - if (event.key.keysym.mod & KMOD_LALT) -#else - if (event.key.keysym.mod & KMOD_LMETA) -#endif - { - switch (event.key.keysym.sym) - { - case SDLK_p: + case KeyboardConfig::KEY_WINDOW_EMOTE: + requestedWindow = emoteWindow; + break; + case KeyboardConfig::KEY_WINDOW_EMOTE_SHORTCUT: + requestedWindow = emoteShortcutWindow; + break; + case KeyboardConfig::KEY_SCREENSHOT: // Screenshot (picture, hence the p) saveScreenshot(); used = true; break; - - default: - break; - - case SDLK_f: + case KeyboardConfig::KEY_PATHFIND: // Find path to mouse (debug purpose) viewport->toggleDebugPath(); used = true; break; - - case SDLK_t: + case KeyboardConfig::KEY_TRADE: // Toggle accepting of incoming trade requests + unsigned int deflt = player_relations.getDefault(); + if (deflt & PlayerRelation::TRADE) + { + chatWindow->chatLog( + _("Ignoring incoming trade requests"), + BY_SERVER); + deflt &= ~PlayerRelation::TRADE; + } + else { - TradeHandler *th = static_cast<TradeHandler*>( - mTradeHandler.get()); - th->setAcceptTradeRequests( - !th->acceptTradeRequests()); + chatWindow->chatLog( + _("Accepting incoming trade requests"), + BY_SERVER); + deflt |= PlayerRelation::TRADE; } + + player_relations.setDefault(deflt); + used = true; break; } + } - // 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; - } + if (requestedWindow) + { + requestedWindow->setVisible(!requestedWindow->isVisible()); + if (requestedWindow->isVisible()) + requestedWindow->requestMoveToTop(); + used = true; } } - // Quit event else if (event.type == SDL_QUIT) { @@ -801,15 +969,31 @@ void Game::handleInput() // Moving player around if (player_node->mAction != Being::DEAD && +#ifdef EATHENA_SUPPORT + current_npc == 0 && +#endif !chatWindow->isInputFocused()) { // Get the state of the keyboard keys keyboard.refreshActiveKeys(); - const Vector &pos = player_node->getPosition(); - Uint16 x = (int) pos.x / 32; - Uint16 y = (int) pos.y / 32; + // Ignore input if either "ignore" key is pressed + // Stops the character moving about if the user's window manager + // uses "ignore+arrow key" to switch virtual desktops. + if (keyboard.isKeyActive(keyboard.KEY_IGNORE_INPUT_1) || + keyboard.isKeyActive(keyboard.KEY_IGNORE_INPUT_2)) + { + return; + } +#ifdef TMWSERV_SUPPORT + const Vector &pos = player_node->getPosition(); + const Uint16 x = (int) pos.x / 32; + const Uint16 y = (int) pos.y / 32; +#else + const Uint16 x = player_node->mX; + const Uint16 y = player_node->mY; +#endif unsigned char direction = 0; // Translate pressed keys to movement and direction @@ -835,6 +1019,7 @@ void Game::handleInput() direction |= Being::RIGHT; } +#ifdef TMWSERV_SUPPORT // First if player is pressing key for the direction he is already // going if (direction == player_node->getWalkingDir()) @@ -854,31 +1039,100 @@ void Game::handleInput() { player_node->stopWalking(true); } +#else + player_node->setWalkingDir(direction); - // Target the nearest player if 'q' is pressed - if (keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER)) + // Attacking monsters + if (keyboard.isKeyActive(keyboard.KEY_ATTACK) || + (joystick && joystick->buttonPressed(0))) { - Being *target = beingManager->findNearestLivingBeing( - player_node, 20, Being::PLAYER); + Being *target = beingManager->findNearestLivingBeing(x, y, 20, + Being::MONSTER); - if (target) + bool newTarget = !keyboard.isKeyActive(keyboard.KEY_TARGET); + // A set target has highest priority + if (newTarget || !player_node->getTarget()) { - player_node->setTarget(target); + Uint16 targetX = x, targetY = y; + + 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); + if (!target) + target = beingManager->findBeing(targetX, targetY, Being::PLAYER); } + + player_node->attack(target, newTarget); + } +#endif + + // 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); + + player_node->setTarget(target); } // Target the nearest monster if 'a' pressed - if (keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST)) + if ((keyboard.isKeyActive(keyboard.KEY_TARGET_CLOSEST) || + (joystick && joystick->buttonPressed(3))) && + !keyboard.isKeyActive(keyboard.KEY_TARGET)) { Being *target = beingManager->findNearestLivingBeing( x, y, 20, Being::MONSTER); - if (target) + player_node->setTarget(target); + } + + // Target the nearest npc if 'n' pressed + if ( keyboard.isKeyActive(keyboard.KEY_TARGET_NPC) && + !keyboard.isKeyActive(keyboard.KEY_TARGET) ) + { + Being *target = beingManager->findNearestLivingBeing( + x, y, 20, Being::NPC); + + player_node->setTarget(target); + } + + // Talk to the nearest NPC if 't' pressed + if ( keyboard.isKeyActive(keyboard.KEY_TALK) ) + { + if (!npcTextDialog->isVisible() && !npcListDialog->isVisible()) { - player_node->setTarget(target); + Being *target = player_node->getTarget(); + + if (!target) + { + target = beingManager->findNearestLivingBeing( + x, y, 20, Being::NPC); + } + + if (target) + { + if (target->getType() == Being::NPC) + dynamic_cast<NPC*>(target)->talk(); + } } } +#ifdef EATHENA_SUPPORT + // Stop attacking if shift is pressed + if (keyboard.isKeyActive(keyboard.KEY_TARGET)) + { + player_node->stopAttack(); + } +#endif + if (joystick) { if (joystick->buttonPressed(1)) @@ -1,38 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GAME_ -#define _TMW_GAME_ +#ifndef GAME_H +#define GAME_H -#include <iosfwd> #include <memory> #include "SDL.h" #include "configlistener.h" -#define SPEECH_TIME 80 -#define SPEECH_MAX_TIME 100 - class MessageHandler; +#ifdef EATHENA_SUPPORT +class Network; +#endif extern std::string map_path; extern volatile int fps; @@ -41,7 +40,11 @@ extern volatile int tick_time; class Game : public ConfigListener { public: +#ifdef TMWSERV_SUPPORT Game(); +#else + Game(Network *network); +#endif ~Game(); void logic(); @@ -51,6 +54,10 @@ class Game : public ConfigListener void optionChanged(const std::string &name); private: +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif + /** Used to determine whether to draw the next frame. */ int mDrawTime; @@ -59,17 +66,22 @@ class Game : public ConfigListener typedef const std::auto_ptr<MessageHandler> MessageHandlerPtr; MessageHandlerPtr mBeingHandler; +#ifdef TMWSERV_SUPPORT + MessageHandlerPtr mGuildHandler; + MessageHandlerPtr mPartyHandler; + MessageHandlerPtr mEffectHandler; +#else + MessageHandlerPtr mEquipmentHandler; + MessageHandlerPtr mSkillHandler; +#endif MessageHandlerPtr mBuySellHandler; MessageHandlerPtr mChatHandler; - MessageHandlerPtr mGuildHandler; MessageHandlerPtr mInventoryHandler; MessageHandlerPtr mItemHandler; MessageHandlerPtr mNpcHandler; - MessageHandlerPtr mPartyHandler; MessageHandlerPtr mPlayerHandler; MessageHandlerPtr mPostHandler; MessageHandlerPtr mTradeHandler; - MessageHandlerPtr mEffectHandler; SDL_TimerID mLogicCounterId; SDL_TimerID mSecondsCounterId; diff --git a/src/graphics.cpp b/src/graphics.cpp index 6920bcb0..4af7b723 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -42,6 +42,8 @@ bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel) logger->log("Setting video mode %dx%d %s", w, h, fs ? "fullscreen" : "windowed"); + logger->log("Bits per pixel: %d", bpp); + int displayFlags = SDL_ANYFORMAT; mFullscreen = fs; @@ -69,7 +71,7 @@ bool Graphics::setVideoMode(int w, int h, int bpp, bool fs, bool hwaccel) logger->log("Using video driver: %s", videoDriverName); } else { - logger->log("Using video driver: unkown"); + logger->log("Using video driver: unknown"); } const SDL_VideoInfo *vi = SDL_GetVideoInfo(); @@ -176,13 +178,12 @@ void Graphics::drawImagePattern(Image *image, int x, int y, int w, int h) } } -void -Graphics::drawImageRect(int x, int y, int w, int h, - Image *topLeft, Image *topRight, - Image *bottomLeft, Image *bottomRight, - Image *top, Image *right, - Image *bottom, Image *left, - Image *center) +void Graphics::drawImageRect(int x, int y, int w, int h, + Image *topLeft, Image *topRight, + Image *bottomLeft, Image *bottomRight, + Image *top, Image *right, + Image *bottom, Image *left, + Image *center) { pushClipArea(gcn::Rectangle(x, y, w, h)); @@ -220,9 +221,8 @@ Graphics::drawImageRect(int x, int y, int w, int h, popClipArea(); } -void -Graphics::drawImageRect(int x, int y, int w, int h, - const ImageRect &imgRect) +void Graphics::drawImageRect(int x, int y, int w, int h, + const ImageRect &imgRect) { drawImageRect(x, y, w, h, imgRect.grid[0], imgRect.grid[2], imgRect.grid[6], imgRect.grid[8], diff --git a/src/graphics.h b/src/graphics.h index efdd1ac1..172032dc 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -46,14 +46,16 @@ struct SDL_Surface; * Sections 0, 2, 6 and 8 will remain as is. 1, 3, 4, 5 and 7 will be * repeated to fit the size of the widget. */ -struct ImageRect { +struct ImageRect +{ Image *grid[9]; }; /** * A central point of control for graphics. */ -class Graphics : public gcn::SDLGraphics { +class Graphics : public gcn::SDLGraphics +{ public: /** * Constructor. @@ -95,17 +97,15 @@ class Graphics : public gcn::SDLGraphics { * @return <code>true</code> if the image was blitted properly * <code>false</code> otherwise. */ - virtual bool - drawImage(Image *image, - int srcX, int srcY, - int dstX, int dstY, - int width, int height, - bool useColor = false); - - virtual void - drawImagePattern(Image *image, - int x, int y, - int w, int h); + virtual bool drawImage(Image *image, + int srcX, int srcY, + int dstX, int dstY, + int width, int height, + bool useColor = false); + + virtual void drawImagePattern(Image *image, + int x, int y, + int w, int h); /** * Draws a rectangle using images. 4 corner images, 4 side images and 1 @@ -153,4 +153,6 @@ class Graphics : public gcn::SDLGraphics { bool mFullscreen, mHWAccel; }; +extern Graphics *graphics; + #endif diff --git a/src/gui/box.h b/src/gui/box.h deleted file mode 100644 index 46654b48..00000000 --- a/src/gui/box.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 BOX_H -#define BOX_H - -#include <guichan/widgets/container.hpp> - -#include "../guichanfwd.h" - -class Box : public gcn::Container -{ - public: - /** - * Returns padding. - */ - unsigned int getPadding(); - - /** - * Sets padding between widgets. - */ - void setPadding(unsigned int); - - protected: - Box(); - virtual ~Box(); - - /** - * Spacing between client widgets. - */ - unsigned int padding; - - virtual void draw(gcn::Graphics *) = 0; - - typedef std::list<gcn::Widget*> Widgets; - typedef Widgets::iterator WidgetIterator; -}; - -#endif diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp index 03540d31..7c0ae1a7 100644 --- a/src/gui/browserbox.cpp +++ b/src/gui/browserbox.cpp @@ -1,35 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <algorithm> -#include "browserbox.h" +#include <guichan/graphics.hpp> +#include "browserbox.h" +#include "color.h" #include "linkhandler.h" #include "truetypefont.h" -BrowserBox::BrowserBox(unsigned int mode): +BrowserBox::BrowserBox(unsigned int mode, bool opaque): gcn::Widget(), mMode(mode), mHighMode(UNDERLINE | BACKGROUND), - mOpaque(true), + mOpaque(opaque), mUseLinksAndUserColors(true), mSelectedLink(-1), mMaxRows(0) @@ -98,12 +100,12 @@ void BrowserBox::addRow(const std::string &row) mLinks.push_back(bLink); - newRow += "##L" + bLink.caption; + newRow += "##<" + bLink.caption; tmp.erase(0, idx3 + 2); - if(tmp != "") + if (!tmp.empty()) { - newRow += "##P"; + newRow += "##>"; } idx1 = tmp.find("@@"); } @@ -122,7 +124,18 @@ void BrowserBox::addRow(const std::string &row) //discard older rows when a row limit has been set if (mMaxRows > 0) { - while (mTextRows.size() > mMaxRows) mTextRows.pop_front(); + while (mTextRows.size() > mMaxRows) + { + mTextRows.pop_front(); + for (unsigned int i = 0; i < mLinks.size(); i++) + { + mLinks[i].y1 -= font->getHeight(); + mLinks[i].y2 -= font->getHeight(); + + if (mLinks[i].y1 < 0) + mLinks.erase(mLinks.begin() + i); + } + } } // Auto size mode @@ -210,8 +223,7 @@ struct MouseOverLink int mX, mY; }; -void -BrowserBox::mousePressed(gcn::MouseEvent &event) +void BrowserBox::mousePressed(gcn::MouseEvent &event) { LinkIterator i = find_if(mLinks.begin(), mLinks.end(), MouseOverLink(event.getX(), event.getY())); @@ -221,8 +233,7 @@ BrowserBox::mousePressed(gcn::MouseEvent &event) } } -void -BrowserBox::mouseMoved(gcn::MouseEvent &event) +void BrowserBox::mouseMoved(gcn::MouseEvent &event) { LinkIterator i = find_if(mLinks.begin(), mLinks.end(), MouseOverLink(event.getX(), event.getY())); @@ -230,8 +241,7 @@ BrowserBox::mouseMoved(gcn::MouseEvent &event) mSelectedLink = (i != mLinks.end()) ? (i - mLinks.begin()) : -1; } -void -BrowserBox::draw(gcn::Graphics *graphics) +void BrowserBox::draw(gcn::Graphics *graphics) { if (mOpaque) { @@ -241,9 +251,10 @@ BrowserBox::draw(gcn::Graphics *graphics) if (mSelectedLink >= 0) { + bool valid; if ((mHighMode & BACKGROUND)) { - graphics->setColor(gcn::Color(HIGHLIGHT)); + graphics->setColor(gcn::Color(textColor->getColor('H', valid))); graphics->fillRectangle(gcn::Rectangle( mLinks[mSelectedLink].x1, mLinks[mSelectedLink].y1, @@ -254,7 +265,7 @@ BrowserBox::draw(gcn::Graphics *graphics) if ((mHighMode & UNDERLINE)) { - graphics->setColor(gcn::Color(LINK)); + graphics->setColor(gcn::Color(textColor->getColor('<', valid))); graphics->drawLine( mLinks[mSelectedLink].x1, mLinks[mSelectedLink].y2, @@ -265,6 +276,7 @@ BrowserBox::draw(gcn::Graphics *graphics) int x = 0, y = 0; int wrappedLines = 0; + int link = 0; TrueTypeFont *font = static_cast<TrueTypeFont*>(getFont()); graphics->setColor(BLACK); @@ -311,57 +323,36 @@ BrowserBox::draw(gcn::Graphics *graphics) // Check for color change in format "##x", x = [L,P,0..9] if (row.find("##", start) == start && row.size() > start + 2) { - switch (row.at(start + 2)) + char c = row.at(start + 2); + if (c == '>') { - case 'L': // Link color - prevColor = selColor; - selColor = LINK; - break; - case 'P': // Previous color - selColor = prevColor; - break; - case '1': - prevColor = selColor; - selColor = RED; - break; - case '2': - prevColor = selColor; - selColor = GREEN; - break; - case '3': - prevColor = selColor; - selColor = BLUE; - break; - case '4': - prevColor = selColor; - selColor = ORANGE; - break; - case '5': - prevColor = selColor; - selColor = YELLOW; - break; - case '6': - prevColor = selColor; - selColor = PINK; - break; - case '7': - prevColor = selColor; - selColor = PURPLE; - break; - case '8': - prevColor = selColor; - selColor = GRAY; - break; - case '9': - prevColor = selColor; - selColor = BROWN; - break; - case '0': - default: + selColor = prevColor; + } + else + { + bool valid; + int rgb = textColor->getColor(c, valid); + if (c == '<') + { + const int size = mLinks[link].x2 - mLinks[link].x1; + mLinks[link].x1 = x; + mLinks[link].y1 = y; + mLinks[link].x2 = mLinks[link].x1 + size; + mLinks[link].y2 = y + font->getHeight(); + link++; prevColor = selColor; - selColor = BLACK; + } + if (valid) + { + selColor = rgb; + } } start += 3; + + if (start == row.size()) + { + break; + } } graphics->setColor(gcn::Color(selColor)); } diff --git a/src/gui/browserbox.h b/src/gui/browserbox.h index cb4c23ed..090c03e1 100644 --- a/src/gui/browserbox.h +++ b/src/gui/browserbox.h @@ -1,36 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_BROWSERBOX_H__ -#define __TMW_BROWSERBOX_H__ +#ifndef BROWSERBOX_H +#define BROWSERBOX_H -#include <iosfwd> +#include <list> #include <vector> #include <guichan/mouselistener.hpp> #include <guichan/widget.hpp> -#include "../guichanfwd.h" -#include "../main.h" - class LinkHandler; struct BROWSER_LINK { @@ -49,7 +46,7 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener /** * Constructor. */ - BrowserBox(unsigned int mode = AUTO_SIZE); + BrowserBox(unsigned int mode = AUTO_SIZE, bool opaque = true); /** * Destructor. @@ -124,7 +121,7 @@ class BrowserBox : public gcn::Widget, public gcn::MouseListener enum { BLACK = 0x000000, /**< Color 0 */ RED = 0xff0000, /**< Color 1 */ - GREEN = 0x1fa052, /**< Color 2 */ + GREEN = 0x009000, /**< Color 2 */ BLUE = 0x0000ff, /**< Color 3 */ ORANGE = 0xe0980e, /**< Color 4 */ YELLOW = 0xf1dc27, /**< Color 5 */ diff --git a/src/gui/button.cpp b/src/gui/button.cpp index 40ecd1b7..1d3a04e4 100644 --- a/src/gui/button.cpp +++ b/src/gui/button.cpp @@ -1,32 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - #include <guichan/exception.hpp> -#include <guichan/graphics.hpp> -#include <guichan/imagefont.hpp> +#include <guichan/font.hpp> #include "button.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -35,6 +33,7 @@ #include "../utils/dtor.h" int Button::mInstances = 0; +float Button::mAlpha = config.getValue("guialpha", 0.8); enum{ BUTTON_STANDARD, // 0 @@ -52,10 +51,10 @@ struct ButtonData }; static ButtonData const data[BUTTON_COUNT] = { - {"graphics/gui/button.png", 0, 0}, - {"graphics/gui/buttonhi.png", 9, 4}, - {"graphics/gui/buttonpress.png", 16, 19}, - {"graphics/gui/button_disabled.png", 25, 23} + { "graphics/gui/button.png", 0, 0 }, + { "graphics/gui/buttonhi.png", 9, 4 }, + { "graphics/gui/buttonpress.png", 16, 19 }, + { "graphics/gui/button_disabled.png", 25, 23 } }; ImageRect Button::button[BUTTON_COUNT]; @@ -100,6 +99,7 @@ void Button::init() data[x].gridX, data[y].gridY, data[x + 1].gridX - data[x].gridX + 1, data[y + 1].gridY - data[y].gridY + 1); + button[mode].grid[a]->setAlpha(mAlpha); a++; } } @@ -122,22 +122,29 @@ Button::~Button() } } -void -Button::draw(gcn::Graphics *graphics) +void Button::draw(gcn::Graphics *graphics) { int mode; - if (!isEnabled()) { + if (!isEnabled()) mode = BUTTON_DISABLED; - } - else if (isPressed() || mIsLogged) { + else if (isPressed() || mIsLogged) mode = BUTTON_PRESSED; - } - else if (mHasMouse || isFocused()) { + else if (mHasMouse || isFocused()) mode = BUTTON_HIGHLIGHTED; - } - else { + else mode = BUTTON_STANDARD; + + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + for (int a = 0; a < 9; a++) + { + button[BUTTON_DISABLED].grid[a]->setAlpha(mAlpha); + button[BUTTON_PRESSED].grid[a]->setAlpha(mAlpha); + button[BUTTON_HIGHLIGHTED].grid[a]->setAlpha(mAlpha); + button[BUTTON_STANDARD].grid[a]->setAlpha(mAlpha); + } } static_cast<Graphics*>(graphics)-> @@ -148,7 +155,8 @@ Button::draw(gcn::Graphics *graphics) int textX; int textY = getHeight() / 2 - getFont()->getHeight() / 2; - switch (getAlignment()) { + switch (getAlignment()) + { case gcn::Graphics::LEFT: textX = 4; break; @@ -164,10 +172,8 @@ Button::draw(gcn::Graphics *graphics) graphics->setFont(getFont()); - if (isPressed()) { + if (isPressed()) graphics->drawText(getCaption(), textX + 1, textY + 1, getAlignment()); - } - else { + else graphics->drawText(getCaption(), textX, textY, getAlignment()); - } } diff --git a/src/gui/button.h b/src/gui/button.h index f451416c..abaf5c43 100644 --- a/src/gui/button.h +++ b/src/gui/button.h @@ -1,28 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_BUTTON_H -#define _TMW_BUTTON_H - -#include <iosfwd> +#ifndef BUTTON_H +#define BUTTON_H #include <guichan/widgets/button.hpp> @@ -33,7 +31,8 @@ class ImageRect; * * \ingroup GUI */ -class Button : public gcn::Button { +class Button : public gcn::Button +{ public: /** * Default constructor. @@ -44,7 +43,7 @@ class Button : public gcn::Button { * Constructor, sets the caption of the button to the given string and * adds the given action listener. */ - Button(const std::string& caption, const std::string &actionEventId, + Button(const std::string &caption, const std::string &actionEventId, gcn::ActionListener *listener); /** @@ -55,7 +54,7 @@ class Button : public gcn::Button { /** * Draws the button. */ - void draw(gcn::Graphics* graphics); + void draw(gcn::Graphics *graphics); /** * Enable/Disable highlighting @@ -68,6 +67,7 @@ class Button : public gcn::Button { static ImageRect button[4]; /**< Button state graphics */ static int mInstances; /**< Number of button instances */ + static float mAlpha; bool mIsLogged; /**< Makes the button appear pressed all the time */ }; diff --git a/src/gui/buy.cpp b/src/gui/buy.cpp index cc2262ec..15a558a3 100644 --- a/src/gui/buy.cpp +++ b/src/gui/buy.cpp @@ -1,29 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * 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" @@ -32,12 +31,27 @@ #include "widgets/layout.h" #include "../npc.h" +#include "../units.h" + +#ifdef TMWSERV_SUPPORT #include "../net/gameserver/player.h" +#else +#include "../net/messageout.h" +#include "../net/ea/protocol.h" +#endif + #include "../utils/gettext.h" #include "../utils/strprintf.h" +#ifdef TMWSERV_SUPPORT BuyDialog::BuyDialog(): +#else +BuyDialog::BuyDialog(Network *network): +#endif Window(_("Buy")), +#ifndef TMWSERV_SUPPORT + mNetwork(network), +#endif mMoney(0), mAmountItems(0), mMaxItems(0) { setWindowName("Buy"); @@ -52,7 +66,8 @@ BuyDialog::BuyDialog(): mScrollArea = new ScrollArea(mShopItemList); mSlider = new Slider(1.0); mQuantityLabel = new gcn::Label("0"); - mMoneyLabel = new gcn::Label(strprintf(_("Price: %d GP / Total: %d GP"), 0, 0)); + mMoneyLabel = new gcn::Label(strprintf(_("Price: %s / Total: %s"), + "", "")); mIncreaseButton = new Button("+", "+", this); mDecreaseButton = new Button("-", "-", this); mBuyButton = new Button(_("Buy"), "buy", this); @@ -128,7 +143,7 @@ void BuyDialog::action(const gcn::ActionEvent &event) if (event.getId() == "quit") { setVisible(false); - current_npc = 0; + if (current_npc) current_npc->handleDeath(); return; } @@ -162,8 +177,16 @@ void BuyDialog::action(const gcn::ActionEvent &event) else if (event.getId() == "buy" && mAmountItems > 0 && mAmountItems <= mMaxItems) { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::tradeWithNPC (mShopItems->at(selectedItem)->getId(), mAmountItems); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_BUY_REQUEST); + outMsg.writeInt16(8); + outMsg.writeInt16(mAmountItems); + outMsg.writeInt16(mShopItems->at(selectedItem)->getId()); +#endif // Update money and adjust the max number of items that can be bought mMaxItems -= mAmountItems; @@ -230,5 +253,7 @@ void BuyDialog::updateButtonsAndLabels() // Update quantity and money labels mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems)); mMoneyLabel->setCaption - (strprintf(_("Price: %d GP / Total: %d GP"), price, mMoney - price)); + (strprintf(_("Price: %s / Total: %s"), + Units::formatCurrency(price).c_str(), + Units::formatCurrency(mMoney - price).c_str())); } diff --git a/src/gui/buy.h b/src/gui/buy.h index a80ffed7..5510ccc6 100644 --- a/src/gui/buy.h +++ b/src/gui/buy.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_BUY_H -#define _TMW_BUY_H +#ifndef BUY_H +#define BUY_H #include <guichan/actionlistener.hpp> #include <guichan/selectionlistener.hpp> @@ -29,6 +29,9 @@ #include "../guichanfwd.h" +#ifndef TMWSERV_SUPPORT +class Network; +#endif class ShopItems; class ShopListBox; class ListBox; @@ -39,7 +42,7 @@ class ListBox; * \ingroup Interface */ class BuyDialog : public Window, public gcn::ActionListener, - gcn::SelectionListener + public gcn::SelectionListener { public: /** @@ -47,7 +50,11 @@ class BuyDialog : public Window, public gcn::ActionListener, * * @see Window::Window */ +#ifdef TMWSERV_SUPPORT BuyDialog(); +#else + BuyDialog(Network *network); +#endif /** * Destructor @@ -95,6 +102,9 @@ class BuyDialog : public Window, public gcn::ActionListener, void updateButtonsAndLabels(); private: +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif gcn::Button *mBuyButton; gcn::Button *mQuitButton; gcn::Button *mIncreaseButton; diff --git a/src/gui/buysell.cpp b/src/gui/buysell.cpp index 42380882..2d39eac7 100644 --- a/src/gui/buysell.cpp +++ b/src/gui/buysell.cpp @@ -1,42 +1,43 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "buysell.h" - #include "button.h" +#include "buysell.h" #include "../npc.h" +#include "../utils/gettext.h" + BuySellDialog::BuySellDialog(): - Window("Shop") + Window(_("Shop")) { Button *buyButton = 0; - const char *buttonNames[] = { - "Buy", "Sell", "Cancel", 0 + static const char *buttonNames[] = { + N_("Buy"), N_("Sell"), N_("Cancel"), 0 }; int x = 10, y = 10; for (const char **curBtn = buttonNames; *curBtn; curBtn++) { - Button *btn = new Button(*curBtn, *curBtn, this); + Button *btn = new Button(gettext(*curBtn), *curBtn, this); if (!buyButton) buyButton = btn; // For focus request btn->setPosition(x, y); add(btn); @@ -57,7 +58,7 @@ void BuySellDialog::action(const gcn::ActionEvent &event) } else if (event.getId() == "Sell") { current_npc->sell(); } else if (event.getId() == "Cancel") { - current_npc = 0; + if (current_npc) current_npc->handleDeath(); } setVisible(false); } diff --git a/src/gui/buysell.h b/src/gui/buysell.h index 2391ed1c..e3cdc52a 100644 --- a/src/gui/buysell.h +++ b/src/gui/buysell.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_BUYSELL_H -#define _TMW_BUYSELL_H +#ifndef BUYSELL_H +#define BUYSELL_H #include <guichan/actionlistener.hpp> diff --git a/src/gui/char_select.cpp b/src/gui/char_select.cpp index f800c266..84270d10 100644 --- a/src/gui/char_select.cpp +++ b/src/gui/char_select.cpp @@ -1,57 +1,65 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "char_select.h" - #include <string> +#include <guichan/font.hpp> + #include <guichan/widgets/label.hpp> #include "button.h" -#include "radiobutton.h" +#include "char_select.h" #include "confirm_dialog.h" #include "ok_dialog.h" #include "playerbox.h" -#include "slider.h" #include "textfield.h" +#ifdef TMWSERV_SUPPORT +#include "radiobutton.h" +#include "slider.h" + #include "unregisterdialog.h" #include "changepassworddialog.h" #include "changeemaildialog.h" +#include "../logindata.h" + +#include "../net/accountserver/account.h" +#endif + #include "widgets/layout.h" #include "../game.h" #include "../localplayer.h" #include "../main.h" -#include "../logindata.h" +#include "../units.h" -#include "../net/accountserver/account.h" #include "../net/charserverhandler.h" #include "../net/messageout.h" +#include "../resources/colordb.h" + #include "../utils/gettext.h" #include "../utils/strprintf.h" -#include "../utils/tostring.h" -#include "../utils/trim.h" +#include "../utils/stringutils.h" // Defined in main.cpp, used here for setting the char create dialog extern CharServerHandler charServerHandler; @@ -78,24 +86,37 @@ CharDeleteConfirm::CharDeleteConfirm(CharSelectDialog *m): void CharDeleteConfirm::action(const gcn::ActionEvent &event) { //ConfirmDialog::action(event); - if (event.getId() == "yes") { + if (event.getId() == "yes") + { master->attemptCharDelete(); } ConfirmDialog::action(event); } +#ifdef TMWSERV_SUPPORT CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, LoginData *loginData): Window(_("Account and Character Management")), mCharInfo(charInfo), mCharSelected(false), mLoginData(loginData) +#else +CharSelectDialog::CharSelectDialog(Network *network, + LockedArray<LocalPlayer*> *charInfo, + Gender gender): + Window(_("Select Character")), mNetwork(network), + mCharInfo(charInfo), + mCharSelected(false), + mGender(gender) +#endif { - mSelectButton = new Button(_("Ok"), "ok", this); mCancelButton = new Button(_("Cancel"), "cancel", this); - mNewCharButton = new Button(_("New"), "new", this); - mDelCharButton = new Button(_("Delete"), "delete", this); mPreviousButton = new Button(_("Previous"), "previous", this); mNextButton = new Button(_("Next"), "next", this); + mNameLabel = new gcn::Label(strprintf(_("Name: %s"), "")); + mLevelLabel = new gcn::Label(strprintf(_("Level: %d"), 0)); +#ifdef TMWSERV_SUPPORT + mNewCharButton = new Button(_("New"), "new", this); + mDelCharButton = new Button(_("Delete"), "delete", this); mUnRegisterButton = new Button(_("Unregister"), "unregister", this); mChangePasswordButton = new Button(_("Change Password"), "change_password", this); mChangeEmailButton = new Button(_("Change Email Address"), "change_email", this); @@ -129,6 +150,42 @@ CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, place(0, 0, mSelectButton); place(1, 0, mCancelButton); reflowLayout(265, 0); +#else + mCharInfo->select(0); + LocalPlayer *pi = mCharInfo->getEntry(); + if (pi) + mMoney = Units::formatCurrency(pi->getMoney()); + // Control that shows the Player + mPlayerBox = new PlayerBox; + mPlayerBox->setWidth(74); + + mJobLevelLabel = new gcn::Label(strprintf(_("Job Level: %d"), 0)); + mMoneyLabel = new gcn::Label(strprintf(_("Money: %s"), mMoney.c_str())); + + const std::string tempString = getFont()->getWidth(_("New")) < + getFont()->getWidth(_("Delete")) ? + _("Delete") : _("New"); + + mNewDelCharButton = new Button(tempString, "newdel", this); + + ContainerPlacer place; + place = getPlacer(0, 0); + + place(0, 0, mPlayerBox, 1, 6).setPadding(3); + place(1, 0, mNewDelCharButton); + place(1, 1, mNameLabel, 5); + place(1, 2, mLevelLabel, 5); + place(1, 3, mJobLevelLabel, 5); + place(1, 4, mMoneyLabel, 5); + place.getCell().matchColWidth(1, 4); + place = getPlacer(0, 2); + place(0, 0, mPreviousButton); + place(1, 0, mNextButton); + place(4, 0, mCancelButton); + place(5, 0, mSelectButton); + + reflowLayout(250, 0); +#endif setLocationRelativeTo(getParent()); setVisible(true); @@ -138,25 +195,37 @@ CharSelectDialog::CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, void CharSelectDialog::action(const gcn::ActionEvent &event) { +#ifdef TMWSERV_SUPPORT // The pointers are set to NULL if there is no character stored if (event.getId() == "ok" && (mCharInfo->getEntry())) +#else + if (event.getId() == "ok" && n_character > 0) +#endif { // Start game +#ifdef TMWSERV_SUPPORT mNewCharButton->setEnabled(false); mDelCharButton->setEnabled(false); - mSelectButton->setEnabled(false); mUnRegisterButton->setEnabled(false); +#else + mNewDelCharButton->setEnabled(false); +#endif + mSelectButton->setEnabled(false); mPreviousButton->setEnabled(false); mNextButton->setEnabled(false); mCharSelected = true; - Net::AccountServer::Account::selectCharacter(mCharInfo->getPos()); - mCharInfo->lock(); + attemptCharSelect(); } else if (event.getId() == "cancel") { +#ifdef TMWSERV_SUPPORT mCharInfo->clear(); state = STATE_SWITCH_ACCOUNTSERVER_ATTEMPT; +#else + state = STATE_EXIT; +#endif } +#ifdef TMWSERV_SUPPORT else if (event.getId() == "new") { // TODO: Search the first free slot, and start CharCreateDialog @@ -177,14 +246,39 @@ void CharSelectDialog::action(const gcn::ActionEvent &event) new CharDeleteConfirm(this); } } +#else + else if (event.getId() == "newdel") + { + // Check for a character + if (mCharInfo->getEntry() && n_character <= MAX_SLOT + 1) + { + new CharDeleteConfirm(this); + } + else + { + // Start new character dialog + CharCreateDialog *charCreateDialog = + new CharCreateDialog(this, mCharInfo->getPos(), + mNetwork, mGender); + charServerHandler.setCharCreateDialog(charCreateDialog); + } + } +#endif else if (event.getId() == "previous") { mCharInfo->prev(); + LocalPlayer *pi = mCharInfo->getEntry(); + if (pi) + mMoney = Units::formatCurrency(pi->getMoney()); } else if (event.getId() == "next") { mCharInfo->next(); + LocalPlayer *pi = mCharInfo->getEntry(); + if (pi) + mMoney = Units::formatCurrency(pi->getMoney()); } +#ifdef TMWSERV_SUPPORT else if (event.getId() == "unregister") { new UnRegisterDialog(this, mLoginData); @@ -197,6 +291,7 @@ void CharSelectDialog::action(const gcn::ActionEvent &event) { new ChangeEmailDialog(this, mLoginData); } +#endif } void CharSelectDialog::updatePlayerInfo() @@ -205,22 +300,39 @@ void CharSelectDialog::updatePlayerInfo() if (pi) { - mNameLabel->setCaption(strprintf(_("Name: %s"), pi->getName().c_str())); + mNameLabel->setCaption(strprintf(_("Name: %s"), + pi->getName().c_str())); mLevelLabel->setCaption(strprintf(_("Level: %d"), pi->getLevel())); - mMoneyLabel->setCaption(strprintf(_("Money: %d"), pi->getMoney())); +#ifndef TMWSERV_SUPPORT + mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), + pi->mJobLevel)); +#endif + mMoneyLabel->setCaption(strprintf(_("Money: %s"), mMoney.c_str())); if (!mCharSelected) { +#ifdef TMWSERV_SUPPORT mNewCharButton->setEnabled(false); mDelCharButton->setEnabled(true); +#else + mNewDelCharButton->setCaption(_("Delete")); +#endif mSelectButton->setEnabled(true); } } - else { + else + { mNameLabel->setCaption(strprintf(_("Name: %s"), "")); mLevelLabel->setCaption(strprintf(_("Level: %d"), 0)); - mMoneyLabel->setCaption(strprintf(_("Money: %d"), 0)); +#ifndef TMWSERV_SUPPORT + mJobLevelLabel->setCaption(strprintf(_("Job Level: %d"), 0)); +#endif + mMoneyLabel->setCaption(strprintf(_("Money: %s"), "")); +#ifdef TMWSERV_SUPPORT mNewCharButton->setEnabled(true); mDelCharButton->setEnabled(false); +#else + mNewDelCharButton->setCaption(_("New")); +#endif mSelectButton->setEnabled(false); } @@ -229,7 +341,28 @@ void CharSelectDialog::updatePlayerInfo() void CharSelectDialog::attemptCharDelete() { +#ifdef TMWSERV_SUPPORT Net::AccountServer::Account::deleteCharacter(mCharInfo->getPos()); +#else + // Request character deletion + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0068); + outMsg.writeInt32(mCharInfo->getEntry()->mCharId); + outMsg.writeString("a@a.com", 40); +#endif + mCharInfo->lock(); +} + +void CharSelectDialog::attemptCharSelect() +{ +#ifdef TMWSERV_SUPPORT + Net::AccountServer::Account::selectCharacter(mCharInfo->getPos()); +#else + // Request character selection + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0066); + outMsg.writeInt8(mCharInfo->getPos()); +#endif mCharInfo->lock(); } @@ -246,7 +379,8 @@ bool CharSelectDialog::selectByName(const std::string &name) unsigned int oldPos = mCharInfo->getPos(); mCharInfo->select(0); - do { + do + { LocalPlayer *player = mCharInfo->getEntry(); if (player && player->getName() == name) @@ -260,14 +394,29 @@ bool CharSelectDialog::selectByName(const std::string &name) return false; } - +#ifdef TMWSERV_SUPPORT CharCreateDialog::CharCreateDialog(Window *parent, int slot): - Window(_("Create Character"), true, parent), mSlot(slot) +#else +CharCreateDialog::CharCreateDialog(Window *parent, int slot, Network *network, + Gender gender): +#endif + Window(_("Create Character"), true, parent), +#ifndef TMWSERV_SUPPORT + mNetwork(network), +#endif + mSlot(slot) { mPlayer = new Player(0, 0, NULL); - mPlayer->setHairStyle(rand() % Being::getHairStylesNr(), - rand() % Being::getHairColorsNr()); +#ifdef TMWSERV_SUPPORT mPlayer->setGender(GENDER_MALE); +#else + mPlayer->setGender(gender); +#endif + + int numberOfHairColors = ColorDB::size(); + + mPlayer->setHairStyle(rand() % mPlayer->getNumOfHairstyles(), + rand() % numberOfHairColors); mNameField = new TextField(""); mNameLabel = new gcn::Label(_("Name:")); @@ -279,19 +428,34 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): mHairStyleLabel = new gcn::Label(_("Hair Style:")); mCreateButton = new Button(_("Create"), "create", this); mCancelButton = new Button(_("Cancel"), "cancel", this); - +#ifdef TMWSERV_SUPPORT mMale = new RadioButton(_("Male"), "gender"); mFemale = new RadioButton(_("Female"), "gender"); + // Default to a Male character + mMale->setSelected(true); + + mMale->setActionEventId("gender"); + mFemale->setActionEventId("gender"); + + mMale->addActionListener(this); + mFemale->addActionListener(this); +#endif mPlayerBox = new PlayerBox(mPlayer); + mPlayerBox->setWidth(74); + + mNameField->setActionEventId("create"); + mNameField->addActionListener(this); + +#ifdef TMWSERV_SUPPORT mAttributeLabel[0] = new gcn::Label(_("Strength:")); mAttributeLabel[1] = new gcn::Label(_("Agility:")); mAttributeLabel[2] = new gcn::Label(_("Dexterity:")); mAttributeLabel[3] = new gcn::Label(_("Vitality:")); mAttributeLabel[4] = new gcn::Label(_("Intelligence:")); mAttributeLabel[5] = new gcn::Label(_("Willpower:")); - for (int i=0; i<6; i++) + for (int i = 0; i < 6; i++) { mAttributeLabel[i]->setWidth(70); mAttributeSlider[i] = new Slider(1, 20); @@ -300,8 +464,6 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): mAttributesLeft = new gcn::Label(strprintf(_("Please distribute %d points"), 99)); - mNameField->setActionEventId("create"); - int w = 200; int h = 330; setContentSize(w, h); @@ -334,19 +496,8 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): mCancelButton->getX() - 5 - mCreateButton->getWidth(), h - 5 - mCancelButton->getHeight()); - mNameField->addActionListener(this); - - mMale->setPosition( 30, 120 ); - mFemale->setPosition( 100, 120 ); - - // Default to a Male character - mMale->setSelected(true); - - mMale->setActionEventId("gender"); - mFemale->setActionEventId("gender"); - - mMale->addActionListener(this); - mFemale->addActionListener(this); + mMale->setPosition(30, 120); + mFemale->setPosition(100, 120); add(mPlayerBox); add(mNameField); @@ -357,7 +508,7 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): add(mNextHairStyleButton); add(mPrevHairStyleButton); add(mHairStyleLabel); - for (int i=0; i<6; i++) + for (int i = 0; i < 6; i++) { add(mAttributeSlider[i]); add(mAttributeValue[i]); @@ -370,6 +521,28 @@ CharCreateDialog::CharCreateDialog(Window *parent, int slot): add(mMale); add(mFemale); +#else + + ContainerPlacer place; + place = getPlacer(0, 0); + + place(0, 0, mNameLabel, 1); + place(1, 0, mNameField, 6); + place(0, 1, mHairStyleLabel, 1); + place(1, 1, mPrevHairStyleButton); + place(2, 1, mPlayerBox, 1, 8).setPadding(3); + place(3, 1, mNextHairStyleButton); + place(0, 2, mHairColorLabel, 1); + place(1, 2, mPrevHairColorButton); + place(3, 2, mNextHairColorButton); + place.getCell().matchColWidth(0, 2); + place = getPlacer(0, 2); + place(4, 0, mCancelButton); + place(5, 0, mCreateButton); + + reflowLayout(225, 0); +#endif + setLocationRelativeTo(getParent()); setVisible(true); mNameField->requestFocus(); @@ -383,14 +556,16 @@ CharCreateDialog::~CharCreateDialog() charServerHandler.setCharCreateDialog(0); } -void -CharCreateDialog::action(const gcn::ActionEvent &event) +void CharCreateDialog::action(const gcn::ActionEvent &event) { - if (event.getId() == "create") { - if (getName().length() >= 4) { + int numberOfColors = ColorDB::size(); + if (event.getId() == "create") + { + if (getName().length() >= 4) + { // Attempt to create the character mCreateButton->setEnabled(false); - +#ifdef TMWSERV_SUPPORT unsigned int genderSelected; if (mMale->isSelected()) { genderSelected = GENDER_MALE; @@ -410,26 +585,34 @@ CharCreateDialog::action(const gcn::ActionEvent &event) (int) mAttributeSlider[4]->getValue(), // INT (int) mAttributeSlider[5]->getValue() // WILL ); +#else + attemptCharCreate(); +#endif } - else { - new OkDialog(_("Error"),_("Your name needs to be at least 4 characters."), this); + else + { + new OkDialog(_("Error"), + _("Your name needs to be at least 4 characters."), + this); } } - else if (event.getId() == "cancel") { + else if (event.getId() == "cancel") scheduleDelete(); - } - else if (event.getId() == "nextcolor") { - mPlayer->setHairStyle(-1, mPlayer->getHairColor() + 1); - } - else if (event.getId() == "prevcolor") { - mPlayer->setHairStyle(-1, mPlayer->getHairColor() + Being::getHairColorsNr() - 1); - } - else if (event.getId() == "nextstyle") { - mPlayer->setHairStyle(mPlayer->getHairStyle() + 1, -1); - } - else if (event.getId() == "prevstyle") { - mPlayer->setHairStyle(mPlayer->getHairStyle() + Being::getHairStylesNr() - 1, -1); - } + else if (event.getId() == "nextcolor") + mPlayer->setHairStyle(mPlayer->getHairStyle(), + (mPlayer->getHairColor() + 1) % numberOfColors); + else if (event.getId() == "prevcolor") + mPlayer->setHairStyle(mPlayer->getHairStyle(), + (mPlayer->getHairColor() + numberOfColors - 1) % + numberOfColors); + else if (event.getId() == "nextstyle") + mPlayer->setHairStyle(mPlayer->getHairStyle() + 1, + mPlayer->getHairColor()); + else if (event.getId() == "prevstyle") + mPlayer->setHairStyle(mPlayer->getHairStyle() + + mPlayer->getNumOfHairstyles() - 1, + mPlayer->getHairColor()); +#ifdef TMWSERV_SUPPORT else if (event.getId() == "statslider") { UpdateSliders(); } @@ -440,16 +623,17 @@ CharCreateDialog::action(const gcn::ActionEvent &event) mPlayer->setGender(GENDER_FEMALE); } } +#endif } -std::string -CharCreateDialog::getName() +std::string CharCreateDialog::getName() { std::string name = mNameField->getText(); trim(name); return name; } +#ifdef TMWSERV_SUPPORT void CharCreateDialog::UpdateSliders() { for (int i = 0; i < 6; i++) @@ -482,13 +666,14 @@ void CharCreateDialog::UpdateSliders() mAttributesLeft->adjustSize(); } +#endif -void -CharCreateDialog::unlock() +void CharCreateDialog::unlock() { mCreateButton->setEnabled(true); } +#ifdef TMWSERV_SUPPORT int CharCreateDialog::getDistributedPoints() { int points = 0; @@ -499,3 +684,23 @@ int CharCreateDialog::getDistributedPoints() } return points; } +#endif + +#ifndef TMWSERV_SUPPORT +void CharCreateDialog::attemptCharCreate() +{ + // Send character infos + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0067); + outMsg.writeString(getName(), 24); + outMsg.writeInt8(5); + outMsg.writeInt8(5); + outMsg.writeInt8(5); + outMsg.writeInt8(5); + outMsg.writeInt8(5); + outMsg.writeInt8(5); + outMsg.writeInt8(mSlot); + outMsg.writeInt16(mPlayer->getHairColor()); + outMsg.writeInt16(mPlayer->getHairStyle()); +} +#endif diff --git a/src/gui/char_select.h b/src/gui/char_select.h index ed03cedd..0ff1d18f 100644 --- a/src/gui/char_select.h +++ b/src/gui/char_select.h @@ -1,38 +1,43 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _CHAR_SELECT_H #define _CHAR_SELECT_H +#include <guichan/actionlistener.hpp> + #include "window.h" +#include "../being.h" #include "../guichanfwd.h" #include "../lockedarray.h" -#include <guichan/actionlistener.hpp> - +#ifdef TMWSERV_SUPPORT #include "../logindata.h" +#else +class Network; +#endif -class Player; class LocalPlayer; +class Player; class PlayerBox; /** @@ -47,8 +52,14 @@ class CharSelectDialog : public Window, public gcn::ActionListener /** * Constructor. */ +#ifdef TMWSERV_SUPPORT CharSelectDialog(LockedArray<LocalPlayer*> *charInfo, LoginData *loginData); +#else + CharSelectDialog(Network *network, + LockedArray<LocalPlayer*> *charInfo, + Gender gender); +#endif void action(const gcn::ActionEvent &event); @@ -59,28 +70,40 @@ class CharSelectDialog : public Window, public gcn::ActionListener bool selectByName(const std::string &name); private: +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif LockedArray<LocalPlayer*> *mCharInfo; gcn::Button *mSelectButton; gcn::Button *mCancelButton; - gcn::Button *mNewCharButton; - gcn::Button *mDelCharButton; gcn::Button *mPreviousButton; gcn::Button *mNextButton; - gcn::Button *mUnRegisterButton; - gcn::Button *mChangePasswordButton; - gcn::Button *mChangeEmailButton; - gcn::Label *mAccountNameLabel; gcn::Label *mNameLabel; gcn::Label *mLevelLabel; gcn::Label *mMoneyLabel; + std::string mMoney; PlayerBox *mPlayerBox; bool mCharSelected; +#ifdef TMWSERV_SUPPORT + gcn::Button *mNewCharButton; + gcn::Button *mDelCharButton; + gcn::Button *mUnRegisterButton; + gcn::Button *mChangePasswordButton; + gcn::Button *mChangeEmailButton; + gcn::Label *mAccountNameLabel; + LoginData *mLoginData; +#else + gcn::Button *mNewDelCharButton; + gcn::Label *mJobLevelLabel; + Gender mGender; +#endif + /** * Communicate character deletion to the server. */ @@ -103,7 +126,12 @@ class CharCreateDialog : public Window, public gcn::ActionListener /** * Constructor. */ +#ifdef TMWSERV_SUPPORT CharCreateDialog(Window *parent, int slot); +#else + CharCreateDialog(Window *parent, int slot, Network *network, + Gender gender); +#endif /** * Destructor. @@ -118,9 +146,11 @@ class CharCreateDialog : public Window, public gcn::ActionListener void unlock(); private: +#ifdef TMWSERV_SUPPORT int getDistributedPoints(); void UpdateSliders(); +#endif /** * Returns the name of the character to create. @@ -132,6 +162,9 @@ class CharCreateDialog : public Window, public gcn::ActionListener */ void attemptCharCreate(); +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif gcn::TextField *mNameField; gcn::Label *mNameLabel; gcn::Button *mNextHairColorButton; @@ -141,6 +174,7 @@ class CharCreateDialog : public Window, public gcn::ActionListener gcn::Button *mPrevHairStyleButton; gcn::Label *mHairStyleLabel; +#ifdef TMWSERV_SUPPORT gcn::RadioButton *mMale; gcn::RadioButton *mFemale; @@ -149,6 +183,10 @@ class CharCreateDialog : public Window, public gcn::ActionListener gcn::Label *mAttributeValue[6]; gcn::Label *mAttributesLeft; + static const int mMaxPoints = 60; + int mUsedPoints; +#endif + gcn::Button *mCreateButton; gcn::Button *mCancelButton; @@ -156,9 +194,6 @@ class CharCreateDialog : public Window, public gcn::ActionListener PlayerBox *mPlayerBox; int mSlot; - - static const int mMaxPoints = 60; - int mUsedPoints; }; #endif diff --git a/src/gui/char_server.cpp b/src/gui/char_server.cpp new file mode 100644 index 00000000..fa03bdc2 --- /dev/null +++ b/src/gui/char_server.cpp @@ -0,0 +1,122 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "button.h" +#include "char_server.h" +#include "listbox.h" +#include "scrollarea.h" + +#include "../logindata.h" +#include "../main.h" +#include "../serverinfo.h" + +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +extern SERVER_INFO **server_info; + +/** + * The list model for the server list. + */ +class ServerListModel : public gcn::ListModel +{ + public: + virtual ~ServerListModel() {}; + + int getNumberOfElements(); + std::string getElementAt(int i); +}; + +ServerSelectDialog::ServerSelectDialog(LoginData *loginData, int nextState): + Window(_("Select Server")), + mLoginData(loginData), + mNextState(nextState) +{ + mServerListModel = new ServerListModel; + mServerList = new ListBox(mServerListModel); + ScrollArea *mScrollArea = new ScrollArea(mServerList); + mOkButton = new Button(_("OK"), "ok", this); + Button *mCancelButton = new Button(_("Cancel"), "cancel", this); + + setContentSize(200, 100); + + mCancelButton->setPosition( + 200 - mCancelButton->getWidth() - 5, + 100 - mCancelButton->getHeight() - 5); + mOkButton->setPosition( + mCancelButton->getX() - mOkButton->getWidth() - 5, + 100 - mOkButton->getHeight() - 5); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mScrollArea->setDimension(gcn::Rectangle( + 5, 5, 200 - 2 * 5, + 100 - 3 * 5 - mCancelButton->getHeight() - + mScrollArea->getFrameSize())); + + mServerList->setActionEventId("ok"); + + //mServerList->addActionListener(this); + + add(mScrollArea); + add(mOkButton); + add(mCancelButton); + + if (n_server == 0) + // Disable Ok button + mOkButton->setEnabled(false); + else + // Select first server + mServerList->setSelected(1); + + setLocationRelativeTo(getParent()); + setVisible(true); + mOkButton->requestFocus(); +} + +ServerSelectDialog::~ServerSelectDialog() +{ + delete mServerListModel; +} + +void ServerSelectDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "ok") + { + mOkButton->setEnabled(false); + const SERVER_INFO *si = server_info[mServerList->getSelected()]; + mLoginData->hostname = ipToString(si->address); + mLoginData->port = si->port; + mLoginData->updateHost = si->updateHost; + state = mNextState; + } + else if (event.getId() == "cancel") + state = STATE_LOGIN; +} + +int ServerListModel::getNumberOfElements() +{ + return n_server; +} + +std::string ServerListModel::getElementAt(int i) +{ + const SERVER_INFO *si = server_info[i]; + return si->name + " (" + toString(si->online_users) + ")"; +} diff --git a/src/gui/char_server.h b/src/gui/char_server.h new file mode 100644 index 00000000..49a5b47b --- /dev/null +++ b/src/gui/char_server.h @@ -0,0 +1,65 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CHAR_SEL_SERVER_H +#define _CHAR_SEL_SERVER_H + +#include <guichan/actionlistener.hpp> +#include <guichan/listmodel.hpp> + +#include "window.h" + +class LoginData; +class ServerListModel; + +/** + * The server select dialog. + * + * \ingroup Interface + */ +class ServerSelectDialog : public Window, public gcn::ActionListener { + public: + /** + * Constructor + * + * @see Window::Window + */ + ServerSelectDialog(LoginData *loginData, int nextState); + + /** + * Destructor. + */ + ~ServerSelectDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + private: + LoginData *mLoginData; + ServerListModel *mServerListModel; + gcn::ListBox *mServerList; + gcn::Button *mOkButton; + int mNextState; +}; + +#endif diff --git a/src/gui/chat.cpp b/src/gui/chat.cpp index 3d1b5643..37250091 100644 --- a/src/gui/chat.cpp +++ b/src/gui/chat.cpp @@ -1,68 +1,83 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> -#include <sstream> - #include <guichan/focushandler.hpp> -#include "chat.h" - #include "browserbox.h" +#include "chat.h" #include "chatinput.h" #include "itemlinkhandler.h" +#include "recorder.h" #include "scrollarea.h" #include "sdlinput.h" #include "windowcontainer.h" +#include "widgets/layout.h" #include "widgets/tab.h" #include "widgets/tabbedarea.h" +#include "../beingmanager.h" +#ifdef TMWSERV_SUPPORT #include "../commandhandler.h" +#endif #include "../channelmanager.h" #include "../channel.h" #include "../configuration.h" #include "../game.h" #include "../localplayer.h" +#ifdef TMWSERV_SUPPORT #include "../net/chatserver/chatserver.h" #include "../net/gameserver/player.h" +#else +#include "../party.h" +#include "../net/messageout.h" +#include "../net/ea/protocol.h" +#endif #include "../resources/iteminfo.h" #include "../resources/itemdb.h" #include "../utils/dtor.h" -#include "../utils/trim.h" -#include "../utils/tostring.h" +#include "../utils/gettext.h" +#include "../utils/strprintf.h" +#include "../utils/stringutils.h" +#ifdef TMWSERV_SUPPORT ChatWindow::ChatWindow(): Window("Chat"), +#else +ChatWindow::ChatWindow(Network * network): + Window(""), mNetwork(network), +#endif mTmpVisible(false) { setWindowName("Chat"); + setResizable(true); setDefaultSize(0, windowContainer->getHeight() - 123, 600, 123); - setOpaque(false); + setMinWidth(150); + setMinHeight(90); - mItemLinkHandler = new ItemLinkHandler(); + mItemLinkHandler = new ItemLinkHandler; mChatInput = new ChatInput; mChatInput->setActionEventId("chatinput"); @@ -74,47 +89,51 @@ ChatWindow::ChatWindow(): textOutput->setLinkHandler(mItemLinkHandler); ScrollArea *scrollArea = new ScrollArea(textOutput); - scrollArea->setPosition( - scrollArea->getFrameSize(), scrollArea->getFrameSize()); - scrollArea->setScrollPolicy( - gcn::ScrollArea::SHOW_NEVER, gcn::ScrollArea::SHOW_ALWAYS); + scrollArea->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, + gcn::ScrollArea::SHOW_ALWAYS); scrollArea->setScrollAmount(0, 1); scrollArea->setOpaque(false); mChatTabs = new TabbedArea(); mChatTabs->addTab("General", scrollArea); - mChatTabs->setPosition(mChatTabs->getFrameSize(), - mChatTabs->getFrameSize()); - mChannels.insert( - std::make_pair("General", ChatArea(textOutput, scrollArea))); + place(0, 0, mChatTabs, 5, 5).setPadding(0); + place(0, 5, mChatInput, 5).setPadding(1); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + layout.setMargin(2); - add(mChatTabs); - add(mChatInput); + loadWindowState(); // Add key listener to chat input to be able to respond to up/down mChatInput->addKeyListener(this); mCurHist = mHistory.end(); - loadWindowState(); +#ifdef EATHENA_SUPPORT + // Read the party prefix + std::string partyPrefix = config.getValue("PartyPrefix", "$"); + mPartyPrefix = (partyPrefix.empty() ? '$' : partyPrefix.at(0)); + mReturnToggles = config.getValue("ReturnToggles", "0") == "1"; + mRecorder = new Recorder(this); + mParty = new Party(this, mNetwork); + + // If the player had @assert on in the last session, ask the server to + // run the @assert command for the player again. Convenience for GMs. + if (config.getValue(player_node->getName() + "GMassert", 0)) + chatSend(player_node->getName(), "@assert"); +#endif } ChatWindow::~ChatWindow() { - delete mChatInput; - delete mChatTabs; -} - -const std::string &ChatWindow::getFocused() const -{ - return mChatTabs->getSelectedTab()->getCaption(); -} - -void ChatWindow::clearTab(const std::string &tab) -{ - ChannelMap::const_iterator chan = mChannels.find(tab); - if (chan != mChannels.end()) - chan->second.browser->clearRows(); +#ifdef EATHENA_SUPPORT + char partyPrefix[2] = "."; + *partyPrefix = mPartyPrefix; + config.setValue("PartyPrefix", partyPrefix); + config.setValue("ReturnToggles", mReturnToggles ? "1" : "0"); + delete mRecorder; +#endif } void ChatWindow::widgetResized(const gcn::Event &event) @@ -159,7 +178,8 @@ void ChatWindow::logic() } } -void ChatWindow::chatLog(std::string line, int own, std::string channelName) +void ChatWindow::chatLog(std::string line, int own, std::string channelName, + bool ignoreRecord) { if(channelName.empty()) channelName = getFocused(); @@ -174,60 +194,122 @@ void ChatWindow::chatLog(std::string line, int own, std::string channelName) // Trim whitespace trim(line); + if (line.empty()) + return; + CHATLOG tmp; - tmp.own = own; + tmp.own = own; tmp.nick = ""; tmp.text = line; std::string::size_type pos = line.find(" : "); - if (pos != std::string::npos) { + if (pos != std::string::npos) + { tmp.nick = line.substr(0, pos); tmp.text = line.substr(pos + 3); } + else + { + // Fix the owner of welcome message. + if (line.substr(0, 7) == "Welcome") + { + own = BY_SERVER; + } + } + + // *implements actions in a backwards compatible way* + if (own == BY_PLAYER && + tmp.text.at(0) == '*' && + tmp.text.at(tmp.text.length()-1) == '*') + { + tmp.text[0] = ' '; + tmp.text.erase(tmp.text.length() - 1); + own = ACT_IS; + } - std::string lineColor = "##0"; // Equiv. to BrowserBox::BLACK - switch (own) { + std::string lineColor = "##C"; + switch (own) + { case BY_GM: - tmp.nick += "Global announcement: "; - lineColor = "##1"; // Equiv. to BrowserBox::RED + if (tmp.nick.empty()) + { + tmp.nick = std::string(_("Global announcement:")); + tmp.nick += " "; + lineColor = "##G"; + } + else + { + tmp.nick = strprintf(_("Global announcement from %s:"), + tmp.nick.c_str()); + tmp.nick += " "; + lineColor = "##1"; // Equiv. to BrowserBox::RED + } break; case BY_PLAYER: - tmp.nick += ": "; - lineColor = "##3"; // Equiv. to BrowserBox::BLUE + tmp.nick += CAT_NORMAL; + lineColor = "##Y"; break; case BY_OTHER: - tmp.nick += ": "; - lineColor = "##0"; // Equiv. to BrowserBox::BLACK + tmp.nick += CAT_NORMAL; + lineColor = "##C"; break; case BY_SERVER: - tmp.nick = "Server: "; + tmp.nick = _("Server:"); + tmp.nick += " "; tmp.text = line; - lineColor = "##7"; // Equiv. to BrowserBox::PINK + lineColor = "##S"; break; case BY_CHANNEL: tmp.nick = ""; + // TODO: Use a predefined color lineColor = "##2"; // Equiv. to BrowserBox::GREEN break; +#ifdef EATHENA_SUPPORT + case BY_PARTY: + tmp.nick += CAT_NORMAL; + lineColor = "##P"; + break; +#endif + case ACT_WHISPER: + tmp.nick = strprintf(_("%s whispers:"), tmp.nick.c_str()); + tmp.nick += " "; + lineColor = "##W"; + break; + case ACT_IS: + tmp.nick += CAT_IS; + lineColor = "##I"; + break; case BY_LOGGER: tmp.nick = ""; tmp.text = line; - lineColor = "##8"; // Equiv. to BrowserBox::GREY + lineColor = "##L"; break; } + if (tmp.nick == ": ") + { + tmp.nick = ""; + lineColor = "##S"; + } + +#ifdef EATHENA_SUPPORT + if (tmp.nick.empty() && tmp.text.substr(0, 17) == "Visible GM status") + { + player_node->setGM(); + } +#endif + // Get the current system time time_t t; time(&t); // Format the time string properly std::stringstream timeStr; - timeStr << "[" - << ((((t / 60) / 60) % 24 < 10) ? "0" : "") - << (int)(((t / 60) / 60) % 24) - << ":" - << (((t / 60) % 60 < 10) ? "0" : "") - << (int)((t / 60) % 60) - << "] "; + timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") + << (int) (((t / 60) / 60) % 24) + << ":" << (((t / 60) % 60 < 10) ? "0" : "") + << (int) ((t / 60) % 60) + << "] "; line = lineColor + timeStr.str() + tmp.nick + tmp.text; @@ -245,6 +327,26 @@ void ChatWindow::chatLog(std::string line, int own, std::string channelName) } scroll->logic(); + mRecorder->record(line.substr(3)); +} + +#ifdef EATHENA_SUPPORT +void ChatWindow::chatLog(CHATSKILL act) +{ + chatLog(const_msg(act), BY_SERVER); +} +#endif + +const std::string &ChatWindow::getFocused() const +{ + return mChatTabs->getSelectedTab()->getCaption(); +} + +void ChatWindow::clearTab(const std::string &tab) +{ + ChannelMap::const_iterator chan = mChannels.find(tab); + if (chan != mChannels.end()) + chan->second.browser->clearRows(); } void ChatWindow::action(const gcn::ActionEvent &event) @@ -253,29 +355,36 @@ void ChatWindow::action(const gcn::ActionEvent &event) { std::string message = mChatInput->getText(); - if (!message.empty()) { + if (!message.empty()) + { // If message different from previous, put it in the history - if (mHistory.empty() || message != mHistory.back()) { + if (mHistory.empty() || message != mHistory.back()) + { mHistory.push_back(message); } - // Reset history iterator mCurHist = mHistory.end(); // Send the message to the server +#ifdef TMWSERV_SUPPORT chatSend(message); +#else + chatSend(player_node->getName(), message); +#endif // Clear the text from the chat input mChatInput->setText(""); } - // Remove focus and hide input - mFocusHandler->focusNone(); + if (message.empty() || !mReturnToggles) + { + // Remove focus and hide input + mFocusHandler->focusNone(); - // If the chatWindow is shown up because you want to send a message - // It should hide now - if (mTmpVisible) { - setVisible(false); + // If the chatWindow is shown up because you want to send a message + // It should hide now + if (mTmpVisible) + setVisible(false); } } } @@ -305,6 +414,56 @@ bool ChatWindow::isInputFocused() return mChatInput->isFocused(); } +void ChatWindow::whisper(const std::string &nick, std::string msg) +{ + 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); + } + } + + trim(msg); + + std::string playerName = player_node->getName(); + std::string tempNick = recvnick; + + toLower(playerName); + toLower(tempNick); + + if (tempNick.compare(playerName) == 0 || msg.empty()) + return; + + // TODO: Implement whispering on tmwserv +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_CHAT_WHISPER); + outMsg.writeInt16(msg.length() + 28); + outMsg.writeString(recvnick, 24); + outMsg.writeString(msg, msg.length()); + + chatLog(strprintf(_("Whispering to %s: %s"), + recvnick.c_str(), msg.c_str()), + BY_PLAYER); +#endif +} + +#ifdef TMWSERV_SUPPORT + void ChatWindow::chatSend(std::string &msg) { if (msg.empty()) return; @@ -415,6 +574,387 @@ void ChatWindow::sendToChannel(short channelId, } } +#else + +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 */ + + trim(msg); + + if (msg.compare("") == 0) + return; + + // Send party message + if (msg.at(0) == mPartyPrefix) + { + msg.erase(0, 1); + std::size_t length = msg.length() + 1; + + if (length == 0) + { + chatLog(_("Trying to send a blank party message."), BY_SERVER); + return; + } + MessageOut outMsg(mNetwork); + + outMsg.writeInt16(CMSG_PARTY_MESSAGE); + outMsg.writeInt16(length + 4); + outMsg.writeString(msg, length); + return; + } + + // Check for item link + std::string::size_type start = msg.find('['); + while (start != std::string::npos && msg[start+1] != '@') + { + std::string::size_type end = msg.find(']', start); + if (start+1 != end && end != std::string::npos) + { + // Catch multiple embeds and ignore them + // so it doesn't crash the client. + while ((msg.find('[', start + 1) != std::string::npos) && + (msg.find('[', start + 1) < end)) + { + start = msg.find('[', start + 1); + } + + std::string temp = msg.substr(start + 1, end - start - 1); + + toLower(trim(temp)); + + const ItemInfo itemInfo = ItemDB::get(temp); + if (itemInfo.getName() != _("Unknown item")) + { + msg.insert(end, "@@"); + msg.insert(start+1, "|"); + msg.insert(start+1, toString(itemInfo.getId())); + msg.insert(start+1, "@@"); + } + } + start = msg.find('[', start + 1); + } + + // Prepare ordinary message + if (msg.substr(0, 1) != "/") + { + msg = nick + " : " + msg; + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_CHAT_MESSAGE); + // 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); + } + + if (command == "announce") + { + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0099); + outMsg.writeInt16(msg.length() + 4); + outMsg.writeString(msg, msg.length()); + } + else if (command == "help") + { + trim(msg); + std::size_t space = msg.find(" "); + std::string msg1; + + if (space == std::string::npos) + { + msg1 = ""; + } + else + { + msg1 = msg.substr(space + 1, msg.length()); + msg = msg.substr(0, space); + } + + if (!msg.empty() && msg.at(0) == '/') + { + msg.erase(0, 1); + } + + trim(msg1); + help(msg, msg1); + } + 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 (command == "who") + { + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x00c1); + } + else if (command == "clear") + clearTab(getFocused()); + else if (command == "whisper" || command == "msg" || command == "w") + whisper(nick, msg); + else if (command == "record") + mRecorder->changeRecordingStatus(msg); + else if (command == "toggle") + { + if (msg.empty()) + { + chatLog(mReturnToggles ? _("Return toggles chat.") + : _("Message closes chat."), BY_SERVER); + return; + } + + msg = msg.substr(0, 1); + + if (msg == "1" || + msg == "y" || msg == "Y" || + msg == "t" || msg == "T") + { + chatLog(_("Return now toggles chat."), BY_SERVER); + mReturnToggles = true; + return; + } + else if (msg == "0" || + msg == "n" || msg == "N" || + msg == "f" || msg == "F") + { + chatLog(_("Message now closes chat."), BY_SERVER); + mReturnToggles = false; + return; + } + else + chatLog(_("Options to /toggle are \"yes\", \"no\", \"true\", " + "\"false\", \"1\", \"0\"."), BY_SERVER); + } + else if (command == "party") + { + if (msg.empty()) + { + chatLog(_("Unknown party command... Type \"/help\" party for more " + "information."), BY_SERVER); + return; + } + + const std::string::size_type space = msg.find(" "); + std::string rest = (space == std::string::npos ? "" + : msg.substr(space + 1, msg.length())); + + if (!rest.empty()) + { + msg = msg.substr(0, space); + trim(msg); + } + + party(msg, rest); + return; + } + else if (command == "cast") + { + /* + * This will eventually be replaced by a GUI, so + * we don't need to get too sophisticated + */ + MessageOut outMsg(mNetwork); + if (msg == "heal") + { + outMsg.writeInt16(0x03f3); + outMsg.writeInt16(0x01); + outMsg.writeInt32(0); + outMsg.writeInt8(0); + outMsg.writeInt8(0); + outMsg.writeString("", 24); + } + else if (msg == "gather") + { + outMsg.writeInt16(0x03f3); + outMsg.writeInt16(0x02); + outMsg.writeInt32(0); + outMsg.writeInt8(0); + outMsg.writeInt8(0); + outMsg.writeString("", 24); + } + else + chatLog(_("No such spell!"), BY_SERVER); + } + else if (command == "present") + { + Beings & beings = beingManager->getAll(); + std::string response = ""; + + for (BeingIterator bi = beings.begin(), be = beings.end(); + bi != be; ++bi) + { + if ((*bi)->getType() == Being::PLAYER) + { + if (!response.empty()) + { + response += ", "; + } + response += (*bi)->getName(); + } + } + + if (mRecorder->isRecording()) + { + // Get the current system time + time_t t; + time(&t); + + // Format the time string properly + std::stringstream timeStr; + timeStr << "[" << ((((t / 60) / 60) % 24 < 10) ? "0" : "") + << (int) (((t / 60) / 60) % 24) + << ":" << (((t / 60) % 60 < 10) ? "0" : "") + << (int) ((t / 60) % 60) + << "] "; + + + mRecorder->record(timeStr.str() + _("Present: ") + response + "."); + chatLog(_("Attendance written to record log."), BY_SERVER, std::string(), true); + } + else + { + chatLog(_("Present: ") + response, BY_SERVER); + } + } + else if (command == "me") + { + std::stringstream actionStr; + actionStr << "*" << msg << "*"; + chatSend(player_node->getName(), actionStr.str()); + } + else + { + chatLog(_("Unknown command"), BY_SERVER); + } +} + +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: + msg = _("Trade failed!"); + break; + case BSKILL_EMOTE: + msg = _("Emote failed!"); + break; + case BSKILL_SIT: + msg = _("Sit failed!"); + break; + case BSKILL_CREATECHAT: + msg = _("Chat creating failed!"); + break; + case BSKILL_JOINPARTY: + msg = _("Could not join party!"); + break; + case BSKILL_SHOUT: + msg = _("Cannot shout!"); + break; + } + + msg += " "; + + switch (act.reason) + { + case RFAIL_SKILLDEP: + msg += _("You have not yet reached a high enough lvl!"); + break; + case RFAIL_INSUFHP: + msg += _("Insufficient HP!"); + break; + case RFAIL_INSUFSP: + msg += _("Insufficient SP!"); + break; + case RFAIL_NOMEMO: + msg += _("You have no memos!"); + break; + case RFAIL_SKILLDELAY: + msg += _("You cannot do that right now!"); + break; + case RFAIL_ZENY: + msg += _("Seems you need more money... ;-)"); + break; + case RFAIL_WEAPON: + msg += _("You cannot use this skill with that kind of weapon!"); + break; + case RFAIL_REDGEM: + msg += _("You need another red gem!"); + break; + case RFAIL_BLUEGEM: + msg += _("You need another blue gem!"); + break; + case RFAIL_OVERWEIGHT: + msg += _("You're carrying to much to do this!"); + break; + default: + msg += _("Huh? What's that?"); + break; + } + } + else + { + switch (act.skill) + { + case SKILL_WARP : + msg = _("Warp failed..."); + break; + case SKILL_STEAL : + msg = _("Could not steal anything..."); + break; + case SKILL_ENVENOM : + msg = _("Poison had no effect..."); + break; + } + } + + return msg; +} + +#endif + +void ChatWindow::scroll(int amount) +{ + if (!isVisible()) + return; + + ChannelMap::const_iterator chan = mChannels.find(getFocused()); + if (chan == mChannels.end()) + return; + + BrowserBox *browser = chan->second.browser; + ScrollArea *scroll = chan->second.scroll; + + int range = scroll->getHeight() / 8 * amount; + gcn::Rectangle scr; + scr.y = scroll->getVerticalScrollAmount() + range; + scr.height = abs(range); + browser->showPart(scr); +} + void ChatWindow::keyPressed(gcn::KeyEvent &event) { if (event.getKey().getValue() == Key::DOWN && @@ -422,11 +962,14 @@ void ChatWindow::keyPressed(gcn::KeyEvent &event) { // Move forward through the history HistoryIterator prevHist = mCurHist++; - if (mCurHist != mHistory.end()) { + + if (mCurHist != mHistory.end()) + { mChatInput->setText(*mCurHist); mChatInput->setCaretPosition(mChatInput->getText().length()); } - else { + else + { mCurHist = prevHist; } } @@ -446,23 +989,171 @@ void ChatWindow::setInputText(std::string input_str) requestChatFocus(); } -void ChatWindow::addItemText(int itemId, const std::string &item) +void ChatWindow::addItemText(const std::string &item) { std::ostringstream text; - text << "[@@" << itemId << "|" << item << "@@] "; + text << "[" << item << "] "; mChatInput->setText(mChatInput->getText() + text.str()); requestChatFocus(); } void ChatWindow::setVisible(bool isVisible) { - Window::setVisible(isVisible); + Window::setVisible(isVisible); + + /* + * For whatever reason, if setVisible is called, the mTmpVisible effect + * should be disabled. + */ + mTmpVisible = false; +} + +#ifdef EATHENA_SUPPORT +void ChatWindow::party(const std::string & command, const std::string & rest) +{ + if (command == "prefix") + { + if (rest.empty()) + { + char temp[2] = "."; + *temp = mPartyPrefix; + chatLog(_("The current party prefix is ") + std::string(temp), + BY_SERVER); + } + else if (rest.length() != 1) + { + chatLog(_("Party prefix must be one character long."), BY_SERVER); + } + else + { + if (rest == "/") + { + chatLog(_("Cannot use a '/' as the prefix."), BY_SERVER); + } + else + { + mPartyPrefix = rest.at(0); + chatLog(_("Changing prefix to ") + rest, BY_SERVER); + } + } + } + else + mParty->respond(command, rest); +} +#endif - /* - * For whatever reason, if setVisible is called, the mTmpVisible effect - * should be disabled. - */ - mTmpVisible = false; +void ChatWindow::help(const std::string & msg1, const std::string & msg2) +{ + chatLog(_("-- Help --"), BY_SERVER); + if (msg1.empty()) + { + chatLog(_("/announce: Global announcement (GM only)"), BY_SERVER); + chatLog(_("/clear: Clears this window"), BY_SERVER); + chatLog(_("/help: Display this help"), BY_SERVER); + chatLog(_("/me <message>: Tell something about yourself"), BY_SERVER); + chatLog(_("/msg <nick> <message>: Alternate form for /whisper"), + BY_SERVER); + chatLog(_("/party <command> <params>: Party commands"), BY_SERVER); + chatLog(_("/present: Get list of players present"), BY_SERVER); + chatLog(_("/record <filename>: Start recording the chat to an " + "external file"), BY_SERVER); + chatLog(_("/toggle: Determine whether <return> toggles the chat log"), + BY_SERVER); + chatLog(_("/w <nick> <message>: Short form for /whisper"), BY_SERVER); + chatLog(_("/where: Display map name"), BY_SERVER); + chatLog(_("/whisper <nick> <message>: Sends a private <message> " + "to <nick>"), BY_SERVER); + chatLog(_("/who: Display number of online users"), BY_SERVER); + chatLog(_("For more information, type /help <command>"), BY_SERVER); + } + else if (msg1 == "announce") + { + chatLog(_("Command: /announce <msg>"), BY_SERVER); + chatLog(_("*** only available to a GM ***"), BY_SERVER); + chatLog(_("This command sends the message <msg> to " + "all players currently online."), BY_SERVER); + } + else if (msg1 == "clear") + { + chatLog(_("Command: /clear"), BY_SERVER); + chatLog(_("This command clears the chat log of previous chat."), + BY_SERVER); + } + else if (msg1 == "help") + { + chatLog(_("Command: /help"), BY_SERVER); + chatLog(_("This command displays a list of all commands available."), + BY_SERVER); + chatLog(_("Command: /help <command>"), BY_SERVER); + chatLog(_("This command displays help on <command>."), BY_SERVER); + } + else if (msg1 == "me") + { + chatLog(_("Command: /me <msg>"), BY_SERVER); + chatLog(_("This command tell others you are (doing) <msg>."), + BY_SERVER); + } +#ifdef EATHENA_SUPPORT + else if (msg1 == "party") + { + mParty->help(msg2); + } +#endif + else if (msg1 == "present") + { + chatLog(_("Command: /present"), BY_SERVER); + chatLog(_("This command gets a list of players within hearing and " + "sends it to either the record log if recording, or the chat " + "log otherwise."), BY_SERVER); + } + else if (msg1 == "record") + { + chatLog(_("Command: /record <filename>"), BY_SERVER); + chatLog(_("This command starts recording the chat log to the file " + "<filename>."), BY_SERVER); + chatLog(_("Command: /record"), BY_SERVER); + chatLog(_("This command finishes a recording session."), BY_SERVER); + } + else if (msg1 == "toggle") + { + chatLog(_("Command: /toggle <state>"), BY_SERVER); + chatLog(_("This command sets whether the return key should toggle the " + "chat log, or whether the chat log turns off automatically."), + BY_SERVER); + chatLog(_("<state> can be one of \"1\", \"yes\", \"true\" to " + "turn the toggle on, or \"0\", \"no\", \"false\" to turn the " + "toggle off."), BY_SERVER); + chatLog(_("Command: /toggle"), BY_SERVER); + chatLog(_("This command displays the return toggle status."), + BY_SERVER); + } + else if (msg1 == "where") + { + chatLog(_("Command: /where"), BY_SERVER); + chatLog(_("This command displays the name of the current map."), + BY_SERVER); + } + else if (msg1 == "whisper" || msg1 == "msg" || msg1 == "w") + { + chatLog(_("Command: /msg <nick> <msg>"), BY_SERVER); + chatLog(_("Command: /whisper <nick> <msg>"), BY_SERVER); + chatLog(_("Command: /w <nick> <msg>"), BY_SERVER); + chatLog(_("This command sends the message <msg> to <nick>."), + BY_SERVER); + chatLog(_("If the <nick> has spaces in it, enclose it in " + "double quotes (\")."), BY_SERVER); + } + else if (msg1 == "who") + { + chatLog(_("Command: /who"), BY_SERVER); + chatLog(_("This command displays the number of players currently " + "online."), BY_SERVER); + } + else + { + chatLog(_("Unknown command."), BY_SERVER); + chatLog(_("Type /help for a list of commands."), BY_SERVER); + } } bool ChatWindow::tabExists(const std::string &tabName) diff --git a/src/gui/chat.h b/src/gui/chat.h index 114b389c..bbca76ad 100644 --- a/src/gui/chat.h +++ b/src/gui/chat.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_CHAT_H -#define _TMW_CHAT_H +#ifndef CHAT_H +#define CHAT_H #include <list> #include <string> @@ -31,25 +31,86 @@ #include "window.h" -#include "../guichanfwd.h" - class BrowserBox; +class Channel; +class Recorder; class ScrollArea; class TabbedArea; -class Channel; class ItemLinkHandler; +#ifdef EATHENA_SUPPORT +class Network; +class Party; +#endif enum { - BY_GM = 0, - BY_PLAYER = 1, - BY_OTHER = 2, - BY_SERVER = 3, - BY_CHANNEL = 4, + BY_GM, +#ifdef EATHENA_SUPPORT + BY_PARTY, +#endif + BY_PLAYER, + BY_OTHER, + BY_SERVER, + BY_CHANNEL, + ACT_WHISPER, // getting whispered at + ACT_IS, // equivalent to "/me" on IRC BY_LOGGER }; /** + * gets in between usernick and message text depending on + * message type + */ +#define CAT_NORMAL ": " +#define CAT_IS "" +#define CAT_WHISPER " whispers: " + +#ifdef EATHENA_SUPPORT +/** job dependend identifiers (?) */ +#define SKILL_BASIC 0x0001 +#define SKILL_WARP 0x001b +#define SKILL_STEAL 0x0032 +#define SKILL_ENVENOM 0x0034 + +/** basic skills identifiers */ +#define BSKILL_TRADE 0x0000 +#define BSKILL_EMOTE 0x0001 +#define BSKILL_SIT 0x0002 +#define BSKILL_CREATECHAT 0x0003 +#define BSKILL_JOINPARTY 0x0004 +#define BSKILL_SHOUT 0x0005 +#define BSKILL_PK 0x0006 // ?? +#define BSKILL_SETALLIGN 0x0007 // ?? + +/** reasons why action failed */ +#define RFAIL_SKILLDEP 0x00 +#define RFAIL_INSUFHP 0x01 +#define RFAIL_INSUFSP 0x02 +#define RFAIL_NOMEMO 0x03 +#define RFAIL_SKILLDELAY 0x04 +#define RFAIL_ZENY 0x05 +#define RFAIL_WEAPON 0x06 +#define RFAIL_REDGEM 0x07 +#define RFAIL_BLUEGEM 0x08 +#define RFAIL_OVERWEIGHT 0x09 +#define RFAIL_GENERIC 0x0a + +/** should always be zero if failed */ +#define SKILL_FAILED 0x00 + +struct CHATSKILL +{ + short skill; + short bskill; + short unused; + char success; + char reason; +}; +#endif + +#define DEFAULT_CHAT_WINDOW_SCROLL 7 // 1 means `1/8th of the window size'. + +/** * The chat window. * * \ingroup Interface @@ -62,10 +123,14 @@ class ChatWindow : public Window, /** * Constructor. */ +#ifdef TMWSERV_SUPPORT ChatWindow(); +#else + ChatWindow(Network *network); +#endif /** - * + * Destructor: used to write back values to the config file */ ~ChatWindow(); @@ -75,26 +140,36 @@ class ChatWindow : public Window, */ void widgetResized(const gcn::Event &event); - /** - * Gets the focused tab's name - */ - const std::string& getFocused() const; - - /** - * Clear the tab with the given name - */ - void clearTab(const std::string &tab); + void logic(); /** * Adds a line of text to our message list. Parameters: * * @param line Text message. - * @param own Type of message (usually the owner-type). + * @parem own Type of message (usually the owner-type). * @param channelName which channel to send the message to. */ void chatLog(std::string line, int own = BY_SERVER, - std::string channelName = ""); + std::string channelName = "", + bool ignoreRecord = false); + +#ifdef EATHENA_SUPPORT + /** + * Calls original chat_log() after processing the packet. + */ + void chatLog(CHATSKILL); +#endif + + /** + * Gets the focused tab's name + */ + const std::string& getFocused() const; + + /** + * Clear the tab with the given name + */ + void clearTab(const std::string &tab); /** * Performs action. @@ -111,6 +186,7 @@ class ChatWindow : public Window, */ bool isInputFocused(); +#ifdef TMWSERV_SUPPORT /** * Determines whether the message is a command or message, then * sends the given message to the game server to be said, or to the @@ -135,6 +211,33 @@ class ChatWindow : public Window, void sendToChannel(short channel, const std::string &user, const std::string &msg); +#else + /** + * 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); +#endif /** Called when key is pressed */ void keyPressed(gcn::KeyEvent &event); @@ -143,7 +246,7 @@ class ChatWindow : public Window, void setInputText(std::string input_str); /** Called to add item to chat */ - void addItemText(int itemid, const std::string &item); + void addItemText(const std::string &item); /** Override to reset mTmpVisible */ void setVisible(bool visible); @@ -151,14 +254,45 @@ class ChatWindow : public Window, /** Check if tab with that name already exists */ bool tabExists(const std::string &tabName); - void logic(); + /** + * 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); + +#ifdef EATHENA_SUPPORT + /** + * 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); +#endif + + /** + * 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: +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif bool mTmpVisible; int mItems; int mItemsKeep; + void whisper(const std::string &nick, std::string msg); + + /** One item in the chat log */ struct CHATLOG { std::string nick; @@ -166,6 +300,11 @@ class ChatWindow : public Window, int own; }; +#ifdef EATHENA_SUPPORT + /** Constructs failed messages for actions */ + std::string const_msg(CHATSKILL); +#endif + /** * A structure combining a BrowserBox with its ScrollArea. */ @@ -196,6 +335,14 @@ class ChatWindow : public Window, typedef History::iterator HistoryIterator; History mHistory; /**< Command history. */ HistoryIterator mCurHist; /**< History iterator. */ + Recorder *mRecorder; /**< Recording class */ + bool mReturnToggles; /**< Marks whether <Return> toggles the chat log + or not */ +#ifdef EATHENA_SUPPORT + char mPartyPrefix; /**< Messages beginning with the prefix are sent to + the party */ + Party *mParty; +#endif }; extern ChatWindow *chatWindow; diff --git a/src/gui/chatinput.cpp b/src/gui/chatinput.cpp index afe7f037..43f3cde4 100644 --- a/src/gui/chatinput.cpp +++ b/src/gui/chatinput.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/gui/chatinput.h b/src/gui/chatinput.h index e04dfa6e..3bc16928 100644 --- a/src/gui/chatinput.h +++ b/src/gui/chatinput.h @@ -1,26 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_CHATINPUT_H -#define _TMW_CHATINPUT_H +#ifndef CHATINPUT_H +#define CHATINPUT_H + +#include <guichan/focuslistener.hpp> #include "textfield.h" diff --git a/src/gui/checkbox.cpp b/src/gui/checkbox.cpp index 20e24dee..7fa4fa81 100644 --- a/src/gui/checkbox.cpp +++ b/src/gui/checkbox.cpp @@ -1,32 +1,34 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "checkbox.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" int CheckBox::instances = 0; +float CheckBox::mAlpha = config.getValue("guialpha", 0.8); Image *CheckBox::checkBoxNormal; Image *CheckBox::checkBoxChecked; Image *CheckBox::checkBoxDisabled; @@ -43,6 +45,10 @@ CheckBox::CheckBox(const std::string& caption, bool selected): checkBoxChecked = checkBox->getSubImage(9, 0, 9, 10); checkBoxDisabled = checkBox->getSubImage(18, 0, 9, 10); checkBoxDisabledChecked = checkBox->getSubImage(27, 0, 9, 10); + checkBoxNormal->setAlpha(mAlpha); + checkBoxChecked->setAlpha(mAlpha); + checkBoxDisabled->setAlpha(mAlpha); + checkBoxDisabledChecked->setAlpha(mAlpha); checkBox->decRef(); } @@ -66,16 +72,25 @@ void CheckBox::drawBox(gcn::Graphics* graphics) { Image *box; - if (isSelected()) { - if (isEnabled()) { + if (isSelected()) + { + if (isEnabled()) box = checkBoxChecked; - } else { + else box = checkBoxDisabledChecked; - } - } else if (isEnabled()) { + } + else if (isEnabled()) box = checkBoxNormal; - } else { + else box = checkBoxDisabled; + + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + checkBoxNormal->setAlpha(mAlpha); + checkBoxChecked->setAlpha(mAlpha); + checkBoxDisabled->setAlpha(mAlpha); + checkBoxDisabledChecked->setAlpha(mAlpha); } static_cast<Graphics*>(graphics)->drawImage(box, 2, 2); diff --git a/src/gui/checkbox.h b/src/gui/checkbox.h index 839ca97e..20adb43c 100644 --- a/src/gui/checkbox.h +++ b/src/gui/checkbox.h @@ -1,28 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_CHECKBOX_H -#define _TMW_CHECKBOX_H - -#include <iosfwd> +#ifndef CHECKBOX_H +#define CHECKBOX_H #include <guichan/widgets/checkbox.hpp> @@ -33,7 +31,8 @@ class Image; * * \ingroup GUI */ -class CheckBox : public gcn::CheckBox { +class CheckBox : public gcn::CheckBox +{ public: /** * Constructor. @@ -52,6 +51,7 @@ class CheckBox : public gcn::CheckBox { private: static int instances; + static float mAlpha; static Image *checkBoxNormal; static Image *checkBoxChecked; static Image *checkBoxDisabled; diff --git a/src/gui/color.cpp b/src/gui/color.cpp new file mode 100644 index 00000000..f9b89857 --- /dev/null +++ b/src/gui/color.cpp @@ -0,0 +1,146 @@ +/* + * Configurable text colors + * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "color.h" + +#include "../configuration.h" + +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +Color::Color() +{ + addColor('C', 0x000000, _("Chat")); + addColor('G', 0xff0000, _("GM")); + addColor('H', 0xebc873, _("Highlight")); + addColor('Y', 0x1fa052, _("Player")); + addColor('W', 0x0000ff, _("Whisper")); + addColor('I', 0xa08527, _("Is")); + addColor('P', 0xff00d8, _("Party")); + addColor('S', 0x8415e2, _("Server")); + addColor('L', 0x919191, _("Logger")); + addColor('<', 0xe50d0d, _("Hyperlink")); + commit(); +} + +Color::~Color() +{ + for (ColVector::iterator col = mColVector.begin(), + colEnd = mColVector.end(); + col != colEnd; + ++col) + { + config.setValue("Color" + col->text, toString(col->rgb)); + } +} + +void Color::setColor(char c, int rgb) +{ + for (ColVector::iterator col = mColVector.begin(), + colEnd = mColVector.end(); + col != colEnd; + ++col) + { + if (col->ch == c) + { + col->rgb = rgb; + return; + } + } +} + +int Color::getColor(char c, bool &valid) const +{ + for (ColVector::const_iterator col = mColVector.begin(), + colEnd = mColVector.end(); + col != colEnd; + ++col) + { + if (col->ch == c) + { + valid = true; + return col->rgb; + } + } + valid = false; + return 0x000000; +} + +std::string Color::getElementAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return mColVector[i].text; +} + +char Color::getColorCharAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return 'C'; + } + return mColVector[i].ch; +} + +void Color::addColor(char c, int rgb, const std::string &text) +{ + int trueRgb = (int) config.getValue("Color" + text, rgb); + mColVector.push_back(ColorElem(c, trueRgb, text)); +} + +int Color::getColorAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return 0; + } + return mColVector[i].rgb; +} + +void Color::setColorAt(int i, int rgb) +{ + if (i >= 0 && i < getNumberOfElements()) + { + mColVector[i].rgb = rgb; + } +} + +void Color::commit() +{ + for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end(); + i != iEnd; + ++i) + { + i->committedRgb = i->rgb; + } +} + +void Color::rollback() +{ + for (ColVector::iterator i = mColVector.begin(), iEnd = mColVector.end(); + i != iEnd; + ++i) + { + i->rgb = i->committedRgb; + } +} diff --git a/src/gui/color.h b/src/gui/color.h new file mode 100644 index 00000000..2816cedc --- /dev/null +++ b/src/gui/color.h @@ -0,0 +1,136 @@ +/* + * Configurable text colors + * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef COLOR_H +#define COLOR_H + +#include <string> +#include <vector> + +#include <guichan/listmodel.hpp> + +class Color : public gcn::ListModel +{ + public: + /** + * Constructor + */ + Color(); + + /** + * Destructor + */ + ~Color(); + + /** + * Define the color replacement for a character + * + * @param c charater to be replaced + * @param rgb color to replace character + */ + void setColor(char c, int rgb); + + /** + * Define the color replacement for a character + * + * @param c character to be replaced + * @param r red component + * @param g green component + * @param b blue component + */ + void setColor(char c, int r, int g, int b) + { + setColor(c, (r << 16) | (g << 8) | b); + } + + /** + * Return the color associated with a character, if exists + * + * @param c character requested + * @param valid indicate whether character is known + */ + int getColor(char c, bool &valid) const; + + /** + * Return the number of colors known + */ + int getNumberOfElements() { return mColVector.size(); } + + /** + * Return the name of the ith color + * + * @param i index of color interested in + */ + std::string getElementAt(int i); + + /** + * Get the color for the element at index i in the current color + * model + */ + int getColorAt(int i); + + /** + * Get the character used by the color for the element at index i in + * the current color model + */ + char getColorCharAt(int i); + + /** + * Set the color for the element at index i + */ + void setColorAt(int i, int rgb); + + /** + * Commit the colors + */ + void commit(); + + /** + * Rollback the colors + */ + void rollback(); + + private: + struct ColorElem + { + ColorElem(char c, int rgb, const std::string &text) : + ch(c), rgb(rgb), text(text) {} + char ch; + int rgb; + int committedRgb; + std::string text; + }; + typedef std::vector<ColorElem> ColVector; + ColVector mColVector; + + /** + * Initialise color + * + * @param c character that needs initialising + * @param rgb default color if not found in config + * @param text identifier of color + */ + void addColor(char c, int rgb, const std::string &text); +}; + +extern Color *textColor; + +#endif diff --git a/src/gui/confirm_dialog.cpp b/src/gui/confirm_dialog.cpp index 5f2b9cb2..5ad2e26c 100644 --- a/src/gui/confirm_dialog.cpp +++ b/src/gui/confirm_dialog.cpp @@ -1,29 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "confirm_dialog.h" - -#include <guichan/widgets/label.hpp> +#include <guichan/font.hpp> #include "button.h" +#include "confirm_dialog.h" +#include "scrollarea.h" +#include "textbox.h" #include "../utils/gettext.h" @@ -31,32 +32,55 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, Window *parent): Window(title, true, parent) { - gcn::Label *textLabel = new gcn::Label(msg); + mTextBox = new TextBox; + mTextBox->setEditable(false); + mTextBox->setOpaque(false); + + mTextArea = new ScrollArea(mTextBox); gcn::Button *yesButton = new Button(_("Yes"), "yes", this); gcn::Button *noButton = new Button(_("No"), "no", this); - int w = textLabel->getWidth() + 20; + mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mTextArea->setOpaque(false); + + mTextBox->setTextWrapped(msg, 260); + + int numRows = mTextBox->getNumberOfRows(); + int width = getFont()->getWidth(title); int inWidth = yesButton->getWidth() + noButton->getWidth() + 5; - int h = textLabel->getHeight() + 25 + yesButton->getHeight(); - if (w < inWidth + 10) { - w = inWidth + 10; + if (numRows > 1) + { + // 15 == height of each line of text (based on font heights) + // 14 == row top + bottom graphic pixel heights + setContentSize(mTextBox->getMinWidth() + 15, 15 + (numRows * 15) + noButton->getHeight()); + mTextArea->setDimension(gcn::Rectangle(4, 5, mTextBox->getMinWidth() + 5, + 3 + (numRows * 14))); + } + else + { + if (width < getFont()->getWidth(msg)) + width = getFont()->getWidth(msg); + if (width < inWidth) + width = inWidth; + setContentSize(width + 15, 30 + noButton->getHeight()); + mTextArea->setDimension(gcn::Rectangle(4, 5, width + 5, 17)); } - setContentSize(w, h); - textLabel->setPosition(10, 10); yesButton->setPosition( - (w - inWidth) / 2, - h - 5 - noButton->getHeight()); + (mTextBox->getMinWidth() - inWidth) / 2, + (numRows * 14) + noButton->getHeight() - 8); noButton->setPosition( yesButton->getX() + yesButton->getWidth() + 5, - h - 5 - noButton->getHeight()); + (numRows * 14) + noButton->getHeight() - 8); - add(textLabel); + add(mTextArea); add(yesButton); add(noButton); - if (getParent()) { + if (getParent()) + { setLocationRelativeTo(getParent()); getParent()->moveToTop(this); } @@ -64,6 +88,11 @@ ConfirmDialog::ConfirmDialog(const std::string &title, const std::string &msg, yesButton->requestFocus(); } +unsigned int ConfirmDialog::getNumRows() +{ + return mTextBox->getNumberOfRows(); +} + void ConfirmDialog::action(const gcn::ActionEvent &event) { // Proxy button events to our listeners diff --git a/src/gui/confirm_dialog.h b/src/gui/confirm_dialog.h index c9bfca02..8d8c0436 100644 --- a/src/gui/confirm_dialog.h +++ b/src/gui/confirm_dialog.h @@ -1,38 +1,41 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_OPTION_DIALOG_H -#define _TMW_OPTION_DIALOG_H +#ifndef OPTION_DIALOG_H +#define OPTION_DIALOG_H #include <guichan/actionlistener.hpp> #include "window.h" +class ScrollArea; +class TextBox; /** * An option dialog. * * \ingroup GUI */ -class ConfirmDialog : public Window, public gcn::ActionListener { +class ConfirmDialog : public Window, public gcn::ActionListener +{ public: /** * Constructor. @@ -42,10 +45,16 @@ 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; }; #endif diff --git a/src/gui/connection.cpp b/src/gui/connection.cpp index f54c9dd5..fbf127de 100644 --- a/src/gui/connection.cpp +++ b/src/gui/connection.cpp @@ -1,29 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "connection.h" - #include <guichan/widgets/label.hpp> #include "button.h" +#include "connection.h" #include "progressbar.h" #include "../main.h" @@ -61,10 +60,10 @@ void ConnectionDialog::action(gcn::ActionEvent const &) void ConnectionDialog::logic() { mProgress += 0.005f; + if (mProgress > 1.0f) - { mProgress = 0.0f; - } + mProgressBar->setProgress(mProgress); Window::logic(); } diff --git a/src/gui/connection.h b/src/gui/connection.h index 36ccd8a9..0e347266 100644 --- a/src/gui/connection.h +++ b/src/gui/connection.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_CONNECTION_H -#define _TMW_CONNECTION_H +#ifndef CONNECTION_H +#define CONNECTION_H #include <guichan/actionlistener.hpp> diff --git a/src/gui/debugwindow.cpp b/src/gui/debugwindow.cpp index ab09ec4e..2ed891db 100644 --- a/src/gui/debugwindow.cpp +++ b/src/gui/debugwindow.cpp @@ -1,113 +1,102 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "debugwindow.h" - #include <SDL_mouse.h> #include <guichan/widgets/label.hpp> -#include "button.h" -#include "gui.h" +#include "debugwindow.h" #include "viewport.h" -#include "../game.h" +#include "widgets/layout.h" + #include "../engine.h" +#include "../game.h" #include "../particle.h" #include "../map.h" -#include "../utils/tostring.h" +#include "../utils/stringutils.h" DebugWindow::DebugWindow(): Window("Debug") { setWindowName("Debug"); + setResizable(true); setCloseButton(true); setDefaultSize(0, 0, 400, 60); loadWindowState(); - mFPSLabel = new gcn::Label("[0 FPS]"); - mFPSLabel->setPosition(0,0); - + mFPSLabel = new gcn::Label("0 FPS"); mMusicFileLabel = new gcn::Label("Music: "); - mMusicFileLabel->setPosition(0, 15); - mMapLabel = new gcn::Label("Map: "); - mMapLabel->setPosition(0, 30); - mMiniMapLabel = new gcn::Label("Mini-Map: "); - mMiniMapLabel->setPosition(0, 45); - - mTileMouseLabel = new gcn::Label("[Mouse: 0, 0]"); - mTileMouseLabel->setPosition(200, 0); + mTileMouseLabel = new gcn::Label("Mouse: 0, 0"); + mParticleCountLabel = new gcn::Label("Particle count: 0"); - mParticleCountLabel = new gcn::Label("[Particle count: 0]"); - mParticleCountLabel->setPosition(200, 15); + place(0, 0, mFPSLabel); + place(3, 0, mTileMouseLabel); + place(0, 1, mMusicFileLabel, 2); + place(3, 1, mParticleCountLabel); + place(0, 2, mMapLabel, 2); + place(0, 3, mMiniMapLabel, 2); - add(mFPSLabel); - add(mMusicFileLabel); - add(mMiniMapLabel); - add(mMapLabel); - add(mTileMouseLabel); - add(mParticleCountLabel); + reflowLayout(375, 0); } -void -DebugWindow::logic() +void DebugWindow::logic() { // Get the current mouse position int mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); - int mouseTileX = mouseX + viewport->getCameraX(); - int mouseTileY = mouseY + viewport->getCameraY(); + int mouseTileX = mouseX / 32 + viewport->getCameraX(); + int mouseTileY = mouseY / 32 + viewport->getCameraY(); - mFPSLabel->setCaption("[" + toString(fps) + " FPS]"); + mFPSLabel->setCaption(toString(fps) + " FPS"); mFPSLabel->adjustSize(); - mTileMouseLabel->setCaption("[Mouse: " + - toString(mouseTileX) + ", " + toString(mouseTileY) + "]"); + mTileMouseLabel->setCaption("Mouse: " + + toString(mouseTileX) + ", " + toString(mouseTileY)); mTileMouseLabel->adjustSize(); Map *currentMap = engine->getCurrentMap(); - if (currentMap != NULL) + if (currentMap) { const std::string music = - " [Music: " + currentMap->getProperty("music") + "]"; + "Music: " + currentMap->getProperty("music"); mMusicFileLabel->setCaption(music); mMusicFileLabel->adjustSize(); const std::string minimap = - " [MiniMap: " + currentMap->getProperty("minimap") + "]"; + "MiniMap: " + currentMap->getProperty("minimap"); mMiniMapLabel->setCaption(minimap); mMiniMapLabel->adjustSize(); const std::string map = - " [Map: " + currentMap->getProperty("_filename") + "]"; + "Map: " + currentMap->getProperty("_filename"); mMapLabel->setCaption(map); mMapLabel->adjustSize(); } - mParticleCountLabel->setCaption("[Particle count: " + - toString(Particle::particleCount) - +"]"); + mParticleCountLabel->setCaption("Particle count: " + + toString(Particle::particleCount)); mParticleCountLabel->adjustSize(); } diff --git a/src/gui/debugwindow.h b/src/gui/debugwindow.h index 8d8b7822..e089de27 100644 --- a/src/gui/debugwindow.h +++ b/src/gui/debugwindow.h @@ -1,35 +1,31 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_DEBUGWINDOW_H -#define _TMW_DEBUGWINDOW_H - -#include <iosfwd> +#ifndef DEBUGWINDOW_H +#define DEBUGWINDOW_H #include <guichan/actionlistener.hpp> #include "window.h" -#include "../guichanfwd.h" - /** * The debug window. * diff --git a/src/gui/emotecontainer.cpp b/src/gui/emotecontainer.cpp new file mode 100644 index 00000000..e22b031b --- /dev/null +++ b/src/gui/emotecontainer.cpp @@ -0,0 +1,172 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/mouseinput.hpp> +#include <guichan/selectionlistener.hpp> + +#include "emotecontainer.h" + +#include "../animatedsprite.h" +#include "../configuration.h" +#include "../emoteshortcut.h" +#include "../graphics.h" +#include "../localplayer.h" +#include "../log.h" + +#include "../resources/emotedb.h" +#include "../resources/image.h" +#include "../resources/iteminfo.h" +#include "../resources/resourcemanager.h" + +#include "../utils/dtor.h" +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +const int EmoteContainer::gridWidth = 34; // emote icon width + 4 +const int EmoteContainer::gridHeight = 36; // emote icon height + 4 + +static const int NO_EMOTE = -1; + +EmoteContainer::EmoteContainer(): + mSelectedEmoteIndex(NO_EMOTE) +{ + ResourceManager *resman = ResourceManager::getInstance(); + + // Setup emote sprites + for (int i = 0; i <= EmoteDB::getLast(); i++) + { + mEmoteImg.push_back(player_node->getEmote(i)); + } + + mSelImg = resman->getImage("graphics/gui/selection.png"); + if (!mSelImg) logger->error(_("Unable to load selection.png")); + + mSelImg->setAlpha(config.getValue("guialpha", 0.8)); + + mMaxEmote = EmoteDB::getLast() + 1; + + addMouseListener(this); + addWidgetListener(this); +} + +EmoteContainer::~EmoteContainer() +{ + if (!mSelImg) + { + mSelImg->decRef(); + mSelImg = NULL; + } +} + +void EmoteContainer::draw(gcn::Graphics *graphics) +{ + int columns = getWidth() / gridWidth; + + // Have at least 1 column + if (columns < 1) + { + columns = 1; + } + + for (int i = 0; i < mMaxEmote ; i++) + { + int emoteX = ((i) % columns) * gridWidth; + int emoteY = ((i) / columns) * gridHeight; + + // Draw emote icon + mEmoteImg[i]->draw(static_cast<Graphics*>(graphics), emoteX, emoteY); + + // Draw selection image below selected item + if (mSelectedEmoteIndex == i) + { + static_cast<Graphics*>(graphics)->drawImage( + mSelImg, emoteX, emoteY); + } + } +} + +void EmoteContainer::widgetResized(const gcn::Event &event) +{ + recalculateHeight(); +} + +void EmoteContainer::recalculateHeight() +{ + int cols = getWidth() / gridWidth; + + if (cols < 1) + cols = 1; + + const int rows = (mMaxEmote / cols) + (mMaxEmote % cols > 0 ? 1 : 0); + const int height = rows * gridHeight + 8; + if (height != getHeight()) + setHeight(height); +} + +int EmoteContainer::getSelectedEmote() +{ + if (mSelectedEmoteIndex == NO_EMOTE) + return 0; + + return 1 + mSelectedEmoteIndex; +} + +void EmoteContainer::selectNone() +{ + setSelectedEmoteIndex(NO_EMOTE); +} + +void EmoteContainer::setSelectedEmoteIndex(int index) +{ + if (index < 0 || index >= mMaxEmote ) + mSelectedEmoteIndex = NO_EMOTE; + else + mSelectedEmoteIndex = index; +} + +void EmoteContainer::distributeValueChangedEvent() +{ + gcn::SelectionEvent event(this); + std::list<gcn::SelectionListener*>::iterator i_end = mListeners.end(); + std::list<gcn::SelectionListener*>::iterator i; + + for (i = mListeners.begin(); i != i_end; ++i) + { + (*i)->valueChanged(event); + } +} + +void EmoteContainer::mousePressed(gcn::MouseEvent &event) +{ + int button = event.getButton(); + if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT) + { + int columns = getWidth() / gridWidth; + int mx = event.getX(); + int my = event.getY(); + int index = mx / gridWidth + ((my / gridHeight) * columns); + if (index < mMaxEmote) + { + setSelectedEmoteIndex(index); + emoteShortcut->setEmoteSelected(index + 1); + } + } +} diff --git a/src/gui/emotecontainer.h b/src/gui/emotecontainer.h new file mode 100644 index 00000000..fefce793 --- /dev/null +++ b/src/gui/emotecontainer.h @@ -0,0 +1,136 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EMOTECONTAINER_H +#define EMOTECONTAINER_H + +#include <list> +#include <vector> + +#include <guichan/mouselistener.hpp> +#include <guichan/widget.hpp> +#include <guichan/widgetlistener.hpp> + +class AnimatedSprite; +class Image; + +namespace gcn { + class SelectionListener; +} + +/** + * An emote container. Used to show emotes in inventory and trade dialog. + * + * \ingroup GUI + */ +class EmoteContainer : public gcn::Widget, + public gcn::MouseListener, + public gcn::WidgetListener +{ + public: + /** + * Constructor. Initializes the graphic. + */ + EmoteContainer(); + + /** + * Destructor. + */ + virtual ~EmoteContainer(); + + /** + * Draws the emotes. + */ + void draw(gcn::Graphics *graphics); + + /** + * Called whenever the widget changes size. + */ + void widgetResized(const gcn::Event &event); + + /** + * Handles mouse click. + */ + void mousePressed(gcn::MouseEvent &event); + + /** + * Returns the selected emote. + */ + int getSelectedEmote(); + + /** + * Sets selected emote to NULL. + */ + void selectNone(); + + /** + * Adds a listener to the list that's notified each time a change to + * the selection occurs. + */ + void addSelectionListener(gcn::SelectionListener *listener) + { + mListeners.push_back(listener); + } + + /** + * Removes a listener from the list that's notified each time a change + * to the selection occurs. + */ + void removeSelectionListener(gcn::SelectionListener *listener) + { + mListeners.remove(listener); + } + + private: + /** + * Sets the currently selected emote. Invalid (e.g., negative) indices + * set `no emotr'. + */ + void setSelectedEmoteIndex(int index); + + /** + * Find the current emote index by the most recently used emote ID + */ + void refindSelectedEmote(void); + + /** + * Determine and set the height of the container. + */ + void recalculateHeight(void); + + /** + * Sends out selection events to the list of selection listeners. + */ + void distributeValueChangedEvent(void); + + std::vector<AnimatedSprite*> mEmoteImg; + Image *mSelImg; + int mSelectedEmoteIndex; + + int mMaxEmote; + + std::list<gcn::SelectionListener*> mListeners; + + static const int gridWidth; + static const int gridHeight; +}; + +#endif diff --git a/src/gui/emoteshortcutcontainer.cpp b/src/gui/emoteshortcutcontainer.cpp new file mode 100644 index 00000000..a0739723 --- /dev/null +++ b/src/gui/emoteshortcutcontainer.cpp @@ -0,0 +1,204 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "emoteshortcutcontainer.h" + +#include "../animatedsprite.h" +#include "../configuration.h" +#include "../emoteshortcut.h" +#include "../graphics.h" +#include "../inventory.h" +#include "../item.h" +#include "../itemshortcut.h" +#include "../keyboardconfig.h" +#include "../localplayer.h" +#include "../log.h" + +#include "../resources/emotedb.h" +#include "../resources/image.h" +#include "../resources/resourcemanager.h" + +#include "../utils/dtor.h" +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +static const int MAX_ITEMS = 12; + +EmoteShortcutContainer::EmoteShortcutContainer(): + ShortcutContainer(), + mEmoteClicked(false), + mEmoteMoved(0) +{ + addMouseListener(this); + addWidgetListener(this); + + ResourceManager *resman = ResourceManager::getInstance(); + + mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png"); + + mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8)); + + // Setup emote sprites + for (int i = 0; i <= EmoteDB::getLast(); i++) + { + mEmoteImg.push_back(player_node->getEmote(i)); + } + + mMaxItems = EmoteDB::getLast() < MAX_ITEMS ? EmoteDB::getLast() : MAX_ITEMS; + + mBoxHeight = mBackgroundImg->getHeight(); + mBoxWidth = mBackgroundImg->getWidth(); +} + +EmoteShortcutContainer::~EmoteShortcutContainer() +{ + mBackgroundImg->decRef(); +} + +void EmoteShortcutContainer::draw(gcn::Graphics *graphics) +{ + Graphics *g = static_cast<Graphics*>(graphics); + + graphics->setFont(getFont()); + + for (int i = 0; i < mMaxItems; i++) + { + const int emoteX = (i % mGridWidth) * mBoxWidth; + const int emoteY = (i / mGridWidth) * mBoxHeight; + + g->drawImage(mBackgroundImg, emoteX, emoteY); + + // Draw emote keyboard shortcut. + const char *key = SDL_GetKeyName( + (SDLKey) keyboard.getKeyValue(keyboard.KEY_EMOTE_1 + i)); + graphics->setColor(0x000000); + g->drawText(key, emoteX + 2, emoteY + 2, gcn::Graphics::LEFT); + + if (emoteShortcut->getEmote(i)) + { + mEmoteImg[emoteShortcut->getEmote(i) - 1]->draw(g, emoteX + 2, emoteY + 10); + } + + } + + if (mEmoteMoved) + { + // Draw the emote image being dragged by the cursor. + AnimatedSprite* sprite = mEmoteImg[mEmoteMoved - 1]; + if (sprite) + { + const int tPosX = mCursorPosX - (sprite->getWidth() / 2); + const int tPosY = mCursorPosY - (sprite->getHeight() / 2); + + sprite->draw(g, tPosX, tPosY); + } + } + + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + mBackgroundImg->setAlpha(mAlpha); + } +} + +void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (!mEmoteMoved && mEmoteClicked) + { + const int index = getIndexFromGrid(event.getX(), event.getY()); + const int emoteId = emoteShortcut->getEmote(index); + + if (index == -1) + { + return; + } + + if (emoteId) + { + mEmoteMoved = emoteId; + emoteShortcut->removeEmote(index); + } + } + if (mEmoteMoved) + { + mCursorPosX = event.getX(); + mCursorPosY = event.getY(); + } + } +} + +void EmoteShortcutContainer::mousePressed(gcn::MouseEvent &event) +{ + const int index = getIndexFromGrid(event.getX(), event.getY()); + + if (index == -1) + { + return; + } + + // Stores the selected emote if there is one. + if (emoteShortcut->isEmoteSelected()) + { + emoteShortcut->setEmote(index); + emoteShortcut->setEmoteSelected(0); + } + else if (emoteShortcut->getEmote(index)) + { + mEmoteClicked = true; + } +} + +void EmoteShortcutContainer::mouseReleased(gcn::MouseEvent &event) +{ + if (event.getButton() == gcn::MouseEvent::LEFT) + { + const int index = getIndexFromGrid(event.getX(), event.getY()); + + if (emoteShortcut->isEmoteSelected()) + { + emoteShortcut->setEmoteSelected(0); + } + + if (index == -1) + { + mEmoteMoved = 0; + return; + } + + if (mEmoteMoved) + { + emoteShortcut->setEmotes(index, mEmoteMoved); + mEmoteMoved = 0; + } + else if (emoteShortcut->getEmote(index) && mEmoteClicked) + { + emoteShortcut->useEmote(index + 1); + } + + if (mEmoteClicked) + { + mEmoteClicked = false; + } + } +} + diff --git a/src/gui/emoteshortcutcontainer.h b/src/gui/emoteshortcutcontainer.h new file mode 100644 index 00000000..d32a9f79 --- /dev/null +++ b/src/gui/emoteshortcutcontainer.h @@ -0,0 +1,77 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EMOTESHORTCUTCONTAINER_H +#define EMOTESHORTCUTCONTAINER_H + +#include <vector> + +#include "shortcutcontainer.h" + +class AnimatedSprite; +class Image; + +/** + * An emote shortcut container. Used to quickly use emoticons. + * + * \ingroup GUI + */ +class EmoteShortcutContainer : public ShortcutContainer +{ + public: + /** + * Constructor. Initializes the graphic. + */ + EmoteShortcutContainer(); + + /** + * Destructor. + */ + virtual ~EmoteShortcutContainer(); + + /** + * Draws the items. + */ + void draw(gcn::Graphics *graphics); + + /** + * Handles mouse when dragged. + */ + void mouseDragged(gcn::MouseEvent &event); + + /** + * Handles mouse when pressed. + */ + void mousePressed(gcn::MouseEvent &event); + + /** + * Handles mouse release. + */ + void mouseReleased(gcn::MouseEvent &event); + + private: + std::vector<AnimatedSprite*> mEmoteImg; + + bool mEmoteClicked; + int mEmoteMoved; +}; + +#endif diff --git a/src/gui/emotewindow.cpp b/src/gui/emotewindow.cpp new file mode 100644 index 00000000..48635720 --- /dev/null +++ b/src/gui/emotewindow.cpp @@ -0,0 +1,77 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "button.h" +#include "gui.h" +#include "emotewindow.h" +#include "emotecontainer.h" +#include "scrollarea.h" + +#include "widgets/layout.h" + +#include "../localplayer.h" + +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +EmoteWindow::EmoteWindow(): + Window(_("Emote")) +{ + setWindowName("Emote"); + setResizable(true); + setCloseButton(true); + setMinWidth(80); + setMinHeight(130); + setDefaultSize(115, 25, 322, 200); + + mUseButton = new Button(_("Use"), "use", this); + + mEmotes = new EmoteContainer; + mEmotes->addSelectionListener(this); + + mEmoteScroll = new ScrollArea(mEmotes); + mEmoteScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + place(0, 0, mEmoteScroll, 5, 4); + place(4, 4, mUseButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + mUseButton->setSize(60, mUseButton->getHeight()); + + loadWindowState(); +} + +void EmoteWindow::action(const gcn::ActionEvent &event) +{ + int emote = mEmotes->getSelectedEmote(); + + if (!emote) + return; + + player_node->emote(emote); +} + +int EmoteWindow::getSelectedEmote() const +{ + return mEmotes->getSelectedEmote(); +} diff --git a/src/gui/emotewindow.h b/src/gui/emotewindow.h new file mode 100644 index 00000000..8af24a7b --- /dev/null +++ b/src/gui/emotewindow.h @@ -0,0 +1,66 @@ +/* + * Extended support for activating emotes + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EMOTEWINDOW_H +#define EMOTEWINDOW_H + +#include <guichan/actionlistener.hpp> +#include <guichan/selectionlistener.hpp> + +#include "window.h" + +class EmoteContainer; +class TextBox; + +/** + * Emote dialog. + * + * \ingroup Interface + */ +class EmoteWindow : public Window, gcn::ActionListener, + gcn::SelectionListener +{ + public: + /** + * Constructor. + */ + EmoteWindow(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + /** + * Returns the selected item. + */ + int getSelectedEmote() const; + + private: + EmoteContainer *mEmotes; + + gcn::Button *mUseButton; + gcn::ScrollArea *mEmoteScroll; +}; + +extern EmoteWindow *emoteWindow; + +#endif diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index 6848b4d8..a44ae3ec 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -1,73 +1,100 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define BOX_WIDTH 36 #define BOX_HEIGHT 36 -#include "equipmentwindow.h" +#include <guichan/font.hpp> #include "button.h" +#include "equipmentwindow.h" +#include "itempopup.h" +#include "playerbox.h" +#include "viewport.h" +#include "../equipment.h" #include "../graphics.h" +#include "../inventory.h" #include "../item.h" #include "../localplayer.h" #include "../resources/image.h" +#include "../resources/iteminfo.h" #include "../resources/resourcemanager.h" #include "../utils/gettext.h" +#include "../utils/stringutils.h" // Positions of the boxes, 2nd dimension is X and Y respectively. static const int boxPosition[][2] = { - {90, 100}, // EQUIP_TORSO_SLOT - {135, 60}, // EQUIP_ARMS_SLOT - {90, 10}, // EQUIP_HEAD_SLOT - {90, 145}, // EQUIP_LEGS_SLOT - {90, 190}, // EQUIP_FEET_SLOT - {35, 105}, // EQUIP_RING1_SLOT - {145, 105}, // EQUIP_RING2_SLOT - {90, 55}, // EQUIP_NECKLACE_SLOT - {20, 150}, // EQUIP_FIGHT1_SLOT - {160, 150}, // EQUIP_FIGHT2_SLOT - {45, 60} // EQUIP_PROJECTILE_SLOT + {50, 208}, // EQUIP_LEGS_SLOT + {8, 123}, // EQUIP_FIGHT1_SLOT + {8, 78}, // EQUIP_GLOVES_SLOT + {129, 168}, // EQUIP_RING2_SLOT + {8, 168}, // EQUIP_RING1_SLOT + {129, 123}, // EQUIP_FIGHT2_SLOT + {90, 208}, // EQUIP_FEET_SLOT + {50, 40}, // EQUIP_CAPE_SLOT + {70, 0}, // EQUIP_HEAD_SLOT + {90, 40}, // EQUIP_TORSO_SLOT + {129, 78} // EQUIP_AMMO_SLOT }; +#ifdef TMWSERV_SUPPORT EquipmentWindow::EquipmentWindow(Equipment *equipment): +#else +EquipmentWindow::EquipmentWindow(): +#endif Window(_("Equipment")), +#ifdef TMWSERV_SUPPORT mEquipment(equipment), +#endif mBackground(NULL), mSelected(-1) { + mItemPopup = new ItemPopup; + + // Control that shows the Player + mPlayerBox = new PlayerBox; + mPlayerBox->setDimension(gcn::Rectangle(50, 80, 74, 123)); + mPlayerBox->setPlayer(player_node); + setWindowName("Equipment"); setCloseButton(true); - setDefaultSize(5, 195, 216, 260); + setDefaultSize(5, 195, 180, 300); loadWindowState(); mUnequip = new Button(_("Unequip"), "unequip", this); gcn::Rectangle const &area = getChildrenArea(); mUnequip->setPosition(area.width - mUnequip->getWidth() - 5, area.height - mUnequip->getHeight() - 5); + + add(mPlayerBox); add(mUnequip); +#ifdef TMWSERV_SUPPORT for (int i = 0; i < EQUIPMENT_SIZE; i++) +#else + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) +#endif { mEquipBox[i].posX = boxPosition[i][0] + getPadding(); mEquipBox[i].posY = boxPosition[i][1] + getTitleBarHeight(); @@ -76,11 +103,17 @@ EquipmentWindow::EquipmentWindow(Equipment *equipment): ResourceManager *resman = ResourceManager::getInstance(); mBackground = resman->getImage("graphics/gui/equip_bg.png"); mBackground->setAlpha(0.3); + +#ifdef EATHENA_SUPPORT + mEquipment = player_node->mEquipment.get(); + mInventory = player_node->getInventory(); +#endif } EquipmentWindow::~EquipmentWindow() { mBackground->decRef(); + delete mItemPopup; delete mUnequip; } @@ -91,21 +124,36 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) Graphics *g = static_cast<Graphics*>(graphics); - if (mBackground) - { - g->drawImage(mBackground, getPadding() + 10, 0); - } - Window::drawChildren(graphics); +#ifdef TMWSERV_SUPPORT for (int i = 0; i < EQUIPMENT_SIZE; i++) +#else + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) +#endif { +#ifdef TMWSERV_SUPPORT Item *item = mEquipment->getEquipment(i); +#else + Item *item = (i != EQUIP_AMMO_SLOT) ? + mInventory->getItem(mEquipment->getEquipment(i)) : + mInventory->getItem(mEquipment->getArrows()); +#endif if (item) { // Draw Item. Image *image = item->getImage(); g->drawImage(image, mEquipBox[i].posX, mEquipBox[i].posY); +#ifdef EATHENA_SUPPORT + if (i == EQUIP_AMMO_SLOT) + { + g->setColor(gcn::Color(0, 0, 0)); + graphics->drawText(toString(item->getQuantity()), + mEquipBox[i].posX + (BOX_WIDTH / 2), + mEquipBox[i].posY - getFont()->getHeight(), + gcn::Graphics::CENTER); + } +#endif } if (i == mSelected) @@ -118,6 +166,7 @@ void EquipmentWindow::draw(gcn::Graphics *graphics) // Set color black. g->setColor(gcn::Color(0, 0, 0)); } + // Draw box border. g->drawRectangle(gcn::Rectangle(mEquipBox[i].posX, mEquipBox[i].posY, BOX_WIDTH, BOX_HEIGHT)); @@ -128,11 +177,43 @@ void EquipmentWindow::action(const gcn::ActionEvent &event) { if (event.getId() == "unequip" && mSelected > -1) { +#ifdef TMWSERV_SUPPORT player_node->unequipItem(mSelected); +#else + Item* item = (mSelected != EQUIP_AMMO_SLOT) ? + mInventory->getItem(mEquipment->getEquipment(mSelected)) : + mInventory->getItem(mEquipment->getArrows()); + player_node->unequipItem(item); +#endif mSelected = -1; } } +Item* EquipmentWindow::getItem(int x, int y) const +{ +#ifdef TMWSERV_SUPPORT + for (int i = 0; i < EQUIPMENT_SIZE; i++) +#else + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) +#endif + { + gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY, + BOX_WIDTH, BOX_HEIGHT); + + if (tRect.isPointInRect(x, y)) + { +#ifdef TMWSERV_SUPPORT + return mEquipment->getEquipment(i); +#else + return (i != EQUIP_AMMO_SLOT) ? + mInventory->getItem(mEquipment->getEquipment(i)) : + mInventory->getItem(mEquipment->getArrows()); +#endif + } + } + return NULL; +} + void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) { Window::mousePressed(mouseEvent); @@ -140,17 +221,77 @@ void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) const int x = mouseEvent.getX(); const int y = mouseEvent.getY(); - // Checks if any of the presses were in the equip boxes. - for (int i = 0; i < EQUIPMENT_SIZE; i++) + Item* item; + + if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) { - gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY, - BOX_WIDTH, BOX_HEIGHT); - if (tRect.isPointInRect(x, y)) + // Checks if any of the presses were in the equip boxes. +#ifdef TMWSERV_SUPPORT + for (int i = 0; i < EQUIPMENT_SIZE; i++) +#else + for (int i = EQUIP_LEGS_SLOT; i < EQUIP_VECTOREND; i++) +#endif { - if (mEquipment->getEquipment(i)) +#ifdef TMWSERV_SUPPORT + item = mEquipment->getEquipment(i); +#else + item = (i != EQUIP_AMMO_SLOT) ? + mInventory->getItem(mEquipment->getEquipment(i)) : + mInventory->getItem(mEquipment->getArrows()); +#endif + gcn::Rectangle tRect(mEquipBox[i].posX, mEquipBox[i].posY, + BOX_WIDTH, BOX_HEIGHT); + + if (tRect.isPointInRect(x, y)) { - mSelected = i; + if (item) + { + mSelected = i; + } } } } + else if (mouseEvent.getButton() == gcn::MouseEvent::RIGHT) + { + item = getItem(x, y); + + if (!item) + return; + + /* Convert relative to the window coordinates to absolute screen + * coordinates. + */ + const int mx = x + getX(); + const int my = y + getY(); + viewport->showPopup(mx, my, item); + } +} + +// Show ItemTooltip +void EquipmentWindow::mouseMoved(gcn::MouseEvent &event) +{ + const int x = event.getX(); + const int y = event.getY(); + + Item* item = getItem(x, y); + + if (item) + { + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + + mItemPopup->setItem(item->getInfo()); + mItemPopup->setOpaque(false); + mItemPopup->view(x + getX(), y + getY()); + } + else + { + mItemPopup->setVisible(false); + } +} + +// Hide ItemTooltip +void EquipmentWindow::mouseExited(gcn::MouseEvent &event) +{ + mItemPopup->setVisible(false); } diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h index b6d2e2f4..7f7150ff 100644 --- a/src/gui/equipmentwindow.h +++ b/src/gui/equipmentwindow.h @@ -1,35 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_EQUIPMENT_H -#define _TMW_EQUIPMENT_H - -#include "window.h" +#ifndef EQUIPMENTWINDOW_H +#define EQUIPMENTWINDOW_H #include <guichan/actionlistener.hpp> -#include "../equipment.h" +#include "window.h" class Equipment; class Image; +class Inventory; +class Item; +class ItemPopup; +class PlayerBox; /** * Equipment box. @@ -51,7 +53,11 @@ class EquipmentWindow : public Window, public gcn::ActionListener /** * Constructor. */ +#ifdef TMWSERV_SUPPORT EquipmentWindow(Equipment *equipment); +#else + EquipmentWindow(); +#endif /** * Destructor. @@ -67,6 +73,7 @@ class EquipmentWindow : public Window, public gcn::ActionListener void mousePressed(gcn::MouseEvent& mouseEvent); +#ifdef TMWSERV_SUPPORT enum{ // Equipment rules: EQUIP_TORSO_SLOT = 0, @@ -79,15 +86,46 @@ class EquipmentWindow : public Window, public gcn::ActionListener EQUIP_NECKLACE_SLOT = 7, EQUIP_FIGHT1_SLOT = 8, EQUIP_FIGHT2_SLOT = 9, - EQUIP_PROJECTILE_SLOT = 10 + EQUIP_PROJECTILE_SLOT = 10, + EQUIP_VECTOREND }; +#else + enum { + // Equipment rules: + EQUIP_LEGS_SLOT = 0, + EQUIP_FIGHT1_SLOT, + EQUIP_GLOVES_SLOT, + EQUIP_RING2_SLOT, + EQUIP_RING1_SLOT, + EQUIP_FIGHT2_SLOT, + EQUIP_FEET_SLOT, + EQUIP_CAPE_SLOT, + EQUIP_HEAD_SLOT, + EQUIP_TORSO_SLOT, + EQUIP_AMMO_SLOT, + EQUIP_VECTOREND + }; +#endif + private: + void mouseExited(gcn::MouseEvent &event); + void mouseMoved(gcn::MouseEvent &event); + + Item* getItem(int x, int y) const; + Equipment *mEquipment; - gcn::Button *mUnequip; /**< Button for unequipping. */ +#ifdef EATHENA_SUPPORT + Inventory *mInventory; +#endif + gcn::Button *mUnequip; /**< Button for unequipping. */ Image *mBackground; /**< Background Image. */ - EquipBox mEquipBox[EQUIPMENT_SIZE]; /**< Equipment Boxes. */ + EquipBox mEquipBox[EQUIP_VECTOREND]; /**< Equipment Boxes. */ + + ItemPopup *mItemPopup; + + PlayerBox *mPlayerBox; - int mSelected; /**< Index of selected item. */ + int mSelected; /**< Index of selected item. */ }; extern EquipmentWindow *equipmentWindow; diff --git a/src/gui/focushandler.cpp b/src/gui/focushandler.cpp index 1bda568e..b9cfd789 100644 --- a/src/gui/focushandler.cpp +++ b/src/gui/focushandler.cpp @@ -1,33 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "focushandler.h" - void FocusHandler::requestModalFocus(gcn::Widget *widget) { /* If there is another widget with modal focus, remove its modal focus * and put it on the modal widget stack. */ - if (mModalFocusedWidget != NULL && mModalFocusedWidget != widget) + if (mModalFocusedWidget && mModalFocusedWidget != widget) { mModalStack.push_front(mModalFocusedWidget); mModalFocusedWidget = NULL; diff --git a/src/gui/focushandler.h b/src/gui/focushandler.h index a5218485..b0639bd8 100644 --- a/src/gui/focushandler.h +++ b/src/gui/focushandler.h @@ -1,33 +1,31 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_FOCUSHANDLER_H -#define _TMW_FOCUSHANDLER_H +#ifndef FOCUSHANDLER_H +#define FOCUSHANDLER_H #include <list> #include <guichan/focushandler.hpp> -#include "../guichanfwd.h" - /** * The focus handler. This focus handler does exactly the same as the Guichan * focus handler, but keeps a stack of modal widgets to be able to handle diff --git a/src/gui/gccontainer.cpp b/src/gui/gccontainer.cpp index ec3c8a5c..8325ccd4 100644 --- a/src/gui/gccontainer.cpp +++ b/src/gui/gccontainer.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/gui/gccontainer.h b/src/gui/gccontainer.h index cc7c9336..da584a42 100644 --- a/src/gui/gccontainer.h +++ b/src/gui/gccontainer.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUI_GCCONTAINER_H -#define _TMW_GUI_GCCONTAINER_H +#ifndef GUI_GCCONTAINER_H +#define GUI_GCCONTAINER_H #include <list> diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index dc6306b4..1ef0219a 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1,31 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "gui.h" - #include <guichan/exception.hpp> #include <guichan/image.hpp> #include <guichan/imagefont.hpp> #include "focushandler.h" +#include "gui.h" #include "sdlinput.h" #include "truetypefont.h" #include "viewport.h" @@ -39,20 +38,21 @@ #include "../resources/image.h" #include "../resources/imageset.h" -#include "../resources/resourcemanager.h" #include "../resources/imageloader.h" +#include "../resources/resourcemanager.h" // Guichan stuff -Gui *gui; -Viewport *viewport; /**< Viewport on the map. */ -SDLInput *guiInput; +Gui *gui = 0; +Viewport *viewport = 0; /**< Viewport on the map. */ +SDLInput *guiInput = 0; // Fonts used in showing hits -gcn::Font *hitRedFont; -gcn::Font *hitBlueFont; -gcn::Font *hitYellowFont; -// Font used to display speech and player names -gcn::Font *speechFont; +gcn::Font *hitRedFont = 0; +gcn::Font *hitBlueFont = 0; +gcn::Font *hitYellowFont = 0; + +// Bolded font +gcn::Font *boldFont = 0; class GuiConfigListener : public ConfigListener { @@ -63,7 +63,8 @@ class GuiConfigListener : public ConfigListener void optionChanged(const std::string &name) { - if (name == "customcursor") { + if (name == "customcursor") + { bool bCustomCursor = config.getValue("customcursor", 1) == 1; mGui->setUseCustomCursor(bCustomCursor); } @@ -96,7 +97,7 @@ Gui::Gui(Graphics *graphics): mFocusHandler = new FocusHandler; // Initialize top GUI widget - WindowContainer *guiTop = new WindowContainer(); + WindowContainer *guiTop = new WindowContainer; guiTop->setDimension(gcn::Rectangle(0, 0, graphics->getWidth(), graphics->getHeight())); guiTop->setOpaque(false); @@ -107,35 +108,48 @@ Gui::Gui(Graphics *graphics): // Set global font std::string path = resman->getPath( - branding.getValue("guiFont","fonts/dejavusans.ttf")); - if (!path.empty()) + branding.getValue("font", "fonts/dejavusans.ttf")); + try + { + const int fontSize = (int)config.getValue("fontSize", 11); + mGuiFont = new TrueTypeFont(path, fontSize); + } + catch (gcn::Exception e) { - mGuiFont = new TrueTypeFont(path.c_str(), 11); + logger->error(std::string("Unable to load dejavusans.ttf: ") + + e.getMessage()); } - // Set speech font + // Set bold font path = resman->getPath( - branding.getValue("speechFont","fonts/dejavusans.ttf")); - if (!path.empty()) + branding.getValue("boldFont", "fonts/dejavusans.ttf")); + try { - speechFont = new TrueTypeFont(path.c_str(), 11); + const int fontSize = (int)config.getValue("fontSize", 11); + boldFont = new TrueTypeFont(path, fontSize); + } + catch (gcn::Exception e) + { + logger->error(std::string("Unable to load dejavusans-bold.ttf: ") + + e.getMessage()); } gcn::Widget::setGlobalFont(mGuiFont); - // Load hits' colourful fonts - try { + // Load hits' colorful fonts + try + { hitRedFont = new gcn::ImageFont("graphics/gui/hits_red.png", - "0123456789"); + "0123456789crit! "); hitBlueFont = new gcn::ImageFont("graphics/gui/hits_blue.png", - "0123456789"); + "0123456789crit! "); hitYellowFont = new gcn::ImageFont("graphics/gui/hits_yellow.png", "0123456789misxp "); } catch (gcn::Exception e) { - logger->log("Unable to load colored hits' fonts: %s", e.getMessage().c_str()); - throw; + logger->error(std::string("Unable to load colored hits' fonts: ") + + e.getMessage()); } // Initialize mouse cursor and listen for changes to the option @@ -144,7 +158,7 @@ Gui::Gui(Graphics *graphics): config.addListener("customcursor", mConfigListener); // Create the viewport - viewport = new Viewport(); + viewport = new Viewport; viewport->setDimension(gcn::Rectangle(0, 0, graphics->getWidth(), graphics->getHeight())); guiTop->add(viewport); @@ -164,7 +178,7 @@ Gui::~Gui() mMouseCursors->decRef(); delete mGuiFont; - delete speechFont; + delete boldFont; delete viewport; delete getTop(); @@ -174,12 +188,13 @@ Gui::~Gui() void Gui::logic() { // Fade out mouse cursor after extended inactivity - if (mMouseInactivityTimer < 100 * 15) { + if (mMouseInactivityTimer < 100 * 15) + { ++mMouseInactivityTimer; mMouseCursorAlpha = std::min(1.0f, mMouseCursorAlpha + 0.05f); - } else { - mMouseCursorAlpha = std::max(0.0f, mMouseCursorAlpha - 0.005f); } + else + mMouseCursorAlpha = std::max(0.0f, mMouseCursorAlpha - 0.005f); gcn::Gui::logic(); } @@ -224,9 +239,8 @@ void Gui::setUseCustomCursor(bool customCursor) mMouseCursors = resman->getImageSet("graphics/gui/mouse.png", 40, 40); - if (!mMouseCursors) { + if (!mMouseCursors) logger->error("Unable to load mouse cursors."); - } } else { @@ -234,7 +248,8 @@ void Gui::setUseCustomCursor(bool customCursor) SDL_ShowCursor(SDL_ENABLE); // Unload the mouse cursor - if (mMouseCursors) { + if (mMouseCursors) + { mMouseCursors->decRef(); mMouseCursors = NULL; } diff --git a/src/gui/gui.h b/src/gui/gui.h index 7d390df9..5c0c24f7 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1,33 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUI -#define _TMW_GUI +#ifndef GUI +#define GUI #include <guichan/gui.hpp> #include "../guichanfwd.h" -class GuiConfigListener; class Graphics; +class GuiConfigListener; class ImageSet; class SDLInput; class Viewport; @@ -115,7 +115,6 @@ class Gui : public gcn::Gui }; extern Gui *gui; /**< The GUI system */ -extern Viewport *viewport; /**< The viewport */ extern SDLInput *guiInput; /**< GUI input */ /** @@ -124,9 +123,10 @@ extern SDLInput *guiInput; /**< GUI input */ extern gcn::Font *hitRedFont; extern gcn::Font *hitBlueFont; extern gcn::Font *hitYellowFont; + /** - * Font used to display speech and player names + * Bolded text font */ -extern gcn::Font *speechFont; +extern gcn::Font *boldFont; #endif diff --git a/src/gui/hbox.cpp b/src/gui/hbox.cpp deleted file mode 100644 index 020e85c6..00000000 --- a/src/gui/hbox.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 "hbox.h" - -void HBox::draw(gcn::Graphics *graphics) -{ - int widgetCount = mWidgets.size(); - int childHeight = getHeight(); - if (widgetCount == 0) - return; - int childWidth = getWidth() / widgetCount; - - int i = 0; - for (WidgetIterator w = mWidgets.begin(); w != mWidgets.end(); w++) { - (*w)->setPosition(childWidth * i - padding, 0); - (*w)->setSize(childWidth, childHeight); - i++; - } - gcn::Container::draw(graphics); -} diff --git a/src/gui/help.cpp b/src/gui/help.cpp index 290679b9..30c6a9c4 100644 --- a/src/gui/help.cpp +++ b/src/gui/help.cpp @@ -1,42 +1,48 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "help.h" - #include "button.h" #include "browserbox.h" +#include "help.h" #include "scrollarea.h" +#include "widgets/layout.h" + #include "../resources/resourcemanager.h" +#include "../utils/gettext.h" + HelpWindow::HelpWindow(): - Window("Help") + Window(_("Help")) { + setMinWidth(300); + setMinHeight(250); setContentSize(455, 350); setWindowName("Help"); + setResizable(true); - mBrowserBox = new BrowserBox(); + mBrowserBox = new BrowserBox; mBrowserBox->setOpaque(false); mScrollArea = new ScrollArea(mBrowserBox); - Button *okButton = new Button("Close", "close", this); + Button *okButton = new Button(_("Close"), "close", this); mScrollArea->setDimension(gcn::Rectangle( 5, 5, 445, 335 - okButton->getHeight())); @@ -46,8 +52,11 @@ HelpWindow::HelpWindow(): mBrowserBox->setLinkHandler(this); - add(mScrollArea); - add(okButton); + place(0, 0, mScrollArea, 5, 3).setPadding(3); + place(4, 3, okButton); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); setLocationRelativeTo(getParent()); } diff --git a/src/gui/help.h b/src/gui/help.h index 053df723..98e3aa67 100644 --- a/src/gui/help.h +++ b/src/gui/help.h @@ -1,33 +1,31 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_HELP_H -#define _TMW_HELP_H +#ifndef HELP_H +#define HELP_H #include <guichan/actionlistener.hpp> -#include "window.h" #include "linkhandler.h" - -#include "../guichanfwd.h" +#include "window.h" class BrowserBox; diff --git a/src/gui/inttextbox.cpp b/src/gui/inttextbox.cpp deleted file mode 100644 index 644601cf..00000000 --- a/src/gui/inttextbox.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 "inttextbox.h" - -#include "sdlinput.h" - -#include "../utils/tostring.h" - -IntTextBox::IntTextBox(int i): - mValue(i) -{ -} - -void -IntTextBox::keyPressed(gcn::KeyEvent &event) -{ - const gcn::Key &key = event.getKey(); - - if (key.getValue() == Key::BACKSPACE || - key.getValue() == Key::DELETE) - { - setText(std::string()); - event.consume(); - } - - if (!key.isNumber()) return; - TextField::keyPressed(event); - - std::istringstream s(getText()); - int i; - s >> i; - setInt(i); - distributeActionEvent(); -} - -void IntTextBox::setRange(int min, int max) -{ - mMin = min; - mMax = max; -} - -int IntTextBox::getInt() -{ - return getText().empty() ? mMin : mValue; -} - -void IntTextBox::setInt(int i) -{ - if (i >= mMin && i <= mMax) - mValue = i; - - const std::string valStr = toString(mValue); - setText(valStr); - setCaretPosition(valStr.length() + 1); -} diff --git a/src/gui/inttextfield.cpp b/src/gui/inttextfield.cpp new file mode 100644 index 00000000..d3fe448b --- /dev/null +++ b/src/gui/inttextfield.cpp @@ -0,0 +1,104 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "inttextfield.h" +#include "sdlinput.h" + +#include "../utils/stringutils.h" + +IntTextField::IntTextField(int def): + TextField(toString(def)), + mDefault(def), + mValue(def) +{ +} + +void IntTextField::keyPressed(gcn::KeyEvent &event) +{ + const gcn::Key &key = event.getKey(); + + if (key.getValue() == Key::BACKSPACE || + key.getValue() == Key::DELETE) + { + setText(std::string()); + event.consume(); + } + + if (!key.isNumber()) + return; + + TextField::keyPressed(event); + + std::istringstream s(getText()); + int i; + s >> i; + setValue(i); +} + +void IntTextField::setRange(int min, int max) +{ + mMin = min; + mMax = max; + + if (mValue < mMin) + mValue = mMin; + else if (mValue > mMax) + mValue = mMax; + + if (mDefault < mMin) + mDefault = mMin; + else if (mDefault > mMax) + mDefault = mMax; +} + +int IntTextField::getValue() +{ + return getText().empty() ? mMin : mValue; +} + +void IntTextField::setValue(int i) +{ + if (i < mMin) + mValue = mMin; + else if (i > mMax) + mValue = mMax; + else + mValue = i; + + const std::string valStr = toString(mValue); + setText(valStr); + setCaretPosition(valStr.length() + 1); +} + +void IntTextField::setDefaultValue(int value) +{ + if (value < mMin) + mDefault = mMin; + else if (value > mMax) + mDefault = mMax; + else + mDefault = value; +} + +void IntTextField::reset() +{ + setValue(mDefault); +} diff --git a/src/gui/inttextbox.h b/src/gui/inttextfield.h index 8dad0c39..ec768bea 100644 --- a/src/gui/inttextbox.h +++ b/src/gui/inttextfield.h @@ -1,39 +1,39 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef INTTEXTBOX_H -#define INTTEXTBOX_H +#ifndef INTTEXTFIELD_H +#define INTTEXTFIELD_H #include "textfield.h" /** * TextBox which only accepts numbers as input. */ -class IntTextBox : public TextField +class IntTextField : public TextField { public: /** - * Constructor, sets initial value. + * Constructor, sets default value. */ - IntTextBox(int value=0); + IntTextField(int def = 0); /** * Sets the minimum and maximum values of the text box. @@ -43,22 +43,32 @@ class IntTextBox : public TextField /** * Returns the value in the text box. */ - int getInt(); + int getValue(); + + /** + * Reset the field to the default value. + */ + void reset(); /** * Set the value of the text box to the specified value. */ - void setInt(int value); + void setValue(int value); + + /** + * Set the default value of the text box to the specified value. + */ + void setDefaultValue(int value); /** * Responds to key presses. */ - void - keyPressed(gcn::KeyEvent &event); + void keyPressed(gcn::KeyEvent &event); private: int mMin; /**< Minimum value */ int mMax; /**< Maximum value */ + int mDefault; /**< Default value */ int mValue; /**< Current value */ }; diff --git a/src/gui/inventorywindow.cpp b/src/gui/inventorywindow.cpp index b4a96394..d18490a4 100644 --- a/src/gui/inventorywindow.cpp +++ b/src/gui/inventorywindow.cpp @@ -1,56 +1,57 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "inventorywindow.h" - #include <string> +#include <guichan/font.hpp> #include <guichan/mouseinput.hpp> #include <guichan/widgets/label.hpp> -#include <guichan/widgets/checkbox.hpp> -#include <guichan/widgets/textbox.hpp> #include "button.h" -#include "gui.h" +#include "inventorywindow.h" #include "item_amount.h" #include "itemcontainer.h" -#include "itempopup.h" +#include "progressbar.h" #include "scrollarea.h" #include "sdlinput.h" #include "viewport.h" #include "widgets/layout.h" +#include "../inventory.h" #include "../item.h" #include "../localplayer.h" #include "../log.h" +#include "../units.h" #include "../resources/iteminfo.h" #include "../utils/gettext.h" +#include "../utils/stringutils.h" #include "../utils/strprintf.h" -InventoryWindow::InventoryWindow(): +InventoryWindow::InventoryWindow(int invSize): Window(_("Inventory")), + mMaxSlots(invSize), mSplit(false), mItemDesc(false) { @@ -65,28 +66,67 @@ InventoryWindow::InventoryWindow(): setDefaultSize(115, 30, 375, 283); addKeyListener(this); - mUseButton = new Button(_("Use"), "use", this); + std::string longestUseString = getFont()->getWidth(_("Equip")) > + getFont()->getWidth(_("Use")) ? + _("Equip") : _("Use"); + + if (getFont()->getWidth(longestUseString) < + getFont()->getWidth(_("Unequip"))) + { + longestUseString = _("Unequip"); + } + + mUseButton = new Button(longestUseString, "use", this); mDropButton = new Button(_("Drop"), "drop", this); +#ifdef TMWSERV_SUPPORT mSplitButton = new Button(_("Split"), "split", this); +#endif - mItems = new ItemContainer(player_node->mInventory, 10, 5); +#ifdef TMWSERV_SUPPORT + mItems = new ItemContainer(player_node->getInventory(), 10, 5); +#else + mItems = new ItemContainer(player_node->getInventory(), 10, 5, 2); +#endif mItems->addSelectionListener(this); mInvenScroll = new ScrollArea(mItems); + mInvenScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mTotalWeight = -1; + mMaxWeight = -1; + mUsedSlots = toString(player_node->getInventory()->getNumberOfSlotsUsed()); + + mSlotsLabel = new gcn::Label(_("Slots: ")); + mWeightLabel = new gcn::Label(_("Weight: ")); + + mSlotsBar = new ProgressBar(1.0f, 100, 20, 225, 200, 25); + mWeightBar = new ProgressBar(1.0f, 100, 20, 0, 0, 255); + + setMinHeight(130); + setMinWidth(mWeightLabel->getWidth() + mSlotsLabel->getWidth() + 280); + + place(0, 0, mWeightLabel).setPadding(3); + place(1, 0, mWeightBar, 3); + place(4, 0, mSlotsLabel).setPadding(3); + place(5, 0, mSlotsBar, 2); + place(0, 1, mInvenScroll, 100).setPadding(3); + place(0, 2, mUseButton); + place(1, 2, mDropButton); +#ifdef TMWSERV_SUPPORT + place(2, 2, mSplitButton); +#endif - place(0, 0, mInvenScroll, 100).setPadding(3); - place(0, 1, mUseButton); - place(1, 1, mDropButton); - place(2, 1, mSplitButton); Layout &layout = getLayout(); - layout.setColWidth(0, 48); - layout.setColWidth(1, 48); - layout.setColWidth(2, 48); layout.setRowHeight(0, Layout::AUTO_SET); loadWindowState(); } +InventoryWindow::~InventoryWindow() +{ + delete mItems; +} + void InventoryWindow::logic() { Window::logic(); @@ -95,24 +135,69 @@ void InventoryWindow::logic() // redesign of InventoryWindow and ItemContainer probably. updateButtons(); - // Update weight information - // mWeightLabel->setCaption(strprintf(_("Total Weight: %d - Maximum Weight: %d"), player_node->getTotalWeight(), player_node->getMaxWeight())); + if (mMaxWeight != player_node->getMaxWeight() || + mTotalWeight != player_node->getTotalWeight() || + mUsedSlots != toString(player_node->getInventory()->getNumberOfSlotsUsed())) + { + mTotalWeight = player_node->getTotalWeight(); + mMaxWeight = player_node->getMaxWeight(); + mUsedSlots = toString(player_node->getInventory()->getNumberOfSlotsUsed()); + + // Weight Bar coloration + if (int(player_node->getTotalWeight()) < int(player_node->getMaxWeight() / 3)) + { + mWeightBar->setColor(0, 0, 255); // Blue + } + else if (int(player_node->getTotalWeight()) < + int((player_node->getMaxWeight() / 3) * 2)) + { + mWeightBar->setColor(255, 255, 0); // Yellow + } + else + { + mWeightBar->setColor(255, 0, 0); // Red + } + + // Adjust progress bars + mSlotsBar->setProgress((float) + player_node->getInventory()->getNumberOfSlotsUsed() / mMaxSlots); + mWeightBar->setProgress((float) player_node->getTotalWeight() / + player_node->getMaxWeight()); + + mSlotsBar->setText(strprintf("%s/%d", mUsedSlots.c_str(), mMaxSlots)); + mWeightBar->setText(strprintf("%s/%s", + Units::formatWeight(mTotalWeight).c_str(), + Units::formatWeight(mMaxWeight).c_str())); + } } void InventoryWindow::action(const gcn::ActionEvent &event) { - Item *item = mItems->getItem(); + Item *item = mItems->getSelectedItem(); + if (!item) return; if (event.getId() == "use") { +#ifdef TMWSERV_SUPPORT if (item->isEquipment()) { player_node->equipItem(item); } else { player_node->useItem(item->getInvIndex()); } +#else + if (item->isEquipment()) + { + if (item->isEquipped()) + player_node->unequipItem(item); + else + player_node->equipItem(item); + } + else + player_node->useItem(item); +#endif } else if (event.getId() == "drop") { @@ -134,18 +219,9 @@ void InventoryWindow::action(const gcn::ActionEvent &event) } } -void InventoryWindow::valueChanged(const gcn::SelectionEvent &event) +Item* InventoryWindow::getSelectedItem() const { - Item *item = mItems->getItem(); - - if (mSplit) - { - if (item && !item->isEquipment() && item->getQuantity() > 1) - { - mSplit = false; - new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item, (item->getQuantity() - 1)); - } - } + return mItems->getSelectedItem(); } void InventoryWindow::mouseClicked(gcn::MouseEvent &event) @@ -154,7 +230,7 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) if (event.getButton() == gcn::MouseEvent::RIGHT) { - Item *item = mItems->getItem(); + Item *item = mItems->getSelectedItem(); if (!item) return; @@ -168,31 +244,7 @@ void InventoryWindow::mouseClicked(gcn::MouseEvent &event) } } -void InventoryWindow::updateButtons() -{ - Item *item = mItems->getItem(); - - if (item && item->isEquipment()) { - mUseButton->setCaption(_("Equip")); - } - else { - mUseButton->setCaption(_("Use")); - } - mUseButton->setEnabled(!!item); - mDropButton->setEnabled(!!item); - if (item && !item->isEquipment() && item->getQuantity() > 1) { - mSplitButton->setEnabled(true); - } - else { - mSplitButton->setEnabled(false); - } -} - -Item* InventoryWindow::getItem() -{ - return mItems->getItem(); -} - +#ifdef TMWSERV_SUPPORT void InventoryWindow::keyPressed(gcn::KeyEvent &event) { switch (event.getKey().getValue()) @@ -214,3 +266,49 @@ void InventoryWindow::keyReleased(gcn::KeyEvent &event) break; } } +#endif + +void InventoryWindow::valueChanged(const gcn::SelectionEvent &event) +{ + if (mSplit) + { + Item *item = mItems->getSelectedItem(); + + if (item && !item->isEquipment() && item->getQuantity() > 1) + { + mSplit = false; + new ItemAmountWindow(AMOUNT_ITEM_SPLIT, this, item, (item->getQuantity() - 1)); + } + } +} + +void InventoryWindow::updateButtons() +{ + const Item *selectedItem = mItems->getSelectedItem(); + + if (selectedItem && selectedItem->isEquipment()) + { +#ifdef EATHENA_SUPPORT + if (selectedItem->isEquipped()) + mUseButton->setCaption(_("Unequip")); + else +#endif + mUseButton->setCaption(_("Equip")); + } + else + mUseButton->setCaption(_("Use")); + + mUseButton->setEnabled(selectedItem != 0); + mDropButton->setEnabled(selectedItem != 0); + +#ifdef TMWSERV_SUPPORT + if (selectedItem && !selectedItem->isEquipment() && + selectedItem->getQuantity() > 1) + { + mSplitButton->setEnabled(true); + } + else { + mSplitButton->setEnabled(false); + } +#endif +} diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index 9d342c83..6a51c66d 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -1,38 +1,39 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_INVENTORYWINDOW_H -#define _TMW_INVENTORYWINDOW_H +#ifndef INVENTORYWINDOW_H +#define INVENTORYWINDOW_H #include <guichan/actionlistener.hpp> -#include <guichan/keylistener.hpp> #include <guichan/selectionlistener.hpp> -#include <guichan/widgets/checkbox.hpp> +#include <guichan/keylistener.hpp> #include "window.h" -#include "../guichanfwd.h" +#include "../localplayer.h" class Item; class ItemContainer; +class ProgressBar; +class TextBox; /** * Inventory dialog. @@ -48,7 +49,16 @@ class InventoryWindow : public Window, /** * Constructor. */ - InventoryWindow(); +#ifdef TMWSERV_SUPPORT + InventoryWindow(int invSize = (INVENTORY_SIZE)); +#else + InventoryWindow(int invSize = (INVENTORY_SIZE - 2)); +#endif + + /** + * Destructor. + */ + ~InventoryWindow(); /** * Logic (updates buttons and weight information). @@ -61,10 +71,16 @@ class InventoryWindow : public Window, void action(const gcn::ActionEvent &event); /** + * Returns the selected item. + */ + Item* getSelectedItem() const; + + /** * Handles the mouse clicks. */ void mouseClicked(gcn::MouseEvent &event); +#ifdef TMWSERV_SUPPORT /** * Handles the key presses. */ @@ -74,8 +90,7 @@ class InventoryWindow : public Window, * Handles the key releases. */ void keyReleased(gcn::KeyEvent &event); - - Item* getItem(); +#endif /** * Updates labels to currently selected item. @@ -87,13 +102,25 @@ class InventoryWindow : public Window, ItemContainer *mItems; - /**< Use, Drop, Split Item Buttons. */ - gcn::Button *mUseButton, *mDropButton, *mSplitButton; - + std::string mWeight; + std::string mSlots; + std::string mUsedSlots; + int mTotalWeight, mMaxWeight; + gcn::Button *mUseButton; + gcn::Button *mDropButton; +#ifdef TMWSERV_SUPPORT + gcn::Button *mSplitButton; +#endif gcn::ScrollArea *mInvenScroll; /**< Inventory Scroll Area. */ + gcn::Label *mWeightLabel; + gcn::Label *mSlotsLabel; - bool mSplit; + ProgressBar *mWeightBar; + ProgressBar *mSlotsBar; + int mMaxSlots; + + bool mSplit; bool mItemDesc; }; diff --git a/src/gui/item_amount.cpp b/src/gui/item_amount.cpp index cae681d4..3bd388f4 100644 --- a/src/gui/item_amount.cpp +++ b/src/gui/item_amount.cpp @@ -1,28 +1,27 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "item_amount.h" - #include "button.h" -#include "inttextbox.h" +#include "inttextfield.h" +#include "item_amount.h" #include "slider.h" #include "trade.h" @@ -44,11 +43,11 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item, } // Integer field - mItemAmountTextBox = new IntTextBox(1); - mItemAmountTextBox->setRange(1, maxRange); - mItemAmountTextBox->setWidth(30); - mItemAmountTextBox->setActionEventId("Dummy"); - mItemAmountTextBox->addActionListener(this); + mItemAmountTextField = new IntTextField(1); + mItemAmountTextField->setRange(1, maxRange); + mItemAmountTextField->setWidth(30); + mItemAmountTextField->setActionEventId("Dummy"); + mItemAmountTextField->addActionListener(this); // Slider mItemAmountSlide = new Slider(1.0, maxRange); @@ -66,7 +65,7 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item, // Set positions place(0, 0, minusButton); - place(1, 0, mItemAmountTextBox).setPadding(2); + place(1, 0, mItemAmountTextField).setPadding(2); place(2, 0, plusButton); place(0, 1, mItemAmountSlide, 6); place(4, 2, okButton); @@ -75,7 +74,8 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item, resetAmount(); - switch (usage) { + switch (usage) + { case AMOUNT_TRADE_ADD: setCaption(_("Select amount of items to trade.")); okButton->setActionEventId("AddTrade"); @@ -98,12 +98,12 @@ ItemAmountWindow::ItemAmountWindow(int usage, Window *parent, Item *item, void ItemAmountWindow::resetAmount() { - mItemAmountTextBox->setInt(1); + mItemAmountTextField->setValue(1); } void ItemAmountWindow::action(const gcn::ActionEvent &event) { - int amount = mItemAmountTextBox->getInt(); + int amount = mItemAmountTextField->getValue(); if (event.getId() == "Cancel") { @@ -123,19 +123,21 @@ void ItemAmountWindow::action(const gcn::ActionEvent &event) } else if (event.getId() == "Drop") { - player_node->dropItem(mItem, mItemAmountTextBox->getInt()); + player_node->dropItem(mItem, mItemAmountTextField->getValue()); scheduleDelete(); } else if (event.getId() == "AddTrade") { - tradeWindow->tradeItem(mItem, mItemAmountTextBox->getInt()); + tradeWindow->tradeItem(mItem, mItemAmountTextField->getValue()); scheduleDelete(); } +#ifdef TMWSERV_SUPPORT else if (event.getId() == "Split") { - player_node->splitItem(mItem, mItemAmountTextBox->getInt()); + player_node->splitItem(mItem, mItemAmountTextField->getValue()); scheduleDelete(); } - mItemAmountTextBox->setInt(amount); +#endif + mItemAmountTextField->setValue(amount); mItemAmountSlide->setValue(amount); } diff --git a/src/gui/item_amount.h b/src/gui/item_amount.h index c0d2b2c0..4fdb8dc6 100644 --- a/src/gui/item_amount.h +++ b/src/gui/item_amount.h @@ -1,36 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ITEM_AMOUNT_WINDOW_H -#define _TMW_ITEM_AMOUNT_WINDOW_H - -#include <iosfwd> +#ifndef ITEM_AMOUNT_WINDOW_H +#define ITEM_AMOUNT_WINDOW_H #include <guichan/actionlistener.hpp> #include "window.h" -#include "../guichanfwd.h" - -class IntTextBox; +class IntTextField; class Item; #define AMOUNT_TRADE_ADD 1 @@ -61,7 +57,7 @@ class ItemAmountWindow : public Window, public gcn::ActionListener void resetAmount(); private: - IntTextBox *mItemAmountTextBox; /**< Item amount caption. */ + IntTextField *mItemAmountTextField; /**< Item amount caption. */ Item *mItem; /** @@ -70,4 +66,4 @@ class ItemAmountWindow : public Window, public gcn::ActionListener gcn::Slider *mItemAmountSlide; }; -#endif /* _TMW_ITEM_AMOUNT_WINDOW_H */ +#endif /* ITEM_AMOUNT_WINDOW_H */ diff --git a/src/gui/itemcontainer.cpp b/src/gui/itemcontainer.cpp index 4a90510c..bdae9ada 100644 --- a/src/gui/itemcontainer.cpp +++ b/src/gui/itemcontainer.cpp @@ -1,27 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "itemcontainer.h" #include "chat.h" +#include "itempopup.h" + #include <guichan/mouseinput.hpp> #include <guichan/selectionlistener.hpp> @@ -32,12 +34,12 @@ #include "../item.h" #include "../itemshortcut.h" #include "../localplayer.h" +#include "../log.h" #include "../resources/image.h" -#include "../resources/iteminfo.h" #include "../resources/resourcemanager.h" -#include "../utils/tostring.h" +#include "../utils/stringutils.h" // TODO: Add support for adding items to the item shortcut window (global // itemShortcut). @@ -55,10 +57,13 @@ enum }; ItemContainer::ItemContainer(Inventory *inventory, - int gridColumns = 1, int gridRows = 1): + int gridColumns, + int gridRows, + int offset): mInventory(inventory), mGridColumns(gridColumns), mGridRows(gridRows), + mOffset(offset), mSelectedItem(NULL), mHighlightedItem(NULL), mSelectionStatus(SEL_NONE), @@ -71,17 +76,19 @@ ItemContainer::ItemContainer(Inventory *inventory, ResourceManager *resman = ResourceManager::getInstance(); mSelImg = resman->getImage("graphics/gui/selection.png"); + if (!mSelImg) logger->error("Unable to load selection.png"); addKeyListener(this); addMouseListener(this); setSize((BOX_WIDTH - 1) * mGridColumns + 1, - (BOX_HEIGHT - 1) * mGridRows + 1); + (BOX_HEIGHT - 1) * mGridRows + 1); } ItemContainer::~ItemContainer() { mSelImg->decRef(); + delete mItemPopup; } void ItemContainer::draw(gcn::Graphics *graphics) @@ -174,8 +181,7 @@ void ItemContainer::distributeValueChangedEvent() } } -void -ItemContainer::keyPressed(gcn::KeyEvent &event) +void ItemContainer::keyPressed(gcn::KeyEvent &event) { switch (event.getKey().getValue()) { @@ -204,8 +210,7 @@ ItemContainer::keyPressed(gcn::KeyEvent &event) } } -void -ItemContainer::keyReleased(gcn::KeyEvent &event) +void ItemContainer::keyReleased(gcn::KeyEvent &event) { switch (event.getKey().getValue()) { @@ -219,8 +224,7 @@ ItemContainer::keyReleased(gcn::KeyEvent &event) } } -void -ItemContainer::mousePressed(gcn::MouseEvent &event) +void ItemContainer::mousePressed(gcn::MouseEvent &event) { const int button = event.getButton(); if (button == gcn::MouseEvent::LEFT || button == gcn::MouseEvent::RIGHT) @@ -235,7 +239,7 @@ ItemContainer::mousePressed(gcn::MouseEvent &event) // put item name into chat window if (mDescItems) { - chatWindow->addItemText(item->getId(), item->getInfo().getName()); + chatWindow->addItemText(item->getInfo().getName()); } if (mSelectedItem && mSelectedItem == item) @@ -246,6 +250,8 @@ ItemContainer::mousePressed(gcn::MouseEvent &event) { setSelectedItem(item); mSelectionStatus = SEL_SELECTING; + + itemShortcut->setItemSelected(item->getId()); } else { @@ -255,8 +261,7 @@ ItemContainer::mousePressed(gcn::MouseEvent &event) } } -void -ItemContainer::mouseDragged(gcn::MouseEvent &event) +void ItemContainer::mouseDragged(gcn::MouseEvent &event) { if (mSelectionStatus != SEL_NONE) { @@ -297,15 +302,16 @@ void ItemContainer::mouseReleased(gcn::MouseEvent &event) // Show ItemTooltip void ItemContainer::mouseMoved(gcn::MouseEvent &event) { - Item *item = mInventory->getItem( getSlotIndex(event.getX(), event.getY() ) ); + Item *item = mInventory->getItem(getSlotIndex(event.getX(), event.getY())); - if( item ) + if (item) { - mItemPopup->setPosition(getParent()->getParent()->getX() + getParent()->getParent()->getWidth(), getParent()->getParent()->getY()); + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); mItemPopup->setItem(item->getInfo()); - - mItemPopup->setVisible(true); + mItemPopup->setOpaque(false); + mItemPopup->view(mouseX, mouseY); } else { @@ -313,14 +319,6 @@ void ItemContainer::mouseMoved(gcn::MouseEvent &event) } } - -// Show ItemTooltip -void ItemContainer::mouseEntered(gcn::MouseEvent &event) -{ - -} - - // Hide ItemTooltip void ItemContainer::mouseExited(gcn::MouseEvent &event) { diff --git a/src/gui/itemcontainer.h b/src/gui/itemcontainer.h index 7636ef0c..38eaba01 100644 --- a/src/gui/itemcontainer.h +++ b/src/gui/itemcontainer.h @@ -1,39 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ITEMCONTAINER_H__ -#define _TMW_ITEMCONTAINER_H__ +#ifndef ITEMCONTAINER_H +#define ITEMCONTAINER_H + +#include <list> #include <guichan/keylistener.hpp> #include <guichan/mouselistener.hpp> - #include <guichan/widget.hpp> -#include "itempopup.h" - -#include <list> - class Image; class Inventory; class Item; +class ItemPopup; namespace gcn { class SelectionListener; @@ -53,9 +51,11 @@ class ItemContainer : public gcn::Widget, * Constructor. Initializes the graphic. * @param inventory * @param gridColumns Amount of columns in grid. - * @param gridRows Amount of rows in grid. + * @param gridRows Amount of rows in grid. + * @param offset Index offset */ - ItemContainer(Inventory *inventory, int gridColumns, int gridRows); + ItemContainer(Inventory *inventory, int gridColumns, int gridRows, + int offset = 0); /** * Destructor. @@ -95,7 +95,7 @@ class ItemContainer : public gcn::Widget, /** * Returns the selected item. */ - Item* getItem() const + Item* getSelectedItem() const { return mSelectedItem; } /** @@ -133,7 +133,6 @@ class ItemContainer : public gcn::Widget, */ void keyAction(); - void mouseEntered(gcn::MouseEvent &event); void mouseExited(gcn::MouseEvent &event); void mouseMoved(gcn::MouseEvent &event); @@ -150,6 +149,16 @@ class ItemContainer : public gcn::Widget, void setSelectedItem(Item *item); /** + * Find the current item index by the most recently used item ID + */ + void refindSelectedItem(); + + /** + * Determine and set the height of the container. + */ + void recalculateHeight(); + + /** * Sends out selection events to the list of selection listeners. */ void distributeValueChangedEvent(); @@ -161,10 +170,11 @@ class ItemContainer : public gcn::Widget, * @param posY The Y Coordinate position. * @return The slot index on success, -1 on failure. */ - int getSlotIndex(const int posX, const int posY) const; + int getSlotIndex(int posX, int posY) const; Inventory *mInventory; int mGridColumns, mGridRows; + int mOffset; Image *mSelImg; Item *mSelectedItem, *mHighlightedItem; int mSelectionStatus; diff --git a/src/gui/itemlinkhandler.cpp b/src/gui/itemlinkhandler.cpp index bdfa2ca6..4060b303 100644 --- a/src/gui/itemlinkhandler.cpp +++ b/src/gui/itemlinkhandler.cpp @@ -1,33 +1,35 @@ /* * The Mana World - * Copyright 2009 The Mana World Development Team + * Copyright (C) 2009 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <sstream> +#include <string> + +#include <SDL_mouse.h> + #include "itemlinkhandler.h" #include "itempopup.h" #include "../resources/iteminfo.h" #include "../resources/itemdb.h" -#include <sstream> -#include <string> - ItemLinkHandler::ItemLinkHandler() { mItemPopup = new ItemPopup; @@ -47,14 +49,15 @@ void ItemLinkHandler::handleLink(const std::string &link) if (id > 0) { const ItemInfo &iteminfo = ItemDB::get(id); + int mouseX, mouseY; + + SDL_GetMouseState(&mouseX, &mouseY); + mItemPopup->setItem(iteminfo); + if (mItemPopup->isVisible()) - { mItemPopup->setVisible(false); - } else - { - mItemPopup->setVisible(true); - } + mItemPopup->view(mouseX, mouseY); } } diff --git a/src/gui/itemlinkhandler.h b/src/gui/itemlinkhandler.h index 973aab75..c04afa9e 100644 --- a/src/gui/itemlinkhandler.h +++ b/src/gui/itemlinkhandler.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2009 The Mana World Development Team + * Copyright (C) 2009 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ITEM_LINK_HANDLER_H_ -#define _TMW_ITEM_LINK_HANDLER_H_ +#ifndef ITEM_LINK_HANDLER_H +#define ITEM_LINK_HANDLER_H #include "linkhandler.h" diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp index 7a662151..25e6e78e 100644 --- a/src/gui/itempopup.cpp +++ b/src/gui/itempopup.cpp @@ -5,107 +5,216 @@ * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "itempopup.h" +#include <guichan/font.hpp> + #include <guichan/widgets/label.hpp> -#include "widgets/layout.h" #include "gui.h" +#include "itempopup.h" +#include "scrollarea.h" +#include "textbox.h" +#include "windowcontainer.h" + +#include "widgets/layout.h" + +#include "../units.h" -#include "../resources/image.h" -#include "../resources/resourcemanager.h" #include "../resources/iteminfo.h" -#include "../utils/gettext.h" -#include "../utils/strprintf.h" +#include "../utils/gettext.h" +#include "../utils/stringutils.h" -ItemPopup::ItemPopup() +ItemPopup::ItemPopup(): + Window() { - setResizable(false); + setShowTitle(false); setTitleBarHeight(0); - loadSkin("graphics/gui/gui.xml"); // Item Name mItemName = new gcn::Label("Label"); - mItemName->setFont(gui->getFont()); + mItemName->setFont(boldFont); mItemName->setPosition(2, 2); - mItemName->setWidth(getWidth() - 4); // Item Description - mItemDesc = new TextBox(); + 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->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight())); mItemDescScroll->setOpaque(false); - mItemDescScroll->setPosition(2, 15); + mItemDescScroll->setPosition(2, getFont()->getHeight()); // Item Effect - mItemEffect = new TextBox(); + 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->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight())); mItemEffectScroll->setOpaque(false); - mItemEffectScroll->setPosition(2, 35); + mItemEffectScroll->setPosition(2, (2 * getFont()->getHeight()) + 5); + + // Item Weight + mItemWeight = new TextBox; + mItemWeight->setEditable(false); + mItemWeightScroll = new ScrollArea(mItemWeight); + + mItemWeightScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemWeightScroll->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mItemWeightScroll->setDimension(gcn::Rectangle(0, 0, 196, getFont()->getHeight())); + mItemWeightScroll->setOpaque(false); + mItemWeightScroll->setPosition(2, (3 * getFont()->getHeight()) + 10); add(mItemName); add(mItemDescScroll); add(mItemEffectScroll); + add(mItemWeightScroll); setLocationRelativeTo(getParent()); +} - // LEEOR / TODO: This causes an exception error. - //moveToBottom(getParent()); - - mItemDesc->setTextWrapped( "" ); - mItemEffect->setTextWrapped( "" ); +ItemPopup::~ItemPopup() +{ + delete mItemName; + delete mItemDesc; + delete mItemDescScroll; + delete mItemEffect; + delete mItemEffectScroll; + delete mItemWeight; + delete mItemWeightScroll; } void ItemPopup::setItem(const ItemInfo &item) { mItemName->setCaption(item.getName()); - mItemDesc->setTextWrapped(item.getDescription()); - mItemEffect->setTextWrapped(item.getEffect()); +#ifdef EATHENA_SUPPORT + mItemName->setForegroundColor(getColor(item.getType())); +#endif + mItemName->setWidth(boldFont->getWidth(item.getName())); + mItemDesc->setTextWrapped(item.getDescription(), 196); + mItemEffect->setTextWrapped(item.getEffect(), 196); + mItemWeight->setTextWrapped(_("Weight: ") + + Units::formatWeight(item.getWeight()), 196); + + int minWidth = mItemName->getWidth(); + + if (mItemDesc->getMinWidth() > minWidth) + minWidth = mItemDesc->getMinWidth(); + if (mItemEffect->getMinWidth() > minWidth) + minWidth = mItemEffect->getMinWidth(); + if (mItemWeight->getMinWidth() > minWidth) + minWidth = mItemWeight->getMinWidth(); + + minWidth += 8; + setWidth(minWidth); int numRowsDesc = mItemDesc->getNumberOfRows(); int numRowsEffect = mItemEffect->getNumberOfRows(); + int numRowsWeight = mItemWeight->getNumberOfRows(); - if(item.getEffect() == "") - { - setContentSize(200, (numRowsDesc * 14) + 30); - } else { - setContentSize(200, (numRowsDesc * 14) + (numRowsEffect*14) + 30); - } + mItemDescScroll->setDimension(gcn::Rectangle(2, 0, minWidth, + numRowsDesc * getFont()->getHeight())); - mItemDescScroll->setDimension(gcn::Rectangle(2, 0, 196, numRowsDesc * 14)); + mItemEffectScroll->setDimension(gcn::Rectangle(2, 0, minWidth, + numRowsEffect * getFont()->getHeight())); - mItemEffectScroll->setDimension(gcn::Rectangle(2, 0, 196, numRowsEffect * 14)); + mItemWeightScroll->setDimension(gcn::Rectangle(2, 0, minWidth, + numRowsWeight * getFont()->getHeight())); + + if (item.getEffect().empty()) + { + setContentSize(minWidth, (numRowsDesc * getFont()->getHeight() + + (3 * getFont()->getHeight()))); + + mItemWeightScroll->setPosition(2, + (numRowsDesc * getFont()->getHeight()) + + (2 * getFont()->getHeight())); + } + else + { + setContentSize(minWidth, (numRowsDesc * getFont()->getHeight()) + + (numRowsEffect * getFont()->getHeight()) + + (3 * getFont()->getHeight())); + + mItemWeightScroll->setPosition(2, + (numRowsDesc * getFont()->getHeight()) + + (numRowsEffect * getFont()->getHeight()) + + (2 * getFont()->getHeight())); + } mItemDescScroll->setPosition(2, 20); - mItemEffectScroll->setPosition(2, (numRowsDesc * 15) + 25); + mItemEffectScroll->setPosition(2, (numRowsDesc * getFont()->getHeight()) + + (2 * getFont()->getHeight())); +} + +gcn::Color ItemPopup::getColor(const std::string& type) +{ + gcn::Color color; + + if (type.compare("generic") == 0) + color = 0x21a5b1; + else if (type.compare("equip-head") == 0) + color = 0x527fa4; + else if (type.compare("usable") == 0) + color = 0x268d24; + else if (type.compare("equip-torso") == 0) + color = 0xd12aa4; + else if (type.compare("equip-1hand") == 0) + color = 0xf42a2a; + else if (type.compare("equip-legs") == 0) + color = 0x699900; + else if (type.compare("equip-feet") == 0) + color = 0xaa1d48; + else if (type.compare("equip-2hand") == 0) + color = 0xf46d0e; + else if (type.compare("equip-shield") == 0) + color = 0x9c2424; + else if (type.compare("equip-ring") == 0) + color = 0x0000ff; + else if (type.compare("equip-arms") == 0) + color = 0x9c24e8; + else if (type.compare("equip-ammo") == 0) + color = 0x8b6311; + else + color = 0x000000; + + return color; } unsigned int ItemPopup::getNumRows() { - return mItemDesc->getNumberOfRows(), mItemEffect->getNumberOfRows(); + return mItemDesc->getNumberOfRows() + mItemEffect->getNumberOfRows() + + mItemWeight->getNumberOfRows(); +} + +void ItemPopup::view(int x, int y) +{ + if (windowContainer->getWidth() < (x + getWidth() + 5)) + x = windowContainer->getWidth() - getWidth(); + if ((y - getHeight() - 10) < 0) + y = 0; + else + y = y - getHeight() - 10; + setPosition(x, y); + setVisible(true); + requestMoveToTop(); } diff --git a/src/gui/itempopup.h b/src/gui/itempopup.h index 8da0b32a..c820e3a0 100644 --- a/src/gui/itempopup.h +++ b/src/gui/itempopup.h @@ -5,44 +5,50 @@ * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ITEMPOPUP_H__ -#define _TMW_ITEMPOPUP_H__ +#ifndef ITEMPOPUP_H +#define ITEMPOPUP_H -#include "textbox.h" -#include "scrollarea.h" #include "window.h" -#include "../item.h" +class ItemInfo; +class ScrollArea; +class TextBox; class ItemPopup : public Window { public: ItemPopup(); + ~ItemPopup(); void setItem(const ItemInfo &item); unsigned int getNumRows(); + void view(int x, int y); private: gcn::Label *mItemName; TextBox *mItemDesc; TextBox *mItemEffect; + TextBox *mItemWeight; ScrollArea *mItemDescScroll; ScrollArea *mItemEffectScroll; + ScrollArea *mItemWeightScroll; + + gcn::Color getColor(const std::string& type); }; -#endif // _TMW_ITEMPOPUP_H__ +#endif // ITEMPOPUP_H diff --git a/src/gui/itemshortcutcontainer.cpp b/src/gui/itemshortcutcontainer.cpp index e0604c78..8864cbd9 100644 --- a/src/gui/itemshortcutcontainer.cpp +++ b/src/gui/itemshortcutcontainer.cpp @@ -1,62 +1,70 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <SDL_mouse.h> #include "itemshortcutcontainer.h" +#include "itempopup.h" +#include "viewport.h" -#include "../localplayer.h" +#include "../configuration.h" #include "../graphics.h" +#include "../inventory.h" #include "../item.h" #include "../itemshortcut.h" #include "../keyboardconfig.h" +#include "../localplayer.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" -#include "../utils/tostring.h" +#include "../utils/stringutils.h" ItemShortcutContainer::ItemShortcutContainer(): - mGridWidth(1), - mGridHeight(1), + ShortcutContainer(), mItemClicked(false), mItemMoved(NULL) { addMouseListener(this); addWidgetListener(this); + mItemPopup = new ItemPopup; + ResourceManager *resman = ResourceManager::getInstance(); mBackgroundImg = resman->getImage("graphics/gui/item_shortcut_bgr.png"); mMaxItems = itemShortcut->getItemCount(); - mBoxHeight = 42; - mBoxWidth = 36; + mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8)); + + mBoxHeight = mBackgroundImg->getHeight(); + mBoxWidth = mBackgroundImg->getWidth(); } ItemShortcutContainer::~ItemShortcutContainer() { mBackgroundImg->decRef(); + delete mItemPopup; } -void -ItemShortcutContainer::logic() +void ItemShortcutContainer::logic() { gcn::Widget::logic(); @@ -69,11 +77,11 @@ ItemShortcutContainer::logic() } } -void -ItemShortcutContainer::draw(gcn::Graphics *graphics) +void ItemShortcutContainer::draw(gcn::Graphics *graphics) { Graphics *g = static_cast<Graphics*>(graphics); + graphics->setColor(gcn::Color(0, 0, 0)); graphics->setFont(getFont()); for (int i = 0; i < mMaxItems; i++) @@ -85,19 +93,27 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics) // Draw item keyboard shortcut. const char *key = SDL_GetKeyName( - (SDLKey) keyboard.getKeyValue(keyboard.KEY_SHORTCUT_0 + i)); + (SDLKey) keyboard.getKeyValue(keyboard.KEY_SHORTCUT_1 + i)); + graphics->setColor(0x000000); g->drawText(key, itemX + 2, itemY + 2, gcn::Graphics::LEFT); if (itemShortcut->getItem(i) < 0) continue; - Item *item = player_node->searchForItem(itemShortcut->getItem(i)); - if (item) { + Item *item = + player_node->getInventory()->findItem(itemShortcut->getItem(i)); + if (item) + { // Draw item icon. Image* image = item->getImage(); - if (image) { - // TODO: Have label indicate equipped status - const std::string label = toString(item->getQuantity()); + + if (image) + { + const std::string label = +#ifdef EATHENA_SUPPORT + item->isEquipped() ? "Eq." : +#endif + toString(item->getQuantity()); g->drawImage(image, itemX, itemY); g->drawText( label, @@ -124,36 +140,30 @@ ItemShortcutContainer::draw(gcn::Graphics *graphics) gcn::Graphics::CENTER); } } -} - -void ItemShortcutContainer::widgetResized(const gcn::Event &event) -{ - mGridWidth = getWidth() / mBoxWidth; - if (mGridWidth < 1) { - mGridWidth = 1; - } - - setHeight((mMaxItems / mGridWidth + - (mMaxItems % mGridWidth > 0 ? 1 : 0)) * mBoxHeight); - mGridHeight = getHeight() / mBoxHeight; - if (mGridHeight < 1) { - mGridHeight = 1; + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mBackgroundImg->setAlpha(config.getValue("guialpha", 0.8)); } } -void -ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) +void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) { - if (event.getButton() == gcn::MouseEvent::LEFT) { - if (!mItemMoved && mItemClicked) { + if (event.getButton() == gcn::MouseEvent::LEFT) + { + if (!mItemMoved && mItemClicked) + { const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) { + const int itemId = itemShortcut->getItem(index); + + if (index == -1) return; - } - if (itemShortcut->getItem(index) < 0) + + if (itemId < 0) return; - Item *item = player_node->searchForItem(itemShortcut->getItem(index)); + + Item *item = player_node->getInventory()->findItem(itemId); + if (item) { mItemMoved = item; @@ -167,39 +177,56 @@ ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) } } -void -ItemShortcutContainer::mousePressed(gcn::MouseEvent &event) +void ItemShortcutContainer::mousePressed(gcn::MouseEvent &event) { const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) { + if (index == -1) return; - } - // Stores the selected item if theirs one. - if (itemShortcut->isItemSelected()) { - itemShortcut->setItem(index); - itemShortcut->setItemSelected(-1); + if (event.getButton() == gcn::MouseEvent::LEFT) + { + + // Stores the selected item if theirs one. + if (itemShortcut->isItemSelected()) + { + itemShortcut->setItem(index); + itemShortcut->setItemSelected(-1); + } + else if (itemShortcut->getItem(index)) + mItemClicked = true; } - else if (itemShortcut->getItem(index)) { - mItemClicked = true; + else if (event.getButton() == gcn::MouseEvent::RIGHT) + { + Item *item = player_node->getInventory()-> + findItem(itemShortcut->getItem(index)); + + if (!item) + return; + + /* Convert relative to the window coordinates to absolute screen + * coordinates. + */ + int mx, my; + SDL_GetMouseState(&mx, &my); + viewport->showPopup(mx, my, item); } } -void -ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) +void ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) { if (event.getButton() == gcn::MouseEvent::LEFT) { if (itemShortcut->isItemSelected()) - { itemShortcut->setItemSelected(-1); - } + const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) { + if (index == -1) + { mItemMoved = NULL; return; } - if (mItemMoved) { + if (mItemMoved) + { itemShortcut->setItems(index, mItemMoved->getId()); mItemMoved = NULL; } @@ -207,25 +234,43 @@ ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) { itemShortcut->useItem(index); } - if (mItemClicked) { + if (mItemClicked) mItemClicked = false; - } } } -int -ItemShortcutContainer::getIndexFromGrid(int pointX, int pointY) const +// Show ItemTooltip +void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event) { - const gcn::Rectangle tRect = gcn::Rectangle( - 0, 0, mGridWidth * mBoxWidth, mGridHeight * mBoxHeight); - if (!tRect.isPointInRect(pointX, pointY)) { - return -1; + const int index = getIndexFromGrid(event.getX(), event.getY()); + const int itemId = itemShortcut->getItem(index); + + if (index == -1) + return; + + if (itemId < 0) + return; + + Item *item = player_node->getInventory()->findItem(itemId); + + if (item) + { + int mouseX, mouseY; + SDL_GetMouseState(&mouseX, &mouseY); + + mItemPopup->setItem(item->getInfo()); + mItemPopup->setOpaque(false); + mItemPopup->view(mouseX, mouseY); } - const int index = ((pointY / mBoxHeight) * mGridWidth) + - pointX / mBoxWidth; - if (index >= mMaxItems) + else { - return -1; + mItemPopup->setVisible(false); } - return index; } + +// Hide ItemTooltip +void ItemShortcutContainer::mouseExited(gcn::MouseEvent &event) +{ + mItemPopup->setVisible(false); +} + diff --git a/src/gui/itemshortcutcontainer.h b/src/gui/itemshortcutcontainer.h index 76ca870c..22d94ec2 100644 --- a/src/gui/itemshortcutcontainer.h +++ b/src/gui/itemshortcutcontainer.h @@ -1,42 +1,41 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ITEMSHORTCUTCONTAINER_H__ -#define _TMW_ITEMSHORTCUTCONTAINER_H__ +#ifndef ITEMSHORTCUTCONTAINER_H +#define ITEMSHORTCUTCONTAINER_H #include <guichan/mouselistener.hpp> -#include <guichan/widget.hpp> -#include <guichan/widgetlistener.hpp> + +#include "shortcutcontainer.h" class Image; class Item; +class ItemPopup; /** * An item shortcut container. Used to quickly use items. * * \ingroup GUI */ -class ItemShortcutContainer : public gcn::Widget, - public gcn::WidgetListener, - public gcn::MouseListener +class ItemShortcutContainer : public ShortcutContainer { public: /** @@ -60,12 +59,6 @@ class ItemShortcutContainer : public gcn::Widget, void draw(gcn::Graphics *graphics); /** - * Invoked when a widget changes its size. This is used to determine - * the new height of the container. - */ - void widgetResized(const gcn::Event &event); - - /** * Handles mouse when dragged. */ void mouseDragged(gcn::MouseEvent &event); @@ -80,34 +73,14 @@ class ItemShortcutContainer : public gcn::Widget, */ void mouseReleased(gcn::MouseEvent &event); - int getMaxItems() - { return mMaxItems; } - - int getBoxWidth() - { return mBoxWidth; } - - int getBoxHeight() - { return mBoxHeight; } - private: - /** - * Gets the index from the grid provided the point is in an item box. - * - * @param pointX X coordinate of the point. - * @param pointY Y coordinate of the point. - * @return index on success, -1 on failure. - */ - int getIndexFromGrid(int pointX, int pointY) const; + void mouseExited(gcn::MouseEvent &event); + void mouseMoved(gcn::MouseEvent &event); - Image *mBackgroundImg; - - int mMaxItems; - int mBoxWidth; - int mBoxHeight; - int mCursorPosX, mCursorPosY; - int mGridWidth, mGridHeight; bool mItemClicked; Item *mItemMoved; + + ItemPopup *mItemPopup; }; #endif diff --git a/src/gui/linkhandler.h b/src/gui/linkhandler.h index 44f906db..fc9da6da 100644 --- a/src/gui/linkhandler.h +++ b/src/gui/linkhandler.h @@ -1,26 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_LINK_HANDLER_H_ -#define _TMW_LINK_HANDLER_H_ +#ifndef LINK_HANDLER_H +#define LINK_HANDLER_H + +#include <string> #include <string> diff --git a/src/gui/listbox.cpp b/src/gui/listbox.cpp index 204d7961..74d0b9ad 100644 --- a/src/gui/listbox.cpp +++ b/src/gui/listbox.cpp @@ -1,70 +1,74 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "listbox.h" - #include <guichan/font.hpp> #include <guichan/graphics.hpp> #include <guichan/listmodel.hpp> -#include <guichan/mouseinput.hpp> + +#include "color.h" +#include "listbox.h" + +#include "../configuration.h" + +float ListBox::mAlpha = config.getValue("guialpha", 0.8); ListBox::ListBox(gcn::ListModel *listModel): gcn::ListBox(listModel) { } -ListBox::ListBox(): - gcn::ListBox() -{ - -} - void ListBox::draw(gcn::Graphics *graphics) { if (!mListModel) return; - graphics->setColor(gcn::Color(110, 160, 255)); + if (config.getValue("guialpha", 0.8) != mAlpha) + mAlpha = config.getValue("guialpha", 0.8); + + bool valid; + const int red = (textColor->getColor('H', valid) >> 16) & 0xFF; + const int green = (textColor->getColor('H', valid) >> 8) & 0xFF; + const int blue = textColor->getColor('H', valid) & 0xFF; + const int alpha = (int)(mAlpha * 255.0f); + + graphics->setColor(gcn::Color(red, green, blue, alpha)); graphics->setFont(getFont()); - int fontHeight = getFont()->getHeight(); + const int fontHeight = getFont()->getHeight(); // Draw rectangle below the selected list element - if (mSelected >= 0) { + if (mSelected >= 0) graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected, getWidth(), fontHeight)); - } // Draw the list elements - graphics->setColor(gcn::Color(0, 0, 0)); - for (int i = 0, y = 0; - i < mListModel->getNumberOfElements(); + graphics->setColor(gcn::Color(0, 0, 0, 255)); + for (int i = 0, y = 0; i < mListModel->getNumberOfElements(); ++i, y += fontHeight) { graphics->drawText(mListModel->getElementAt(i), 1, y); } } -void -ListBox::mouseDragged(gcn::MouseEvent &event) +void ListBox::mouseDragged(gcn::MouseEvent &event) { // Pretend mouse is pressed continuously while dragged. Causes list // selection to be updated as is default in many GUIs. diff --git a/src/gui/listbox.h b/src/gui/listbox.h index d42c7d3e..12fcb955 100644 --- a/src/gui/listbox.h +++ b/src/gui/listbox.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_LISTBOX_H -#define _TMW_LISTBOX_H +#ifndef LISTBOX_H +#define LISTBOX_H #include <guichan/widgets/listbox.hpp> @@ -40,7 +40,6 @@ class ListBox : public gcn::ListBox * Constructor. */ ListBox(gcn::ListModel *listModel); - ListBox(); /** * Draws the list box. @@ -48,6 +47,9 @@ class ListBox : public gcn::ListBox void draw(gcn::Graphics *graphics); void mouseDragged(gcn::MouseEvent &event); + + private: + static float mAlpha; }; #endif diff --git a/src/gui/login.cpp b/src/gui/login.cpp index 615045b6..e68a8da1 100644 --- a/src/gui/login.cpp +++ b/src/gui/login.cpp @@ -1,72 +1,127 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "login.h" - -#include <string> - #include <guichan/widgets/label.hpp> -#include "../main.h" -#include "../logindata.h" - #include "button.h" #include "checkbox.h" +#include "listbox.h" +#include "login.h" #include "ok_dialog.h" #include "passwordfield.h" +#include "scrollarea.h" #include "textfield.h" +#include "widgets/dropdown.h" #include "widgets/layout.h" +#include "../main.h" +#include "../logindata.h" +#include "../configuration.h" + #include "../utils/gettext.h" +#include "../utils/stringutils.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:")); +#ifdef EATHENA_SUPPORT + gcn::Label *serverLabel = new gcn::Label(_("Server:")); + gcn::Label *portLabel = new gcn::Label(_("Port:")); + gcn::Label *dropdownLabel = new gcn::Label(_("Recent:")); + std::vector<std::string> dfltServer; + dfltServer.push_back("server.themanaworld.org"); + std::vector<std::string> dfltPort; + dfltPort.push_back("6901"); + mServerList = new DropDownList("MostRecent00", dfltServer, dfltPort, + MAX_SERVER_LIST_SIZE); + mServerListBox = new ListBox(mServerList); + mServerScrollArea = new ScrollArea; +#endif + mUserField = new TextField(mLoginData->username); mPassField = new PasswordField(mLoginData->password); +#ifdef EATHENA_SUPPORT + mServerField = new TextField(mServerList->getServerAt(0)); + mPortField = new TextField(mServerList->getPortAt(0)); + mServerDropDown = new DropDown(mServerList, + mServerScrollArea, + mServerListBox); + mServerDropDown->setOpaque(false); +#endif + mKeepCheck = new CheckBox(_("Remember Username"), mLoginData->remember); - mOkButton = new Button(_("Ok"), "ok", this); + mOkButton = new Button(_("OK"), "ok", this); mCancelButton = new Button(_("Cancel"), "cancel", this); mRegisterButton = new Button(_("Register"), "register", this); mUserField->setActionEventId("ok"); mPassField->setActionEventId("ok"); +#ifdef EATHENA_SUPPORT + mServerField->setActionEventId("ok"); + mPortField->setActionEventId("ok"); + mServerDropDown->setActionEventId("changeSelection"); +#endif mUserField->addKeyListener(this); mPassField->addKeyListener(this); +#ifdef EATHENA_SUPPORT + mServerField->addKeyListener(this); + mPortField->addKeyListener(this); + mServerDropDown->addKeyListener(this); +#endif mUserField->addActionListener(this); mPassField->addActionListener(this); +#ifdef EATHENA_SUPPORT + mServerField->addActionListener(this); + mPortField->addActionListener(this); + mServerDropDown->addActionListener(this); mKeepCheck->addActionListener(this); +#endif place(0, 0, userLabel); place(0, 1, passLabel); - place(1, 0, mUserField, 3).setPadding(2); - place(1, 1, mPassField, 3).setPadding(2); - place(0, 2, mKeepCheck, 4); - place(0, 3, mRegisterButton).setHAlign(LayoutCell::LEFT); - place(2, 3, mOkButton); - place(3, 3, mCancelButton); +#ifdef EATHENA_SUPPORT + place(0, 2, serverLabel); + place(0, 3, portLabel); + place(0, 4, dropdownLabel); +#endif + place(1, 0, mUserField, 3).setPadding(1); + place(1, 1, mPassField, 3).setPadding(1); +#ifdef EATHENA_SUPPORT + place(1, 2, mServerField, 3).setPadding(1); + place(1, 3, mPortField, 3).setPadding(1); + place(1, 4, mServerDropDown, 3).setPadding(1); +#endif + place(0, 5, mKeepCheck, 4); + place(0, 6, mRegisterButton).setHAlign(LayoutCell::LEFT); + place(2, 6, mCancelButton); + place(3, 6, mOkButton); reflowLayout(250, 0); setLocationRelativeTo(getParent()); @@ -81,14 +136,14 @@ LoginDialog::LoginDialog(LoginData *loginData): mOkButton->setEnabled(canSubmit()); } -LoginDialog::~LoginDialog() -{ -} - void LoginDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "ok" && canSubmit()) { +#ifdef EATHENA_SUPPORT + mLoginData->hostname = mServerField->getText(); + mLoginData->port = getUShort(mPortField->getText()); +#endif mLoginData->username = mUserField->getText(); mLoginData->password = mPassField->getText(); mLoginData->remember = mKeepCheck->isSelected(); @@ -96,16 +151,43 @@ void LoginDialog::action(const gcn::ActionEvent &event) mOkButton->setEnabled(false); mRegisterButton->setEnabled(false); - +#ifdef EATHENA_SUPPORT + mServerList->save(mServerField->getText(), mPortField->getText()); + state = STATE_ACCOUNT; +#else state = STATE_LOGIN_ATTEMPT; +#endif } +#ifdef EATHENA_SUPPORT + else if (event.getId() == "changeSelection") + { + int selected = mServerListBox->getSelected(); + mServerField->setText(mServerList->getServerAt(selected)); + mPortField->setText(mServerList->getPortAt(selected)); + } +#endif else if (event.getId() == "cancel") { +#ifdef TMWSERV_SUPPORT state = STATE_SWITCH_ACCOUNTSERVER; +#else + state = STATE_EXIT; +#endif } else if (event.getId() == "register") { +#ifdef EATHENA_SUPPORT // 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; + } +#endif mLoginData->username = mUserField->getText(); mLoginData->password = mPassField->getText(); @@ -122,5 +204,143 @@ bool LoginDialog::canSubmit() { return !mUserField->getText().empty() && !mPassField->getText().empty() && +#ifdef EATHENA_SUPPORT + !mServerField->getText().empty() && + isUShort(mPortField->getText()) && +#endif state == STATE_LOGIN; } + +#ifdef EATHENA_SUPPORT +bool LoginDialog::isUShort(const std::string &str) +{ + if (str.empty()) + { + return false; + } + unsigned long l = 0; + for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end(); + strPtr != strEnd; ++strPtr) + { + if (*strPtr < '0' || *strPtr > '9') + { + return false; + } + l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative + if (l > 65535) + { + return false; + } + } + return true; +} + +unsigned short LoginDialog::getUShort(const std::string &str) +{ + unsigned long l = 0; + for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end(); + strPtr != strEnd; ++strPtr) + { + l = l * 10 + (*strPtr - '0'); + } + return static_cast<unsigned short>(l); +} + +/** + * LoginDialog::DropDownList + */ + +void LoginDialog::DropDownList::saveEntry(const std::string &server, + const std::string &port, int &saved) +{ + if (saved < MAX_SERVER_LIST_SIZE && !server.empty()) + { + config.setValue(mConfigPrefix + "Server" + toString(saved), server); + config.setValue(mConfigPrefix + "Port" + toString(saved), port); + ++saved; + } +} + +LoginDialog::DropDownList::DropDownList(std::string prefix, + std::vector<std::string> dflt, + std::vector<std::string> dfltPort, + int maxEntries) : + mConfigPrefix(prefix), + mMaxEntries(maxEntries) +{ + for (int i = 0; i < maxEntries; ++i) + { + std::string server = config.getValue(mConfigPrefix + "Server" + + toString(i), ""); + if (server.empty()) // Just in case had original config entries + { + server = config.getValue(mConfigPrefix + "ServerList" + + toString(i), ""); + } + std::string port = config.getValue(mConfigPrefix + "Port" + + toString(i), dfltPort.front()); + + if (!server.empty()) + { + mServers.push_back(server); + mPorts.push_back(port); + } + } + if (mServers.empty()) + { + mServers.assign(dflt.begin(), dflt.end()); + mPorts.assign(dfltPort.begin(), dfltPort.end()); + } +} + +void LoginDialog::DropDownList::save(const std::string &server, + const std::string &port) +{ + int position = 0; + saveEntry(server, port, position); + for (std::vector<std::string>::const_iterator sPtr = mServers.begin(), + sEnd = mServers.end(), + pPtr = mPorts.begin(), + pEnd = mPorts.end(); + sPtr != sEnd && pPtr != pEnd; + ++sPtr, ++pPtr) + { + if (*sPtr != server || *pPtr != port) + { + saveEntry(*sPtr, *pPtr, position); + } + } +} + +int LoginDialog::DropDownList::getNumberOfElements() +{ + return mServers.size(); +} + +std::string LoginDialog::DropDownList::getElementAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return getServerAt(i) + ":" + getPortAt(i); +} + +std::string LoginDialog::DropDownList::getServerAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return mServers.at(i); +} + +std::string LoginDialog::DropDownList::getPortAt(int i) +{ + if (i < 0 || i >= getNumberOfElements()) + { + return ""; + } + return mPorts.at(i); +} +#endif diff --git a/src/gui/login.h b/src/gui/login.h index 1c23a0f5..9a97cd4d 100644 --- a/src/gui/login.h +++ b/src/gui/login.h @@ -1,35 +1,43 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_LOGIN_H -#define _TMW_LOGIN_H +#ifndef LOGIN_H +#define LOGIN_H + +#include <string> +#include <vector> -#include <iosfwd> #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> +#ifdef EATHENA_SUPPORT +#include <guichan/listmodel.hpp> +#endif #include "window.h" -#include "../guichanfwd.h" class LoginData; +#ifdef EATHENA_SUPPORT +class DropDown; +class ScrollArea; +#endif /** * The login dialog. @@ -48,11 +56,6 @@ class LoginDialog : public Window, public gcn::ActionListener, LoginDialog(LoginData *loginData); /** - * Destructor - */ - ~LoginDialog(); - - /** * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); @@ -67,17 +70,71 @@ class LoginDialog : public Window, public gcn::ActionListener, * Returns whether submit can be enabled. This is true in the login * state, when all necessary fields have some text. */ - bool - canSubmit(); + bool canSubmit(); + +#ifdef EATHENA_SUPPORT + /** + * 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); + +#endif gcn::TextField *mUserField; gcn::TextField *mPassField; +#ifdef EATHENA_SUPPORT + gcn::TextField *mServerField; + gcn::TextField *mPortField; + DropDown *mServerDropDown; +#endif gcn::CheckBox *mKeepCheck; gcn::Button *mOkButton; gcn::Button *mCancelButton; gcn::Button *mRegisterButton; LoginData *mLoginData; + +#ifdef EATHENA_SUPPORT + /** + * Helper class to keep a list of all the recent entries for the + * dropdown + */ + class DropDownList : public gcn::ListModel + { + private: + std::vector<std::string> mServers; + std::vector<std::string> mPorts; + std::string mConfigPrefix; + int mMaxEntries; + void saveEntry(const std::string &server, + const std::string &port, int &saved); + public: + DropDownList(std::string prefix, + std::vector<std::string> dfltServer, + std::vector<std::string> dfltPort, + int maxEntries); + void save(const std::string &server, const std::string &port); + int getNumberOfElements(); + std::string getElementAt(int i); + std::string getServerAt(int i); + std::string getPortAt(int i); + }; + DropDownList *mServerList; + gcn::ListBox *mServerListBox; + gcn::ScrollArea *mServerScrollArea; +#endif }; #endif diff --git a/src/gui/magic.cpp b/src/gui/magic.cpp index 2c81321b..0e56e853 100644 --- a/src/gui/magic.cpp +++ b/src/gui/magic.cpp @@ -29,7 +29,6 @@ #include "../localplayer.h" #include "../utils/dtor.h" -#include "../utils/tostring.h" #include "../utils/gettext.h" MagicDialog::MagicDialog(): diff --git a/src/gui/menuwindow.cpp b/src/gui/menuwindow.cpp index 9415188e..25ece461 100644 --- a/src/gui/menuwindow.cpp +++ b/src/gui/menuwindow.cpp @@ -1,44 +1,47 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "menuwindow.h" - #include <string> #include <guichan/actionlistener.hpp> #include "button.h" +#include "menuwindow.h" #include "windowcontainer.h" #include "../utils/gettext.h" -extern Window *setupWindow; -extern Window *inventoryWindow; +extern Window *chatWindow; extern Window *equipmentWindow; +extern Window *inventoryWindow; +extern Window *itemShortcutWindow; +extern Window *emoteWindow; +extern Window *setupWindow; extern Window *skillDialog; -extern Window *magicDialog; extern Window *statusWindow; -extern Window *guildWindow; -extern Window *itemShortcutWindow; +#ifdef TMWSERV_SUPPORT extern Window *buddyWindow; +extern Window *guildWindow; +extern Window *magicDialog; +#endif namespace { struct MenuWindowListener : public gcn::ActionListener @@ -54,20 +57,25 @@ MenuWindow::MenuWindow(): Window() { setResizable(false); + setWindowName("Menu"); setMovable(false); setTitleBarHeight(0); // Buttons static const char *buttonNames[] = { + N_("Chat"), N_("Status"), N_("Equipment"), N_("Inventory"), N_("Skills"), +#ifdef TMWSERV_SUPPORT N_("Magic"), N_("Guilds"), N_("Buddys"), +#endif N_("Shortcut"), + N_("Emote"), N_("Setup"), 0 }; @@ -96,7 +104,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; } @@ -112,6 +124,7 @@ void MenuWindowListener::action(const gcn::ActionEvent &event) { window = skillDialog; } +#ifdef TMWSERV_SUPPORT else if (event.getId() == "Magic") { window = magicDialog; @@ -124,10 +137,15 @@ void MenuWindowListener::action(const gcn::ActionEvent &event) { window = buddyWindow; } +#endif else if (event.getId() == "Shortcut") { window = itemShortcutWindow; } + else if (event.getId() == "Emote") + { + window = emoteWindow; + } else if (event.getId() == "Setup") { window = setupWindow; diff --git a/src/gui/menuwindow.h b/src/gui/menuwindow.h index 03ec3380..9bb54e29 100644 --- a/src/gui/menuwindow.h +++ b/src/gui/menuwindow.h @@ -1,31 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MENU_H -#define _TMW_MENU_H +#ifndef MENU_H +#define MENU_H #include "window.h" -#include "../guichanfwd.h" - /** * The Button Menu. * diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index f7749755..4347c9cc 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -1,28 +1,31 @@ /* * The Mana World - * Copyright 2004-2005 The Mana World Development Team + * Copyright (C) 2004-2005 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <guichan/font.hpp> + #include "minimap.h" #include "../being.h" #include "../beingmanager.h" +#include "../configuration.h" #include "../graphics.h" #include "../localplayer.h" @@ -30,22 +33,27 @@ #include "../utils/gettext.h" +bool Minimap::mShow = true; + Minimap::Minimap(): Window(_("MiniMap")), - mMapImage(NULL) + mMapImage(NULL), + mProportion(0.5) { setWindowName("MiniMap"); + mShow = config.getValue(getWindowName() + "Show", true); setDefaultSize(5, 25, 100, 100); + setResizable(true); + loadWindowState(); - // LEEOR: The Window class needs to modified to accept - // setAlignment calls. - setAlignment(gcn::Graphics::CENTER); } Minimap::~Minimap() { if (mMapImage) mMapImage->decRef(); + + config.setValue(getWindowName() + "Show", mShow); } void Minimap::setMapImage(Image *img) @@ -55,30 +63,94 @@ void Minimap::setMapImage(Image *img) mMapImage = img; - if (mMapImage) { - mMapImage->setAlpha(0.7); - setContentSize(mMapImage->getWidth(), mMapImage->getHeight()); + if (mMapImage) + { + const int offsetX = 2 * getPadding(); + const int offsetY = getTitleBarHeight() + getPadding(); + const int titleWidth = getFont()->getWidth(getCaption()) + 15; + const int mapWidth = mMapImage->getWidth() < 100 ? + mMapImage->getWidth() + offsetX : 100; + const int mapHeight = mMapImage->getHeight() < 100 ? + mMapImage->getHeight() + offsetY : 100; + + setMinWidth(mapWidth > titleWidth ? mapWidth : titleWidth); + setMinHeight(mapHeight); + setMaxWidth(mMapImage->getWidth() > titleWidth ? + mMapImage->getWidth() + offsetX : titleWidth); + setMaxHeight(mMapImage->getHeight() + offsetY); + + // Make sure the window is within the minimum and maximum boundaries + // TODO: Shouldn't this be happening automatically within the Window + // class? + if (getMinWidth() > getWidth()) + setWidth(getMinWidth()); + else if (getMaxWidth() < getWidth()) + setWidth(getMaxWidth()); + if (getMinHeight() > getHeight()) + setHeight(getMinHeight()); + else if (getMaxHeight() < getHeight()) + setHeight(getMaxHeight()); + + setContentSize(getWidth() - offsetX, getHeight() - offsetY); + setDefaultSize(getX(), getY(), getWidth(), getHeight()); + resetToDefaultSize(); + + setVisible(mShow); } + else + { + setVisible(false); + } +} + +void Minimap::toggle() +{ + mShow = !mShow; } void Minimap::draw(gcn::Graphics *graphics) { + setVisible(mShow); + Window::draw(graphics); + if (!mShow) + return; + const gcn::Rectangle a = getChildrenArea(); - int mapOriginX = a.x; - int mapOriginY = a.y; + graphics->pushClipArea(a); + + int mapOriginX = 0; + int mapOriginY = 0; if (mMapImage) { if (mMapImage->getWidth() > a.width || mMapImage->getHeight() > a.height) { - const Vector &pos = player_node->getPosition(); - mapOriginX += (a.width - (int) (pos.x / 32)) / 2; - mapOriginY += (a.height - (int) (pos.y / 32)) / 2; +#ifdef TMWSERV_SUPPORT + const Vector &p = player_node->getPosition(); + mapOriginX = (int) (((a.width) / 2) - (int) (p.x * mProportion) / 32); + mapOriginY = (int) (((a.height) / 2) - (int) (p.y * mProportion) / 32); +#else + mapOriginX = (int) (((a.width) / 2) - (player_node->mX * mProportion)); + mapOriginY = (int) (((a.height) / 2) - (player_node->mY * mProportion)); +#endif + + const int minOriginX = a.width - mMapImage->getWidth(); + const int minOriginY = a.height - mMapImage->getHeight(); + + if (mapOriginX < minOriginX) + mapOriginX = minOriginX; + if (mapOriginY < minOriginY) + mapOriginY = minOriginY; + if (mapOriginX > 0) + mapOriginX = 0; + if (mapOriginY > 0) + mapOriginY = 0; } + static_cast<Graphics*>(graphics)-> drawImage(mMapImage, mapOriginX, mapOriginY); } @@ -102,24 +174,26 @@ void Minimap::draw(gcn::Graphics *graphics) graphics->setColor(gcn::Color(61, 52, 209)); break; - case Being::NPC: - graphics->setColor(gcn::Color(255, 255, 0)); - break; - case Being::MONSTER: graphics->setColor(gcn::Color(209, 52, 61)); break; + case Being::NPC: + graphics->setColor(gcn::Color(255, 255, 0)); + break; + default: continue; } - const int offset = (dotSize - 1) / 2; + const int offset = (int) ((dotSize - 1) * mProportion); const Vector &pos = being->getPosition(); graphics->fillRectangle(gcn::Rectangle( - (int) pos.x / 64 + mapOriginX - offset, - (int) pos.x / 64 + mapOriginY - offset, + (int) (pos.x * mProportion) / 32 + mapOriginX - offset, + (int) (pos.x * mProportion) / 32 + mapOriginY - offset, dotSize, dotSize)); } + + graphics->popClipArea(); } diff --git a/src/gui/minimap.h b/src/gui/minimap.h index f91dc22d..3ce0aacd 100644 --- a/src/gui/minimap.h +++ b/src/gui/minimap.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004-2005 The Mana World Development Team + * Copyright (C) 2004-2005 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MINIMAP_H -#define _TMW_MINIMAP_H +#ifndef MINIMAP_H +#define MINIMAP_H #include "window.h" @@ -50,12 +50,24 @@ class Minimap : public Window void setMapImage(Image *img); /** + * Sets the map proportion (1 means 1 tile to one pixel, .5 means 2 tiles to 1 pixel, etc.) + */ + void setProportion(float proportion) { mProportion = proportion; } + + /** + * Toggles the displaying of the minimap. + */ + void toggle(); + + /** * Draws the minimap. */ void draw(gcn::Graphics *graphics); private: Image *mMapImage; + float mProportion; + static bool mShow; }; extern Minimap *minimap; diff --git a/src/gui/ministatus.cpp b/src/gui/ministatus.cpp index 86e5a8f1..5bc25bdb 100644 --- a/src/gui/ministatus.cpp +++ b/src/gui/ministatus.cpp @@ -1,65 +1,94 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * 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 "../animatedsprite.h" #include "../configuration.h" #include "../graphics.h" +#include "../localplayer.h" -#include "../utils/tostring.h" +#include "../utils/stringutils.h" MiniStatusWindow::MiniStatusWindow() { + setWindowName("MiniStatus"); setResizable(false); setMovable(false); setTitleBarHeight(0); mHpBar = new ProgressBar(1.0f, 100, 20, 0, 171, 34); - mHpLabel = new gcn::Label(""); +#ifdef EATHENA_SUPPORT + mMpBar = new ProgressBar(1.0f, 100, 20, 26, 102, 230); + mXpBar = new ProgressBar(1.0f, 100, 20, 143, 192, 211); +#endif mHpBar->setPosition(0, 3); +#ifdef EATHENA_SUPPORT + mMpBar->setPosition(mHpBar->getWidth() + 3, 3); + mXpBar->setPosition(mMpBar->getX() + mMpBar->getWidth() + 3, 3); +#endif - mHpLabel->setDimension(mHpBar->getDimension()); + add(mHpBar); +#ifdef EATHENA_SUPPORT + add(mMpBar); + add(mXpBar); +#endif + +#ifdef EATHENA_SUPPORT + setContentSize(mXpBar->getX() + mXpBar->getWidth(), + mXpBar->getY() + mXpBar->getHeight()); +#else + setContentSize(mHpBar->getX() + mHpBar->getWidth(), + mHpBar->getY() + mHpBar->getHeight()); +#endif + setDefaultSize(0, 0, getWidth(), getHeight()); + loadWindowState(); +} - mHpLabel->setForegroundColor(gcn::Color(255, 255, 255)); +void MiniStatusWindow::setIcon(int index, AnimatedSprite *sprite) +{ + if (index >= (int) mIcons.size()) + mIcons.resize(index + 1, NULL); - mHpLabel->setFont(speechFont); + if (mIcons[index]) + delete mIcons[index]; - mHpLabel->setAlignment(gcn::Graphics::CENTER); + mIcons[index] = sprite; +} - add(mHpBar); - add(mHpLabel); +void MiniStatusWindow::eraseIcon(int index) +{ + mIcons.erase(mIcons.begin() + index); } +extern volatile int tick_time; + void MiniStatusWindow::update() { // HP Bar coloration - int maxHp = player_node->getMaxHP(); - int hp = player_node->getHP(); + int maxHp = player_node->getMaxHp(); + int hp = player_node->getHp(); if (hp < int(maxHp / 3)) { mHpBar->setColor(223, 32, 32); // Red @@ -73,10 +102,47 @@ void MiniStatusWindow::update() mHpBar->setColor(0, 171, 34); // Green } +#ifdef EATHENA_SUPPORT + float xp = (float) player_node->getXp() / player_node->mXpForNextLevel; + + if (xp != xp) xp = 0.0f; // check for NaN + if (xp < 0.0f) xp = 0.0f; // make sure the experience isn't negative (uninitialized pointer most likely) + if (xp > 1.0f) xp = 1.0f; +#endif + mHpBar->setProgress((float) hp / maxHp); +#ifdef EATHENA_SUPPORT + mMpBar->setProgress((float) player_node->mMp / player_node->mMaxMp); + mXpBar->setProgress(xp); +#endif // Update labels - mHpLabel->setCaption(toString(hp)); + mHpBar->setText(toString(player_node->getHp())); +#ifdef EATHENA_SUPPORT + mMpBar->setText(toString(player_node->mMp)); + + std::stringstream updatedText; + updatedText << (float) ((int) (xp * 10000.0f)) / 100.0f << "%"; + + // Displays the number of monsters to next lvl + // (disabled for now but interesting idea) + /* + if (config.getValue("xpBarMonsterCounterExp", 0)!=0) + { + updatedText << " | " + << (int)(((float)player_node->mXpForNextLevel - (float)player_node->mXp) + / (float)config.getValue("xpBarMonsterCounterExp", 0)) + << " " + << config.getValue("xpBarMonsterCounterName", "Monsters") <<" left..."; + } + */ + + mXpBar->setText(updatedText.str()); +#endif + + for (unsigned int i = 0; i < mIcons.size(); i++) + if (mIcons[i]) + mIcons[i]->update(tick_time * 10); } void MiniStatusWindow::draw(gcn::Graphics *graphics) @@ -84,3 +150,19 @@ void MiniStatusWindow::draw(gcn::Graphics *graphics) update(); drawChildren(graphics); } + +void MiniStatusWindow::drawIcons(Graphics *graphics) +{ + // Draw icons +#ifdef TMWSERV_SUPPORT + int icon_x = mHpBar->getX() + mHpBar->getWidth() + 4; +#else + int icon_x = mXpBar->getX() + mXpBar->getWidth() + 4; +#endif + for (unsigned int i = 0; i < mIcons.size(); i++) { + if (mIcons[i]) { + mIcons[i]->draw(graphics, icon_x, 3); + icon_x += 2 + mIcons[i]->getWidth(); + } + } +} diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h index f512ef25..b69f9a14 100644 --- a/src/gui/ministatus.h +++ b/src/gui/ministatus.h @@ -1,33 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MINISTATUS_H -#define _TMW_MINISTATUS_H - -#include <iosfwd> +#ifndef MINISTATUS_H +#define MINISTATUS_H #include "window.h" -#include "../guichanfwd.h" +#include <vector> +class AnimatedSprite; class ProgressBar; /** @@ -44,13 +43,22 @@ class MiniStatusWindow : public Window MiniStatusWindow(); /** - * Draw this window + * Draw this window. */ void draw(gcn::Graphics *graphics); + /** + * Sets one of the icons. + */ + void setIcon(int index, AnimatedSprite *sprite); + + void eraseIcon(int index); + + void drawIcons(Graphics *graphics); + private: /** - * Updates this dialog with values from player_node + * Updates this dialog with values from player_node. */ void update(); @@ -58,7 +66,12 @@ class MiniStatusWindow : public Window * Mini Status Bars */ ProgressBar *mHpBar; - gcn::Label *mHpLabel; +#ifdef EATHENA_SUPPORT + ProgressBar *mMpBar; + ProgressBar *mXpBar; +#endif + + std::vector<AnimatedSprite *> mIcons; }; #endif diff --git a/src/gui/npc_text.cpp b/src/gui/npc_text.cpp index c9ace303..48f2adb7 100644 --- a/src/gui/npc_text.cpp +++ b/src/gui/npc_text.cpp @@ -1,102 +1,117 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "button.h" #include "npc_text.h" - -#include <string> - #include "scrollarea.h" -#include "button.h" #include "textbox.h" +#include "widgets/layout.h" + #include "../npc.h" #include "../utils/gettext.h" NpcTextDialog::NpcTextDialog(): - Window(_("NPC")) + Window(_("NPC")), + mState(NPC_TEXT_STATE_WAITING) { setResizable(true); setMinWidth(200); setMinHeight(150); + setDefaultSize(0, 0, 260, 200); + mTextBox = new TextBox; mTextBox->setEditable(false); + mTextBox->setOpaque(false); - scrollArea = new ScrollArea(mTextBox); - okButton = new Button(_("OK"), "ok", this); + mScrollArea = new ScrollArea(mTextBox); + mButton = new Button(_("Waiting for server"), "ok", this); - setContentSize(260, 175); - scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - scrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - scrollArea->setDimension(gcn::Rectangle( - 5, 5, 250, 160 - okButton->getHeight())); - okButton->setPosition( - 260 - 5 - okButton->getWidth(), - 175 - 5 - okButton->getHeight()); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mScrollArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_ALWAYS); - add(scrollArea); - add(okButton); + place(0, 0, mScrollArea, 5).setPadding(3); + place(4, 1, mButton); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + loadWindowState(); setLocationRelativeTo(getParent()); } void NpcTextDialog::setText(const std::string &text) { mText = text; - mTextBox->setTextWrapped(mText); + mTextBox->setTextWrapped(mText, mScrollArea->getWidth() - 15); } void NpcTextDialog::addText(const std::string &text) { setText(mText + text + "\n"); + mScrollArea->setVerticalScrollAmount(mScrollArea->getVerticalMaxScroll()); } -void NpcTextDialog::widgetResized(const gcn::Event &event) +void NpcTextDialog::showNextButton() { - Window::widgetResized(event); - - const gcn::Rectangle &area = getChildrenArea(); - const int width = area.width; - const int height = area.height; - - scrollArea->setDimension(gcn::Rectangle( - 5, 5, width - 10, height - 15 - okButton->getHeight())); - okButton->setPosition( - width - 5 - okButton->getWidth(), - height - 5 - okButton->getHeight()); + mButton->setCaption(_("Next")); + mState = NPC_TEXT_STATE_NEXT; + mButton->setEnabled(true); +} - // Set the text again so that it gets wrapped according to the new size - mTextBox->setTextWrapped(mText); +void NpcTextDialog::showCloseButton() +{ + mButton->setCaption(_("Close")); + mState = NPC_TEXT_STATE_CLOSE; + mButton->setEnabled(true); } void NpcTextDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "ok") { - setText(""); - setVisible(false); - if (current_npc) + if (mState == NPC_TEXT_STATE_NEXT && current_npc) { current_npc->nextDialog(); - current_npc = 0; + addText("\n> Next\n"); + } else if (mState == NPC_TEXT_STATE_CLOSE || + (mState == NPC_TEXT_STATE_NEXT && !current_npc)) { + setText(""); + setVisible(false); + if (current_npc) current_npc->handleDeath(); + } else return; } + else return; + + mButton->setEnabled(false); + mButton->setCaption(_("Waiting for server")); + mState = NPC_TEXT_STATE_WAITING; +} + +void NpcTextDialog::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + setText(mText); } + diff --git a/src/gui/npc_text.h b/src/gui/npc_text.h index b6eccf95..a1373830 100644 --- a/src/gui/npc_text.h +++ b/src/gui/npc_text.h @@ -1,28 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NPC_TEXT_H -#define _TMW_NPC_TEXT_H +#ifndef NPC_TEXT_H +#define NPC_TEXT_H + +#include <string> -#include <iosfwd> #include <guichan/actionlistener.hpp> #include "window.h" @@ -45,16 +46,14 @@ class NpcTextDialog : public Window, public gcn::ActionListener NpcTextDialog(); /** - * Called when resizing the window. - * - * @param event The calling event + * Called when receiving actions from the widgets. */ - void widgetResized(const gcn::Event &event); + void action(const gcn::ActionEvent &event); /** - * Called when receiving actions from the widgets. + * Clears the text shown in the dialog. */ - void action(const gcn::ActionEvent &event); + void clearText(); /** * Sets the text shows in the dialog. @@ -71,12 +70,30 @@ class NpcTextDialog : public Window, public gcn::ActionListener */ void addText(const std::string &string); + void showNextButton(); + + void showCloseButton(); + + /** + * Called when resizing the window. + * + * @param event The calling event + */ + void widgetResized(const gcn::Event &event); + private: - gcn::Button *okButton; - gcn::ScrollArea *scrollArea; + gcn::ScrollArea *mScrollArea; TextBox *mTextBox; + gcn::Button *mButton; std::string mText; + + enum NPCTextState { + NPC_TEXT_STATE_WAITING, + NPC_TEXT_STATE_NEXT, + NPC_TEXT_STATE_CLOSE + }; + int mState; }; -#endif // _TMW_NPC_TEXT_H +#endif // NPC_TEXT_H diff --git a/src/gui/npcintegerdialog.cpp b/src/gui/npcintegerdialog.cpp new file mode 100644 index 00000000..463f46ae --- /dev/null +++ b/src/gui/npcintegerdialog.cpp @@ -0,0 +1,125 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "button.h" +#include "inttextfield.h" +#include "npc_text.h" +#include "npcintegerdialog.h" + +#include "widgets/layout.h" + +#include "../npc.h" + +#include "../utils/gettext.h" +#include "../utils/strprintf.h" + +extern NpcTextDialog *npcTextDialog; + +NpcIntegerDialog::NpcIntegerDialog(): + Window(_("NPC Number Request")) +{ + mValueField = new IntTextField; + + mDecButton = new Button("-", "decvalue", this); + mIncButton = new Button("+", "incvalue", this); + gcn::Button *okButton = new Button(_("OK"), "ok", this); + gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this); + gcn::Button *resetButton = new Button(_("Reset"), "reset", this); + + mDecButton->setSize(20, 20); + mIncButton->setSize(20, 20); + + ContainerPlacer place; + place = getPlacer(0, 0); + + place(0, 0, mDecButton); + place(1, 0, mValueField, 3); + place(4, 0, mIncButton); + place.getCell().matchColWidth(1, 0); + place = getPlacer(0, 1); + place(0, 0, resetButton); + place(2, 0, cancelButton); + place(3, 0, okButton); + reflowLayout(175, 0); + + setLocationRelativeTo(getParent()); +} + +void NpcIntegerDialog::setRange(int min, int max) +{ + mValueField->setRange(min, max); +} + +int NpcIntegerDialog::getValue() +{ + return mValueField->getValue(); +} + +void NpcIntegerDialog::action(const gcn::ActionEvent &event) +{ + int finish = 0; + + if (event.getId() == "ok") + { + finish = 1; + npcTextDialog->addText(strprintf("\n> %d\n", mValueField->getValue())); + } + else if (event.getId() == "cancel") + { + finish = 1; + mValueField->reset(); + npcTextDialog->addText(_("\n> Cancel\n")); + } + else if (event.getId() == "decvalue") + { + mValueField->setValue(mValueField->getValue() - 1); + } + else if (event.getId() == "incvalue") + { + mValueField->setValue(mValueField->getValue() + 1); + } + else if (event.getId() == "reset") + { + mValueField->reset(); + } + + if (finish) + { + setVisible(false); + current_npc->integerInput(mValueField->getValue()); + mValueField->reset(); + } +} + +void NpcIntegerDialog::setDefaultValue(int value) +{ + mValueField->setDefaultValue(value); +} + +bool NpcIntegerDialog::isInputFocused() +{ + return mValueField->isFocused(); +} + +void NpcIntegerDialog::requestFocus() +{ + mValueField->requestFocus(); +} diff --git a/src/gui/npcintegerdialog.h b/src/gui/npcintegerdialog.h new file mode 100644 index 00000000..941bb55a --- /dev/null +++ b/src/gui/npcintegerdialog.h @@ -0,0 +1,87 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_NPCINTEGERDIALOG_H +#define GUI_NPCINTEGERDIALOG_H + +#include <guichan/actionlistener.hpp> + +#include "window.h" + +class IntTextField; + +/** + * The npc integer input dialog. + * + * \ingroup Interface + */ +class NpcIntegerDialog : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + NpcIntegerDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + /** + * Returns the current value. + */ + int getValue(); + + /** + * Prepares the NPC dialog. + * + * @param min The minimum value to allow + * @param max The maximum value to allow + */ + void setRange(int min, int max); + + /** + * Sets the default value. + * + * @param value The new default value + */ + void setDefaultValue(int value); + + /** + * Checks whether NpcStringDialog is Focused or not. + */ + bool isInputFocused(); + + /** + * Requests the textfield to take focus for input. + */ + void requestFocus(); + + private: + gcn::Button *mDecButton; + gcn::Button *mIncButton; + IntTextField *mValueField; +}; + +#endif // GUI_NPCINTEGERDIALOG_H diff --git a/src/gui/npclistdialog.cpp b/src/gui/npclistdialog.cpp index c55255ea..82e05fd5 100644 --- a/src/gui/npclistdialog.cpp +++ b/src/gui/npclistdialog.cpp @@ -1,35 +1,40 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * 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 "npc_text.h" +#include "npclistdialog.h" +#include "scrollarea.h" + +#include "widgets/layout.h" #include "../npc.h" #include "../utils/gettext.h" +#include "../utils/strprintf.h" + +extern NpcTextDialog *npcTextDialog; NpcListDialog::NpcListDialog(): Window(_("NPC")) @@ -39,30 +44,25 @@ NpcListDialog::NpcListDialog(): setMinWidth(200); setMinHeight(150); + setDefaultSize(0, 0, 260, 200); + mItemList = new ListBox(this); - scrollArea = new ScrollArea(mItemList); - okButton = new Button(_("OK"), "ok", this); - cancelButton = new Button(_("Cancel"), "cancel", this); + mItemList->setWrappingEnabled(true); + gcn::ScrollArea *scrollArea = new ScrollArea(mItemList); + gcn::Button *okButton = new Button(_("OK"), "ok", this); + gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this); setContentSize(260, 175); scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - scrollArea->setDimension(gcn::Rectangle( - 5, 5, 250, 160 - okButton->getHeight())); - cancelButton->setPosition( - 260 - 5 - cancelButton->getWidth(), - 175 - 5 - cancelButton->getHeight()); - okButton->setPosition( - cancelButton->getX() - 5 - okButton->getWidth(), - cancelButton->getY()); - mItemList->setActionEventId("item"); + place(0, 0, scrollArea, 5).setPadding(3); + place(3, 1, okButton); + place(4, 1, cancelButton); - mItemList->addActionListener(this); - - add(scrollArea); - add(okButton); - add(cancelButton); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + loadWindowState(); setLocationRelativeTo(getParent()); } @@ -81,33 +81,23 @@ void NpcListDialog::addItem(const std::string &item) mItems.push_back(item); } -void NpcListDialog::reset() +void NpcListDialog::parseItems(const std::string &itemString) { - mItems.clear(); + std::istringstream iss(itemString); + + std::string tmp; + while (getline(iss, tmp, ':')) + mItems.push_back(tmp); } -void NpcListDialog::widgetResized(const gcn::Event &event) +void NpcListDialog::reset() { - Window::widgetResized(event); - - const gcn::Rectangle &area = getChildrenArea(); - const int width = area.width; - const int height = area.height; - - scrollArea->setDimension(gcn::Rectangle( - 5, 5, width - 10, height - 15 - okButton->getHeight())); - cancelButton->setPosition( - width - 5 - cancelButton->getWidth(), - height - 5 - cancelButton->getHeight()); - okButton->setPosition( - cancelButton->getX() - 5 - okButton->getWidth(), - cancelButton->getY()); + mItems.clear(); } void NpcListDialog::action(const gcn::ActionEvent &event) { int choice = 0; - if (event.getId() == "ok") { // Send the selected index back to the server @@ -115,11 +105,14 @@ void NpcListDialog::action(const gcn::ActionEvent &event) if (selectedIndex > -1) { choice = selectedIndex + 1; + npcTextDialog->addText(strprintf("\n> \"%s\"\n", + mItems[selectedIndex].c_str())); } } else if (event.getId() == "cancel") { choice = 0xff; // 0xff means cancel + npcTextDialog->addText(_("\n> Cancel\n")); } if (choice) @@ -127,6 +120,5 @@ void NpcListDialog::action(const gcn::ActionEvent &event) setVisible(false); reset(); current_npc->dialogChoice(choice); - current_npc = 0; } } diff --git a/src/gui/npclistdialog.h b/src/gui/npclistdialog.h index 65281f58..7e37c7e6 100644 --- a/src/gui/npclistdialog.h +++ b/src/gui/npclistdialog.h @@ -1,36 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUI_NPCLISTDIALOG_H -#define _TMW_GUI_NPCLISTDIALOG_H +#ifndef GUI_NPCLISTDIALOG_H +#define GUI_NPCLISTDIALOG_H -#include <iosfwd> -#include <vector> +#include "window.h" #include <guichan/actionlistener.hpp> #include <guichan/listmodel.hpp> -#include "window.h" - -#include "../guichanfwd.h" +#include <vector> /** * The npc list dialog. @@ -49,13 +46,6 @@ class NpcListDialog : public Window, public gcn::ActionListener, NpcListDialog(); /** - * Called when resizing the window - * - * @param event The calling event - */ - void widgetResized(const gcn::Event &event); - - /** * Called when receiving actions from the widgets. */ void action(const gcn::ActionEvent &event); @@ -76,17 +66,21 @@ class NpcListDialog : public Window, public gcn::ActionListener, void addItem(const std::string &); /** + * Fills the options list for an NPC dialog. + * + * @param itemString A string with the options separated with colons. + */ + void parseItems(const std::string &itemString); + + /** * Resets the list by removing all items. */ void reset(); private: gcn::ListBox *mItemList; - gcn::ScrollArea *scrollArea; - gcn::Button *okButton; - gcn::Button *cancelButton; std::vector<std::string> mItems; }; -#endif // _TMW_GUI_NPCLISTDIALOG_H +#endif // GUI_NPCLISTDIALOG_H diff --git a/src/gui/npcstringdialog.cpp b/src/gui/npcstringdialog.cpp new file mode 100644 index 00000000..d9bf5682 --- /dev/null +++ b/src/gui/npcstringdialog.cpp @@ -0,0 +1,89 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "button.h" +#include "npc_text.h" +#include "npcstringdialog.h" +#include "textfield.h" + +#include "widgets/layout.h" + +#include "../npc.h" + +#include "../utils/gettext.h" +#include "../utils/strprintf.h" + +extern NpcTextDialog *npcTextDialog; + +NpcStringDialog::NpcStringDialog(): + Window(_("NPC Text Request")) +{ + mValueField = new TextField(""); + + gcn::Button *okButton = new Button(_("OK"), "ok", this); + gcn::Button *cancelButton = new Button(_("Cancel"), "cancel", this); + + place(0, 0, mValueField, 3); + place(1, 1, cancelButton); + place(2, 1, okButton); + reflowLayout(175, 0); + + setLocationRelativeTo(getParent()); +} + +std::string NpcStringDialog::getValue() +{ + return mValueField->getText(); +} + +void NpcStringDialog::setValue(const std::string &value) +{ + mValueField->setText(value); + mDefault = value; +} + +void NpcStringDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "cancel") + { + mValueField->setText(mDefault); + npcTextDialog->addText(_("\n> Cancel\n")); + } + else + { + npcTextDialog->addText(strprintf("\n> \"%s\"\n", + mValueField->getText().c_str())); + } + + setVisible(false); + current_npc->stringInput(mValueField->getText()); + mValueField->setText(""); +} + +bool NpcStringDialog::isInputFocused() +{ + return mValueField->isFocused(); +} + +void NpcStringDialog::requestFocus() +{ + mValueField->requestFocus(); +} diff --git a/src/gui/npcstringdialog.h b/src/gui/npcstringdialog.h new file mode 100644 index 00000000..0faaf203 --- /dev/null +++ b/src/gui/npcstringdialog.h @@ -0,0 +1,76 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_NPCSTRINGDIALOG_H +#define GUI_NPCSTRINGDIALOG_H + +#include "window.h" + +#include <guichan/actionlistener.hpp> + +/** + * The npc integer input dialog. + * + * \ingroup Interface + */ +class NpcStringDialog : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + * + * @see Window::Window + */ + NpcStringDialog(); + + /** + * Called when receiving actions from the widgets. + */ + void action(const gcn::ActionEvent &event); + + /** + * Returns the current value. + */ + std::string getValue(); + + /** + * Chnages the current value. + * + * @param value The new value + */ + void setValue(const std::string &value); + + /** + * Checks whether NpcStringDialog is Focused or not. + */ + bool isInputFocused(); + + /** + * Requests the textfield to take focus for input. + */ + void requestFocus(); + + private: + gcn::TextField *mValueField; + std::string mDefault; +}; + +#endif // GUI_NPCSTRINGDIALOG_H diff --git a/src/gui/ok_dialog.cpp b/src/gui/ok_dialog.cpp index b03c3964..4df3fa07 100644 --- a/src/gui/ok_dialog.cpp +++ b/src/gui/ok_dialog.cpp @@ -1,29 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "ok_dialog.h" - -#include <guichan/widgets/label.hpp> +#include <guichan/font.hpp> #include "button.h" +#include "ok_dialog.h" +#include "scrollarea.h" +#include "textbox.h" #include "../utils/gettext.h" @@ -31,22 +32,44 @@ OkDialog::OkDialog(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 *okButton = new Button(_("Ok"), "ok", this); - int w = textLabel->getWidth() + 20; - int h = textLabel->getHeight() + 25 + okButton->getHeight(); + mTextArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mTextArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mTextArea->setOpaque(false); + + mTextBox->setTextWrapped(msg, 260); + + int numRows = mTextBox->getNumberOfRows(); - if (okButton->getWidth() + 10 > w) { - w = okButton->getWidth() + 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) + 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)); } - setContentSize(w, h); - textLabel->setPosition(10, 10); - okButton->setPosition((w - okButton->getWidth()) / 2, - h - 5 - okButton->getHeight()); + okButton->setPosition((mTextBox->getMinWidth() - okButton->getWidth()) / 2, + (numRows * 14) + okButton->getHeight() - 8); - add(textLabel); + add(mTextArea); add(okButton); setLocationRelativeTo(getParent()); @@ -54,6 +77,11 @@ OkDialog::OkDialog(const std::string &title, const std::string &msg, okButton->requestFocus(); } +unsigned int OkDialog::getNumRows() +{ + return mTextBox->getNumberOfRows(); +} + void OkDialog::action(const gcn::ActionEvent &event) { // Proxy button events to our listeners diff --git a/src/gui/ok_dialog.h b/src/gui/ok_dialog.h index cba12d72..24325c2f 100644 --- a/src/gui/ok_dialog.h +++ b/src/gui/ok_dialog.h @@ -1,30 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _OK_DIALOG_H -#define _OK_DIALOG_H +#ifndef OK_DIALOG_H +#define OK_DIALOG_H + +#include "window.h" #include <guichan/actionlistener.hpp> -#include "window.h" +class ScrollArea; +class TextBox; /** * An 'Ok' button dialog. @@ -41,10 +44,16 @@ 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; }; #endif diff --git a/src/gui/passwordfield.cpp b/src/gui/passwordfield.cpp index 01c7e15d..345ee1c3 100644 --- a/src/gui/passwordfield.cpp +++ b/src/gui/passwordfield.cpp @@ -1,28 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "passwordfield.h" -#include <string> - PasswordField::PasswordField(const std::string& text): TextField(text) { diff --git a/src/gui/passwordfield.h b/src/gui/passwordfield.h index 8a14b72a..86195bd1 100644 --- a/src/gui/passwordfield.h +++ b/src/gui/passwordfield.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_PASSWORDFIELD_H_ -#define _TMW_PASSWORDFIELD_H_ +#ifndef PASSWORDFIELD_H +#define PASSWORDFIELD_H #include "textfield.h" @@ -29,7 +29,8 @@ * * \ingroup GUI */ -class PasswordField : public TextField { +class PasswordField : public TextField +{ public: /** * Constructor, initializes the password field with the given string. diff --git a/src/gui/playerbox.cpp b/src/gui/playerbox.cpp index 6888d69a..2bfa798c 100644 --- a/src/gui/playerbox.cpp +++ b/src/gui/playerbox.cpp @@ -1,30 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - #include "playerbox.h" -#include "../player.h" +#include "../animatedsprite.h" +#include "../configuration.h" #include "../graphics.h" +#include "../player.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" @@ -32,6 +32,7 @@ #include "../utils/dtor.h" int PlayerBox::instances = 0; +float PlayerBox::mAlpha = config.getValue("guialpha", 0.8); ImageRect PlayerBox::background; PlayerBox::PlayerBox(const Player *player): @@ -54,6 +55,7 @@ PlayerBox::PlayerBox(const Player *player): bggridx[x], bggridy[y], bggridx[x + 1] - bggridx[x] + 1, bggridy[y + 1] - bggridy[y] + 1); + background.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); a++; } } @@ -80,9 +82,29 @@ void PlayerBox::draw(gcn::Graphics *graphics) { // Draw character const int bs = getFrameSize(); +#ifdef TMWSERV_SUPPORT const int x = getWidth() / 2 + bs; const int y = getHeight() - bs - 8; mPlayer->draw(static_cast<Graphics*>(graphics), x, y); +#else + const int x = getWidth() / 2 - 16 + bs; + const int y = getHeight() / 2 + bs; + for (int i = 0; i < Being::VECTOREND_SPRITE; i++) + { + if (mPlayer->getSprite(i)) + { + mPlayer->getSprite(i)->draw(static_cast<Graphics*>(graphics), x, y); + } + } +#endif + } + + if (config.getValue("guialpha", 0.8) != mAlpha) + { + for (int a = 0; a < 9; a++) + { + background.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); + } } } diff --git a/src/gui/playerbox.h b/src/gui/playerbox.h index 78eeee91..7c08defd 100644 --- a/src/gui/playerbox.h +++ b/src/gui/playerbox.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_PLAYERBOX_H__ -#define __TMW_PLAYERBOX_H__ +#ifndef PLAYERBOX_H +#define PLAYERBOX_H #include <guichan/widgets/scrollarea.hpp> @@ -51,8 +51,7 @@ class PlayerBox : public gcn::ScrollArea * player to <code>NULL</code> causes the box not to draw any * character. */ - void - setPlayer(const Player *player) { mPlayer = player; } + void setPlayer(const Player *player) { mPlayer = player; } /** * Draws the scroll area. @@ -67,6 +66,7 @@ class PlayerBox : public gcn::ScrollArea private: const Player *mPlayer; /**< The character used for display */ + static float mAlpha; static int instances; static ImageRect background; }; diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index a430ff10..ced44f42 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -1,43 +1,46 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "popupmenu.h" - #include <cassert> -#include <iostream> - -#include <guichan/focushandler.hpp> #include "browserbox.h" +#include "chat.h" #include "inventorywindow.h" #include "item_amount.h" +#include "popupmenu.h" #include "windowcontainer.h" #include "../being.h" +#include "../beingmanager.h" #include "../floor_item.h" #include "../item.h" #include "../localplayer.h" #include "../npc.h" +#include "../player_relations.h" + +#ifdef EATHENA_SUPPORT +#include "../net/messageout.h" +#include "../net/ea/protocol.h" +#endif -#include "../resources/iteminfo.h" #include "../resources/itemdb.h" #include "../utils/gettext.h" @@ -47,14 +50,15 @@ extern std::string tradePartnerName; PopupMenu::PopupMenu(): Window(), - mBeing(NULL), + mBeingId(0), mFloorItem(NULL), mItem(NULL) { setResizable(false); setTitleBarHeight(0); + setShowTitle(false); - mBrowserBox = new BrowserBox(); + mBrowserBox = new BrowserBox; mBrowserBox->setPosition(4, 4); mBrowserBox->setHighlightMode(BrowserBox::BACKGROUND); mBrowserBox->setOpaque(false); @@ -64,22 +68,47 @@ PopupMenu::PopupMenu(): void PopupMenu::showPopup(int x, int y, Being *being) { - mBeing = being; + mBeingId = being->getId(); mBrowserBox->clearRows(); - switch (mBeing->getType()) + switch (being->getType()) { case Being::PLAYER: { // Players can be traded with. Later also attack, follow and // add as buddy will be options in this menu. - const std::string &name = mBeing->getName(); + const std::string &name = being->getName(); mBrowserBox->addRow(strprintf(_("@@trade|Trade With %s@@"), name.c_str())); mBrowserBox->addRow(strprintf(_("@@attack|Attack %s@@"), name.c_str())); - //mBrowserBox->addRow("@@follow|Follow " + name + "@@"); - //mBrowserBox->addRow("@@buddy|Add " + name + " to Buddy List@@"); + + mBrowserBox->addRow("##3---"); + + switch (player_relations.getRelation(name)) { + case PlayerRelation::NEUTRAL: + mBrowserBox->addRow(strprintf(_("@@friend|Befriend %s@@"), name.c_str())); + + case PlayerRelation::FRIEND: + mBrowserBox->addRow(strprintf(_("@@disregard|Disregard %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@ignore|Ignore %s@@"), name.c_str())); + break; + + case PlayerRelation::DISREGARDED: + mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str())); + mBrowserBox->addRow(strprintf(_("@@ignore|Completely ignore %s@@"), name.c_str())); + break; + + case PlayerRelation::IGNORED: + mBrowserBox->addRow(strprintf(_("@@unignore|Un-Ignore %s@@"), name.c_str())); + break; + } + + //mBrowserBox->addRow(_("@@follow|Follow ") + name + "@@"); + //mBrowserBox->addRow(_("@@buddy|Add ") + name + " to Buddy List@@"); mBrowserBox->addRow(strprintf(_("@@guild|Invite %s@@"), name.c_str())); mBrowserBox->addRow(strprintf(_("@@party|Invite %s to join your party@@"), name.c_str())); + + mBrowserBox->addRow("##3---"); + mBrowserBox->addRow(strprintf(_("@@party-invite|Invite %s to party@@"), name.c_str())); } break; @@ -119,37 +148,76 @@ void PopupMenu::showPopup(int x, int y, FloorItem *floorItem) void PopupMenu::handleLink(const std::string& link) { + Being *being = beingManager->findBeing(mBeingId); + // Talk To action if (link == "talk" && - mBeing != NULL && - mBeing->getType() == Being::NPC) + being && + being->getType() == Being::NPC && + current_npc == 0) { - static_cast<NPC*>(mBeing)->talk(); + dynamic_cast<NPC*>(being)->talk(); } // Trade action else if (link == "trade" && - mBeing != NULL && - mBeing->getType() == Being::PLAYER) + being && + being->getType() == Being::PLAYER) + { + player_node->trade(being); + tradePartnerName = being->getName(); + } +#ifdef EATHENA_SUPPORT + // Attack action + else if (link == "attack" && + being && + being->getType() == Being::PLAYER) { - player_node->trade(mBeing); - tradePartnerName = mBeing->getName(); + player_node->attack(being, true); + } +#endif + else if (link == "unignore" && + being && + being->getType() == Being::PLAYER) + { + player_relations.setRelation(being->getName(), PlayerRelation::NEUTRAL); } + else if (link == "ignore" && + being && + being->getType() == Being::PLAYER) + { + player_relations.setRelation(being->getName(), PlayerRelation::IGNORED); + } + + else if (link == "disregard" && + being && + being->getType() == Being::PLAYER) + { + player_relations.setRelation(being->getName(), PlayerRelation::DISREGARDED); + } + + else if (link == "friend" && + being && + being->getType() == Being::PLAYER) + { + player_relations.setRelation(being->getName(), PlayerRelation::FRIEND); + } +#ifdef TMWSERV_SUPPORT // Guild action else if (link == "guild" && - mBeing != NULL && - mBeing->getType() == Being::PLAYER) + being != NULL && + being->getType() == Being::PLAYER) { - player_node->inviteToGuild(mBeing); + player_node->inviteToGuild(being); } // Add player to your party else if (link == "party") { - player_node->inviteToParty(mBeing->getName()); + player_node->inviteToParty(being->getName()); } - +#endif /* // Follow Player action else if (link == "follow") @@ -158,16 +226,16 @@ void PopupMenu::handleLink(const std::string& link) /* // Add Buddy action - else if ((link == "buddy") && mBeing != NULL && mBeing->isPlayer()) + else if ((link == "buddy") && being && being->isPlayer()) { if (!buddyWindow->isVisible()) buddyWindow->setVisible(true); - buddyWindow->addBuddy(mBeing->getName()); + buddyWindow->addBuddy(being->getName()); }*/ // Pick Up Floor Item action - else if ((link == "pickup") && mFloorItem != NULL) + else if ((link == "pickup") && mFloorItem) { player_node->pickUp(mFloorItem); } @@ -182,13 +250,34 @@ void PopupMenu::handleLink(const std::string& link) assert(mItem); if (mItem->isEquipment()) { +#ifdef TMWSERV_SUPPORT player_node->equipItem(mItem); +#else + if (mItem->isEquipped()) + { + player_node->unequipItem(mItem); + } + else + { + player_node->equipItem(mItem); + } +#endif } else { +#ifdef TMWSERV_SUPPORT player_node->useItem(mItem->getInvIndex()); +#else + player_node->useItem(mItem); +#endif } } + + else if (link == "chat") + { + chatWindow->addItemText(mItem->getInfo().getName()); + } + else if (link == "split") { new ItemAmountWindow(AMOUNT_ITEM_SPLIT, inventoryWindow, mItem); @@ -197,12 +286,16 @@ void PopupMenu::handleLink(const std::string& link) { new ItemAmountWindow(AMOUNT_ITEM_DROP, inventoryWindow, mItem); } - - else if (link == "description") +#ifdef EATHENA_SUPPORT + else if (link == "party-invite" && + being && + being->getType() == Being::PLAYER) { - // do nothing for now, I need to write - // a window for the description first + MessageOut outMsg(player_node->getNetwork()); + outMsg.writeInt16(CMSG_PARTY_INVITE); + outMsg.writeInt32(being->getId()); } +#endif // Unknown actions else @@ -212,7 +305,7 @@ void PopupMenu::handleLink(const std::string& link) setVisible(false); - mBeing = NULL; + mBeingId = 0; mFloorItem = NULL; mItem = NULL; } @@ -225,14 +318,24 @@ void PopupMenu::showPopup(int x, int y, Item *item) if (item->isEquipment()) { +#ifdef TMWSERV_SUPPORT mBrowserBox->addRow(_("@@use|Equip@@")); +#else + if (item->isEquipped()) + mBrowserBox->addRow(_("@@use|Unequip@@")); + else + mBrowserBox->addRow(_("@@use|Equip@@")); +#endif } else mBrowserBox->addRow(_("@@use|Use@@")); + mBrowserBox->addRow(_("@@drop|Drop@@")); - mBrowserBox->addRow(_("@@description|Description@@")); +#ifdef TMWSERV_SUPPORT if (!item->isEquipment()) - { mBrowserBox->addRow(_("@@split|Split@@")); } + mBrowserBox->addRow(_("@@split|Split@@")); +#endif + mBrowserBox->addRow(_("@@chat|Add to Chat@@")); mBrowserBox->addRow("##3---"); mBrowserBox->addRow(_("@@cancel|Cancel@@")); diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h index 2d10e6eb..2694abd8 100644 --- a/src/gui/popupmenu.h +++ b/src/gui/popupmenu.h @@ -1,36 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_POPUP_MENU_H -#define _TMW_POPUP_MENU_H +#ifndef POPUP_MENU_H +#define POPUP_MENU_H + +#include <SDL.h> // for Uint32 -#include "window.h" #include "linkhandler.h" +#include "window.h" class Being; class BrowserBox; class FloorItem; class Item; - /** * Window showing popup menu. */ @@ -67,7 +68,7 @@ class PopupMenu : public Window, public LinkHandler private: BrowserBox* mBrowserBox; - Being* mBeing; + Uint32 mBeingId; FloorItem* mFloorItem; Item *mItem; diff --git a/src/gui/progressbar.cpp b/src/gui/progressbar.cpp index 9a47eefc..85f21604 100644 --- a/src/gui/progressbar.cpp +++ b/src/gui/progressbar.cpp @@ -1,26 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <guichan/font.hpp> + +#include "gui.h" #include "progressbar.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -28,6 +32,7 @@ ImageRect ProgressBar::mBorder; int ProgressBar::mInstances = 0; +float ProgressBar::mAlpha = config.getValue("guialpha", 0.8); ProgressBar::ProgressBar(float progress, unsigned int width, unsigned int height, @@ -56,6 +61,12 @@ ProgressBar::ProgressBar(float progress, mBorder.grid[6] = dBorders->getSubImage(0, 15, 4, 4); mBorder.grid[7] = dBorders->getSubImage(4, 15, 3, 4); mBorder.grid[8] = dBorders->getSubImage(7, 15, 4, 4); + + for (int i = 0; i < 9; i++) + { + mBorder.grid[i]->setAlpha(mAlpha); + } + dBorders->decRef(); } @@ -109,32 +120,62 @@ void ProgressBar::logic() mProgress = mProgressToGo; } -void -ProgressBar::draw(gcn::Graphics *graphics) +void ProgressBar::draw(gcn::Graphics *graphics) { + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + for (int i = 0; i < 9; i++) + { + mBorder.grid[i]->setAlpha(mAlpha); + } + } + static_cast<Graphics*>(graphics)-> drawImageRect(0, 0, getWidth(), getHeight(), mBorder); + const int alpha = (int)(mAlpha * 255.0f); + // The bar if (mProgress > 0) { - graphics->setColor(gcn::Color(mRed, mGreen, mBlue, 200)); + + graphics->setColor(gcn::Color(mRed, mGreen, mBlue, alpha)); graphics->fillRectangle(gcn::Rectangle(4, 4, - (int)(mProgress * (getWidth() - 8)), + (int) (mProgress * (getWidth() - 8)), getHeight() - 8)); } + + // The label + if (!mText.empty()) + { + gcn::Font *f = boldFont; + const int textX = getWidth() / 2; + const int textY = (getHeight() - f->getHeight()) / 2; + + graphics->setFont(f); + + graphics->setColor(gcn::Color(0, 0, 0, alpha)); + graphics->drawText(mText, textX + 1, textY, gcn::Graphics::CENTER); + graphics->drawText(mText, textX, textY - 1, gcn::Graphics::CENTER); + graphics->drawText(mText, textX, textY + 1, gcn::Graphics::CENTER); + graphics->drawText(mText, textX - 1, textY, gcn::Graphics::CENTER); + + graphics->setColor(gcn::Color(255, 255, 255, alpha)); + graphics->drawText(mText, textX, textY, gcn::Graphics::CENTER); + + graphics->setColor(gcn::Color(0, 0, 0)); + } } -void -ProgressBar::setProgress(float progress) +void ProgressBar::setProgress(float progress) { if (progress < 0.0f) mProgressToGo = 0.0; else if (progress > 1.0f) mProgressToGo = 1.0; else mProgressToGo = progress; } -void -ProgressBar::setColor(Uint8 red, Uint8 green, Uint8 blue) +void ProgressBar::setColor(Uint8 red, Uint8 green, Uint8 blue) { mRedToGo = red; mGreenToGo = green; diff --git a/src/gui/progressbar.h b/src/gui/progressbar.h index 0b1616f5..49bc3edd 100644 --- a/src/gui/progressbar.h +++ b/src/gui/progressbar.h @@ -1,26 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_PROGRESSBAR_H -#define _TMW_PROGRESSBAR_H +#ifndef PROGRESSBAR_H +#define PROGRESSBAR_H + +#include <string> #include <guichan/widget.hpp> @@ -28,13 +30,13 @@ class ImageRect; - /** * A progress bar. * * \ingroup GUI */ -class ProgressBar : public gcn::Widget { +class ProgressBar : public gcn::Widget +{ public: /** * Constructor, initializes the progress with the given value. @@ -51,63 +53,65 @@ class ProgressBar : public gcn::Widget { /** * Performs progress bar logic (fading colors) */ - void - logic(); + void logic(); /** * Draws the progress bar. */ - void - draw(gcn::Graphics *graphics); + void draw(gcn::Graphics *graphics); /** * Sets the current progress. */ - void - setProgress(float progress); + void setProgress(float progress); /** * Returns the current progress. */ - float - getProgress() { return mProgress; } + float getProgress() const { return mProgress; } /** * Change the filling of the progress bar. */ - void - setColor(Uint8, Uint8 green, Uint8 blue); + void setColor(Uint8, Uint8 green, Uint8 blue); + + /** + * Returns the red value of color. + */ + Uint8 getRed() const { return mRed; } /** - * Get The red value of color + * Returns the green value of color. */ - Uint8 - getRed() { return mRed; } + Uint8 getGreen() const { return mGreen; } - /** - * Get The red value of color + /** + * Returns the blue value of color. */ - Uint8 - getGreen() { return mGreen; } + Uint8 getBlue() const { return mBlue; } /** - * Get The red value of color + * Sets the text shown on the progress bar. */ - Uint8 - getBlue() { return mBlue; } + void setText(const std::string &text) + { mText = text; } /** - * Set wether the progress is moved smoothly + * Returns the text shown on the progress bar. */ - void - setSmoothProgress(bool smoothProgress) + const std::string &text() const + { return mText; } + + /** + * Set wether the progress is moved smoothly. + */ + void setSmoothProgress(bool smoothProgress) { mSmoothProgress = smoothProgress; } /** - * Set wether the color changing is made smoothly + * Set wether the color changing is made smoothly. */ - void - setSmoothColorChange(bool smoothColorChange) + void setSmoothColorChange(bool smoothColorChange) { mSmoothColorChange = smoothColorChange; } @@ -119,8 +123,11 @@ class ProgressBar : public gcn::Widget { Uint8 mRedToGo, mGreenToGo, mBlueToGo; bool mSmoothColorChange; + std::string mText; + static ImageRect mBorder; static int mInstances; + static float mAlpha; }; #endif diff --git a/src/gui/radiobutton.cpp b/src/gui/radiobutton.cpp index 619ec84f..c8ae2fad 100644 --- a/src/gui/radiobutton.cpp +++ b/src/gui/radiobutton.cpp @@ -1,32 +1,34 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "radiobutton.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" #include "../resources/resourcemanager.h" int RadioButton::instances = 0; +float RadioButton::mAlpha = config.getValue("guialpha", 0.8); Image *RadioButton::radioNormal; Image *RadioButton::radioChecked; Image *RadioButton::radioDisabled; @@ -43,6 +45,10 @@ RadioButton::RadioButton(const std::string& caption, const std::string& group, radioChecked = resman->getImage("graphics/gui/radioin.png"); radioDisabled = resman->getImage("graphics/gui/radioout.png"); radioDisabledChecked = resman->getImage("graphics/gui/radioin.png"); + radioNormal->setAlpha(mAlpha); + radioChecked->setAlpha(mAlpha); + radioDisabled->setAlpha(mAlpha); + radioDisabledChecked->setAlpha(mAlpha); } instances++; @@ -63,32 +69,37 @@ RadioButton::~RadioButton() void RadioButton::drawBox(gcn::Graphics* graphics) { + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + radioNormal->setAlpha(mAlpha); + radioChecked->setAlpha(mAlpha); + radioDisabled->setAlpha(mAlpha); + radioDisabledChecked->setAlpha(mAlpha); + } + Image *box = NULL; - if (isSelected()) { - if (isEnabled()) { + if (isSelected()) + { + if (isEnabled()) box = radioChecked; - } else { + else box = radioDisabledChecked; - } - } else if (isEnabled()) { + } + else if (isEnabled()) box = radioNormal; - } else { + else box = radioDisabled; - } - if (box != NULL) { + if (box) static_cast<Graphics*>(graphics)->drawImage(box, 2, 2); - } } void RadioButton::draw(gcn::Graphics* graphics) { - - graphics->pushClipArea(gcn::Rectangle(1, - 1, - getWidth() - 1, - getHeight() - 1)); + graphics->pushClipArea(gcn::Rectangle(1, 1, getWidth() - 1, + getHeight() - 1)); drawBox(graphics); diff --git a/src/gui/radiobutton.h b/src/gui/radiobutton.h index 09f703dc..3d952b3f 100644 --- a/src/gui/radiobutton.h +++ b/src/gui/radiobutton.h @@ -1,36 +1,36 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_RADIOBUTTON_H -#define _TMW_RADIOBUTTON_H +#ifndef RADIOBUTTON_H +#define RADIOBUTTON_H #include <guichan/widgets/radiobutton.hpp> class Image; - /* * Guichan based RadioButton with custom look */ -class RadioButton : public gcn::RadioButton { +class RadioButton : public gcn::RadioButton +{ public: /* * Constructor. @@ -56,10 +56,11 @@ class RadioButton : public gcn::RadioButton { private: static int instances; + static float mAlpha; static Image *radioNormal; static Image *radioChecked; static Image *radioDisabled; static Image *radioDisabledChecked; }; -#endif /* _TMW_RADIOBUTTON_H */ +#endif /* RADIOBUTTON_H */ diff --git a/src/gui/recorder.cpp b/src/gui/recorder.cpp new file mode 100644 index 00000000..ce097db2 --- /dev/null +++ b/src/gui/recorder.cpp @@ -0,0 +1,116 @@ +/* + * A chat recorder + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <physfs.h> + +#include "button.h" +#include "chat.h" +#include "recorder.h" +#include "windowcontainer.h" + +#include "widgets/layout.h" + +#include "../utils/stringutils.h" + +Recorder::Recorder(ChatWindow *chat, const std::string &title, + const std::string &buttonTxt) : + Window(title) +{ + setWindowName("Recorder"); + const int offsetX = 2 * getPadding() + 10; + const int offsetY = getTitleBarHeight() + getPadding() + 10; + + mChat = chat; + Button *button = new Button(buttonTxt, "activate", this); + setDefaultSize(0, windowContainer->getHeight() - 123 - button->getHeight() - + offsetY, button->getWidth() + offsetX, button->getHeight() + + offsetY); + + place(0, 0, button); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); + + loadWindowState(); +} + +Recorder::~Recorder() +{ +} + +void Recorder::record(const std::string &msg) +{ + if (mStream.is_open()) + { + mStream << msg << std::endl; + } +} + +void Recorder::changeRecordingStatus(const std::string &msg) +{ + std::string msgCopy = msg; + trim(msgCopy); + + if (msgCopy.empty()) + { + if (mStream.is_open()) + { + mStream.close(); + setVisible(false); + + /* + * Message should go after mStream is closed so that it isn't + * recorded. + */ + mChat->chatLog(_("Finishing recording."), BY_SERVER); + } + else + { + mChat->chatLog(_("Not currently recording."), BY_SERVER); + } + } + else if (mStream.is_open()) + { + mChat->chatLog(_("Already recording."), BY_SERVER); + } + else + { + /* + * Message should go before mStream is opened so that it isn't + * recorded. + */ + mChat->chatLog(_("Starting to record..."), BY_SERVER); + const std::string file = + std::string(PHYSFS_getUserDir()) + "/.tmw/" + msgCopy; + + mStream.open(file.c_str(), std::ios_base::trunc); + + if (mStream.is_open()) + setVisible(true); + else + mChat->chatLog(_("Failed to start recording."), BY_SERVER); + } +} + +void Recorder::action(const gcn::ActionEvent &event) +{ + changeRecordingStatus(""); +} diff --git a/src/gui/recorder.h b/src/gui/recorder.h new file mode 100644 index 00000000..0bbab012 --- /dev/null +++ b/src/gui/recorder.h @@ -0,0 +1,76 @@ +/* + * A chat recorder + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef RECORD_H +#define RECORD_H + +#include <fstream> +#include <string> + +#include <guichan/actionlistener.hpp> + +#include "window.h" + +#include "../utils/gettext.h" + +class ChatWindow; + +class Recorder : public Window, public gcn::ActionListener +{ + public: + Recorder(ChatWindow *chat, const std::string &title = _("Recording..."), + const std::string &buttonTxt = _("Stop recording")); + + virtual ~Recorder(); + + /* + * Outputs the message to the recorder file + * + * @param msg the line to write to the recorded file. + */ + void record(const std::string &msg); + + /* + * Outputs the message to the recorder file + * + * @param msg The file to write out to. If null, then stop recording. + */ + void changeRecordingStatus(const std::string &msg); + + /* + * Whether or not the recorder is in use. + */ + bool isRecording() {return (bool) mStream.is_open();} + + /* + * called when the button is pressed + * + * @param event is the event that is generated + */ + void action(const gcn::ActionEvent &event); + + private: + ChatWindow *mChat; + + std::ofstream mStream; +}; + +#endif diff --git a/src/gui/register.cpp b/src/gui/register.cpp index 051c0fa4..216ac211 100644 --- a/src/gui/register.cpp +++ b/src/gui/register.cpp @@ -1,55 +1,52 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "register.h" - -#include <string> -#include <sstream> - #include <guichan/widgets/label.hpp> -#include "../main.h" #include "../configuration.h" #include "../log.h" #include "../logindata.h" +#include "../main.h" #include "button.h" #include "checkbox.h" #include "login.h" +#include "ok_dialog.h" #include "passwordfield.h" #include "radiobutton.h" +#include "register.h" #include "textfield.h" -#include "ok_dialog.h" + +#include "widgets/layout.h" #include "../utils/gettext.h" #include "../utils/strprintf.h" +#include "../utils/stringutils.h" -void -WrongDataNoticeListener::setTarget(gcn::TextField *textField) +void WrongDataNoticeListener::setTarget(gcn::TextField *textField) { mTarget = textField; } -void -WrongDataNoticeListener::action(const gcn::ActionEvent &event) +void WrongDataNoticeListener::action(const gcn::ActionEvent &event) { if (event.getId() == "ok") { @@ -57,54 +54,61 @@ WrongDataNoticeListener::action(const gcn::ActionEvent &event) } } + RegisterDialog::RegisterDialog(LoginData *loginData): Window(_("Register")), - mWrongDataNoticeListener(new WrongDataNoticeListener()), + mWrongDataNoticeListener(new WrongDataNoticeListener), mLoginData(loginData) { gcn::Label *userLabel = new gcn::Label(_("Name:")); gcn::Label *passwordLabel = new gcn::Label(_("Password:")); gcn::Label *confirmLabel = new gcn::Label(_("Confirm:")); - gcn::Label *emailLabel = new gcn::Label(_("Email:")); +#ifdef EATHENA_SUPPORT + gcn::Label *serverLabel = new gcn::Label(_("Server:")); + gcn::Label *portLabel = new gcn::Label(_("Port:")); +#endif mUserField = new TextField(loginData->username); mPasswordField = new PasswordField(loginData->password); - mConfirmField = new PasswordField(); - mEmailField = new TextField(); + mConfirmField = new PasswordField; +#ifdef EATHENA_SUPPORT + mServerField = new TextField(loginData->hostname); + mPortField = new TextField(toString(loginData->port)); + mMaleButton = new RadioButton(_("Male"), "sex", true); + mFemaleButton = new RadioButton(_("Female"), "sex", false); +#endif mRegisterButton = new Button(_("Register"), "register", this); mCancelButton = new Button(_("Cancel"), "cancel", this); - const int width = 220; - const int height = 130; - 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()); - mEmailField->setPosition( - 65, mConfirmField->getY() + mConfirmField->getHeight() + 7); - mEmailField->setWidth(mUserField->getWidth()); - - userLabel->setPosition(5, mUserField->getY() + 1); - passwordLabel->setPosition(5, mPasswordField->getY() + 1); - confirmLabel->setPosition(5, mConfirmField->getY() + 1); - emailLabel->setPosition(5, mEmailField->getY() + 1); - - mCancelButton->setPosition( - width - mCancelButton->getWidth() - 5, - height - mCancelButton->getHeight() - 5); - mRegisterButton->setPosition( - mCancelButton->getX() - mRegisterButton->getWidth() - 5, - height - mRegisterButton->getHeight() - 5); + ContainerPlacer place; + place = getPlacer(0, 0); + place(0, 0, userLabel); + place(0, 1, passwordLabel); + place(0, 2, confirmLabel); +#ifdef EATHENA_SUPPORT + place(1, 3, mMaleButton); + place(2, 3, mFemaleButton); + place(0, 4, serverLabel); + place(0, 5, portLabel); +#endif + place(1, 0, mUserField, 3).setPadding(2); + place(1, 1, mPasswordField, 3).setPadding(2); + place(1, 2, mConfirmField, 3).setPadding(2); +#ifdef EATHENA_SUPPORT + place(1, 4, mServerField, 3).setPadding(2); + place(1, 5, mPortField, 3).setPadding(2); +#endif + place = getPlacer(0, 2); + place(1, 0, mRegisterButton); + place(2, 0, mCancelButton); + reflowLayout(250, 0); mUserField->addKeyListener(this); mPasswordField->addKeyListener(this); mConfirmField->addKeyListener(this); - mEmailField->addKeyListener(this); +#ifdef EATHENA_SUPPORT + mServerField->addKeyListener(this); + mPortField->addKeyListener(this); +#endif /* TODO: * This is a quick and dirty way to respond to the ENTER key, regardless of @@ -114,22 +118,18 @@ RegisterDialog::RegisterDialog(LoginData *loginData): mUserField->setActionEventId("register"); mPasswordField->setActionEventId("register"); mConfirmField->setActionEventId("register"); - mEmailField->setActionEventId("register"); + mUserField->addActionListener(this); mPasswordField->addActionListener(this); mConfirmField->addActionListener(this); - mEmailField->addActionListener(this); - - add(userLabel); - add(passwordLabel); - add(emailLabel); - add(confirmLabel); - add(mUserField); - add(mPasswordField); - add(mConfirmField); - add(mEmailField); - add(mRegisterButton); - add(mCancelButton); + +#ifdef EATHENA_SUPPORT + mServerField->setActionEventId("register"); + mPortField->setActionEventId("register"); + + mServerField->addActionListener(this); + mPortField->addActionListener(this); +#endif setLocationRelativeTo(getParent()); setVisible(true); @@ -144,8 +144,7 @@ RegisterDialog::~RegisterDialog() delete mWrongDataNoticeListener; } -void -RegisterDialog::action(const gcn::ActionEvent &event) +void RegisterDialog::action(const gcn::ActionEvent &event) { if (event.getId() == "cancel") { @@ -225,25 +224,73 @@ RegisterDialog::action(const gcn::ActionEvent &event) mLoginData->username = mUserField->getText(); mLoginData->password = mPasswordField->getText(); +#ifdef EATHENA_SUPPORT + mLoginData->hostname = mServerField->getText(); + mLoginData->port = getUShort(mPortField->getText()); + mLoginData->username += mFemaleButton->isSelected() ? "_F" : "_M"; +#else mLoginData->email = mEmailField->getText(); +#endif mLoginData->registerLogin = true; +#ifdef TMWSERV_SUPPORT state = STATE_REGISTER_ATTEMPT; +#else + state = STATE_ACCOUNT; +#endif } } } -void -RegisterDialog::keyPressed(gcn::KeyEvent &keyEvent) +void RegisterDialog::keyPressed(gcn::KeyEvent &keyEvent) { mRegisterButton->setEnabled(canSubmit()); } -bool -RegisterDialog::canSubmit() +bool RegisterDialog::canSubmit() const { return !mUserField->getText().empty() && !mPasswordField->getText().empty() && !mConfirmField->getText().empty() && +#ifdef EATHENA_SUPPORT + !mServerField->getText().empty() && + isUShort(mPortField->getText()) && +#endif state == STATE_REGISTER; } + +#ifdef EATHENA_SUPPORT +bool RegisterDialog::isUShort(const std::string &str) +{ + if (str.empty()) + { + return false; + } + unsigned long l = 0; + for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end(); + strPtr != strEnd; ++strPtr) + { + if (*strPtr < '0' || *strPtr > '9') + { + return false; + } + l = l * 10 + (*strPtr - '0'); // *strPtr - '0' will never be negative + if (l > 65535) + { + return false; + } + } + return true; +} + +unsigned short RegisterDialog::getUShort(const std::string &str) +{ + unsigned long l = 0; + for (std::string::const_iterator strPtr = str.begin(), strEnd = str.end(); + strPtr != strEnd; ++strPtr) + { + l = l * 10 + (*strPtr - '0'); + } + return static_cast<unsigned short>(l); +} +#endif diff --git a/src/gui/register.h b/src/gui/register.h index 79578461..fde82a40 100644 --- a/src/gui/register.h +++ b/src/gui/register.h @@ -1,33 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_REGISTER_H -#define _TMW_REGISTER_H +#ifndef REGISTER_H +#define REGISTER_H + +#include <string> -#include <iosfwd> #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> #include "window.h" -#include "../guichanfwd.h" class LoginData; class OkDialog; @@ -82,16 +82,44 @@ class RegisterDialog : public Window, public gcn::ActionListener, * Returns whether submit can be enabled. This is true in the register * state, when all necessary fields have some text. */ - bool - canSubmit(); + bool canSubmit() const; + +#ifdef EATHENA_SUPPORT + /** + * 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); +#endif gcn::TextField *mUserField; gcn::TextField *mPasswordField; gcn::TextField *mConfirmField; +#ifdef EATHENA_SUPPORT + gcn::TextField *mServerField; + gcn::TextField *mPortField; +#else gcn::TextField *mEmailField; +#endif gcn::Button *mRegisterButton; gcn::Button *mCancelButton; +#ifdef EATHENA_SUPPORT + gcn::RadioButton *mMaleButton; + gcn::RadioButton *mFemaleButton; +#endif WrongDataNoticeListener *mWrongDataNoticeListener; diff --git a/src/gui/scrollarea.cpp b/src/gui/scrollarea.cpp index 032e3f78..70504a03 100644 --- a/src/gui/scrollarea.cpp +++ b/src/gui/scrollarea.cpp @@ -1,28 +1,27 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - #include "scrollarea.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -31,20 +30,21 @@ #include "../utils/dtor.h" int ScrollArea::instances = 0; +float ScrollArea::mAlpha = config.getValue("guialpha", 0.8); ImageRect ScrollArea::background; ImageRect ScrollArea::vMarker; Image *ScrollArea::buttons[4][2]; -ScrollArea::ScrollArea(bool gc): +ScrollArea::ScrollArea(): gcn::ScrollArea(), - mGC(gc) + mOpaque(true) { init(); } -ScrollArea::ScrollArea(gcn::Widget *widget, bool gc): +ScrollArea::ScrollArea(gcn::Widget *widget): gcn::ScrollArea(widget), - mGC(gc) + mOpaque(true) { init(); } @@ -52,9 +52,7 @@ ScrollArea::ScrollArea(gcn::Widget *widget, bool gc): ScrollArea::~ScrollArea() { // Garbage collection - if (mGC) { - delete getContent(); - } + delete getContent(); instances--; @@ -88,12 +86,15 @@ void ScrollArea::init() const int bggridy[4] = {0, 3, 28, 31}; int a = 0, x, y; - for (y = 0; y < 3; y++) { - for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) + { + for (x = 0; x < 3; x++) + { background.grid[a] = textbox->getSubImage( bggridx[x], bggridy[y], bggridx[x + 1] - bggridx[x] + 1, bggridy[y + 1] - bggridy[y] + 1); + background.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); a++; } } @@ -106,12 +107,15 @@ void ScrollArea::init() int vsgridy[4] = {0, 4, 15, 19}; a = 0; - for (y = 0; y < 3; y++) { - for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) + { + for (x = 0; x < 3; x++) + { vMarker.grid[a] = vscroll->getSubImage( vsgridx[x], vsgridy[y], vsgridx[x + 1] - vsgridx[x], vsgridy[y + 1] - vsgridy[y]); + vMarker.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); a++; } } @@ -146,7 +150,7 @@ void ScrollArea::logic() // When no scrollbar in a certain direction, adapt content size to match // the content dimension exactly. - if (content != NULL) + if (content) { if (getHorizontalScrollPolicy() == gcn::ScrollArea::SHOW_NEVER) { @@ -188,6 +192,16 @@ void ScrollArea::draw(gcn::Graphics *graphics) mScrollbarWidth)); } + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + for (int a = 0; a < 9; a++) + { + background.grid[a]->setAlpha(mAlpha); + vMarker.grid[a]->setAlpha(mAlpha); + } + } + drawChildren(graphics); } @@ -197,7 +211,8 @@ void ScrollArea::drawFrame(gcn::Graphics *graphics) int w = getWidth() + bs * 2; int h = getHeight() + bs * 2; - if (mOpaque) { + if (mOpaque) + { static_cast<Graphics*>(graphics)-> drawImageRect(0, 0, w, h, background); } @@ -207,10 +222,12 @@ void ScrollArea::setOpaque(bool opaque) { mOpaque = opaque; - if (mOpaque) { + if (mOpaque) + { setFrameSize(2); } - else { + else + { setFrameSize(0); } } @@ -220,7 +237,8 @@ void ScrollArea::drawButton(gcn::Graphics *graphics, BUTTON_DIR dir) int state = 0; gcn::Rectangle dim; - switch(dir) { + switch (dir) + { case UP: state = mUpButtonPressed ? 1 : 0; dim = getUpButtonDimension(); diff --git a/src/gui/scrollarea.h b/src/gui/scrollarea.h index d21dae11..e9aa5ed2 100644 --- a/src/gui/scrollarea.h +++ b/src/gui/scrollarea.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SCROLLAREA_H__ -#define __TMW_SCROLLAREA_H__ +#ifndef SCROLLAREA_H +#define SCROLLAREA_H #include <guichan/widgets/scrollarea.hpp> @@ -30,6 +30,10 @@ class ImageRect; /** * A scroll area. * + * Contrary to Guichan's scroll area, this scroll area takes ownership over its + * content. However, it won't delete a previously set content widget when + * setContent is called! + * * \ingroup GUI */ class ScrollArea : public gcn::ScrollArea @@ -38,12 +42,12 @@ class ScrollArea : public gcn::ScrollArea /** * Constructor. */ - ScrollArea(bool gc = true); + ScrollArea(); /** * Constructor. */ - ScrollArea(gcn::Widget *content, bool gc = true); + ScrollArea(gcn::Widget *content); /** * Destructor. @@ -100,12 +104,12 @@ class ScrollArea : public gcn::ScrollArea void drawHMarker(gcn::Graphics *graphics); static int instances; + static float mAlpha; static ImageRect background; static ImageRect vMarker; static Image *buttons[4][2]; bool mOpaque; - bool mGC; }; #endif diff --git a/src/gui/sdlinput.cpp b/src/gui/sdlinput.cpp index ee94b2c6..51442798 100644 --- a/src/gui/sdlinput.cpp +++ b/src/gui/sdlinput.cpp @@ -7,7 +7,7 @@ * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ * * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson - * Copyright 2007 The Mana World Development Team + * Copyright (C) 2007 The Mana World Development Team * * Js_./ * Per Larsson a.k.a finalman _RqZ{a<^_aa @@ -228,7 +228,7 @@ int SDLInput::convertMouseButton(int button) int SDLInput::convertKeyCharacter(SDL_Event event) { SDL_keysym keysym = event.key.keysym; - + int value = keysym.unicode; switch (keysym.sym) diff --git a/src/gui/sdlinput.h b/src/gui/sdlinput.h index 72d949e1..3901589a 100644 --- a/src/gui/sdlinput.h +++ b/src/gui/sdlinput.h @@ -7,7 +7,7 @@ * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ * * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson - * Copyright 2007 The Mana World Development Team + * Copyright (C) 2007 The Mana World Development Team * * Js_./ * Per Larsson a.k.a finalman _RqZ{a<^_aa @@ -55,8 +55,8 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _TMW_SDLINPUT_ -#define _TMW_SDLINPUT_ +#ifndef SDLINPUT_ +#define SDLINPUT_ #include <queue> diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index 9aee4bee..957ff861 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -1,47 +1,56 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "sell.h" - -#include <cassert> - #include <guichan/widgets/label.hpp> #include "button.h" -#include "shoplistbox.h" #include "scrollarea.h" +#include "sell.h" #include "shop.h" +#include "shoplistbox.h" #include "slider.h" #include "widgets/layout.h" -#include "../item.h" #include "../npc.h" +#include "../units.h" + +#include "../net/messageout.h" +#ifdef TMWSERV_SUPPORT #include "../net/gameserver/player.h" -#include "../resources/iteminfo.h" +#else +#include "../net/ea/protocol.h" +#endif + #include "../utils/gettext.h" #include "../utils/strprintf.h" +#ifdef TMWSERV_SUPPORT SellDialog::SellDialog(): Window(_("Sell")), +#else +SellDialog::SellDialog(Network *network): + Window(_("Sell")), + mNetwork(network), +#endif mMaxItems(0), mAmountItems(0) { setWindowName("Sell"); @@ -50,13 +59,14 @@ SellDialog::SellDialog(): setMinHeight(230); setDefaultSize(0, 0, 260, 230); - mShopItems = new ShopItems(); + mShopItems = new ShopItems; mShopItemList = new ShopListBox(mShopItems, mShopItems); mScrollArea = new ScrollArea(mShopItemList); mSlider = new Slider(1.0); mQuantityLabel = new gcn::Label("0"); - mMoneyLabel = new gcn::Label(strprintf(_("Price: %d GP / Total: %d GP"), 0, 0)); + mMoneyLabel = new gcn::Label(strprintf(_("Price: %s / Total: %s"), + "", "")); mIncreaseButton = new Button("+", "+", this); mDecreaseButton = new Button("-", "-", this); mSellButton = new Button(_("Sell"), "sell", this); @@ -111,12 +121,30 @@ void SellDialog::reset() updateButtonsAndLabels(); } +#ifdef TMWSERV_SUPPORT + void SellDialog::addItem(int item, int amount, int price) { mShopItems->addItem(item, amount, price); mShopItemList->adjustSize(); } +#else + +void SellDialog::addItem(const Item *item, int price) +{ + if (!item) + return; + + mShopItems->addItem( + item->getInvIndex(), item->getId(), + item->getQuantity(), price); + + mShopItemList->adjustSize(); +} + +#endif + void SellDialog::action(const gcn::ActionEvent &event) { int selectedItem = mShopItemList->getSelected(); @@ -124,7 +152,7 @@ void SellDialog::action(const gcn::ActionEvent &event) if (event.getId() == "quit") { setVisible(false); - current_npc = 0; + if (current_npc) current_npc->handleDeath(); return; } @@ -155,8 +183,17 @@ void SellDialog::action(const gcn::ActionEvent &event) else if (event.getId() == "sell" && mAmountItems > 0 && mAmountItems <= mMaxItems) { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::tradeWithNPC (mShopItems->at(selectedItem)->getId(), mAmountItems); +#else + // Attempt sell + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_SELL_REQUEST); + outMsg.writeInt16(8); + outMsg.writeInt16(mShopItems->at(selectedItem)->getInvIndex()); + outMsg.writeInt16(mAmountItems); +#endif mMaxItems -= mAmountItems; mShopItems->getShop()->at(selectedItem)->setQuantity(mMaxItems); @@ -239,7 +276,7 @@ void SellDialog::updateButtonsAndLabels() // Update the quantity and money labels mQuantityLabel->setCaption(strprintf("%d / %d", mAmountItems, mMaxItems)); - mMoneyLabel->setCaption - (strprintf(_("Price: %d GP / Total: %d GP"), - income, mPlayerMoney + income)); + mMoneyLabel->setCaption(strprintf(_("Price: %s / Total: %s"), + Units::formatCurrency(income).c_str(), + Units::formatCurrency(mPlayerMoney - income).c_str())); } diff --git a/src/gui/sell.h b/src/gui/sell.h index 742c28fb..f64a6fd5 100644 --- a/src/gui/sell.h +++ b/src/gui/sell.h @@ -1,35 +1,38 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SELL_H -#define _TMW_SELL_H +#ifndef SELL_H +#define SELL_H #include <guichan/actionlistener.hpp> #include <guichan/selectionlistener.hpp> -#include "window.h" +#include <SDL_types.h> -#include "../guichanfwd.h" +#include "window.h" class Item; +#ifdef EATHENA_SUPPORT +class Network; +#endif class ShopItems; class ShopListBox; @@ -46,7 +49,11 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener * * @see Window::Window */ +#ifdef TMWSERV_SUPPORT SellDialog(); +#else + SellDialog(Network *network); +#endif /** * Destructor @@ -61,7 +68,11 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener /** * Adds an item to the inventory. */ +#ifdef TMWSERV_SUPPORT void addItem(int item, int amount, int price); +#else + void addItem(const Item *item, int price); +#endif /** * Called when receiving actions from the widgets. @@ -86,6 +97,9 @@ class SellDialog : public Window, gcn::ActionListener, gcn::SelectionListener */ void updateButtonsAndLabels(); +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif gcn::Button *mSellButton; gcn::Button *mQuitButton; gcn::Button *mIncreaseButton; diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index b11aea6c..a8074b0c 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -41,7 +41,7 @@ #include "../main.h" #include "../utils/gettext.h" -#include "../utils/tostring.h" +#include "../utils/stringutils.h" const short MAX_SERVERLIST = 5; diff --git a/src/gui/setup.cpp b/src/gui/setup.cpp index 59b54be0..c8b7f900 100644 --- a/src/gui/setup.cpp +++ b/src/gui/setup.cpp @@ -1,71 +1,80 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - -#include "setup.h" - #include "button.h" +#include "setup.h" #include "setup_audio.h" +#include "setup_colors.h" #include "setup_joystick.h" -#include "setup_video.h" #include "setup_keyboard.h" +#include "setup_players.h" +#include "setup_video.h" #include "widgets/tabbedarea.h" #include "../utils/dtor.h" #include "../utils/gettext.h" -extern Window *statusWindow; -extern Window *minimap; extern Window *chatWindow; -extern Window *inventoryWindow; extern Window *equipmentWindow; extern Window *helpWindow; +extern Window *inventoryWindow; +extern Window *minimap; extern Window *skillDialog; +extern Window *statusWindow; +extern Window *itemShortcutWindow; +extern Window *emoteShortcutWindow; +extern Window *emoteWindow; +extern Window *tradeWindow; +#ifdef TMWSERV_SUPPORT extern Window *magicDialog; extern Window *guildWindow; -extern Window *itemShortcutWindow; +#endif Setup::Setup(): Window(_("Setup")) { setCloseButton(true); - int width = 260; - int height = 265; + int width = 340; + int height = 340; setContentSize(width, height); static const char *buttonNames[] = { N_("Apply"), N_("Cancel"), N_("Reset Windows"), 0 }; int x = width; - for (const char **curBtn = buttonNames; *curBtn; ++curBtn) { + for (const char **curBtn = buttonNames; *curBtn; ++curBtn) + { Button *btn = new Button(gettext(*curBtn), *curBtn, this); x -= btn->getWidth() + 5; btn->setPosition(x, height - btn->getHeight() - 5); add(btn); + + // Disable this button when the windows aren't created yet + if (!strcmp(*curBtn, "Reset Windows")) + btn->setEnabled(statusWindow != NULL); } - TabbedArea *panel = new TabbedArea(); - panel->setDimension(gcn::Rectangle(5, 5, 260, 225)); + TabbedArea *panel = new TabbedArea; + panel->setDimension(gcn::Rectangle(5, 5, width - 10, height - 40)); SetupTab *tab; @@ -85,6 +94,14 @@ Setup::Setup(): panel->addTab(_("Keyboard"), tab); mTabs.push_back(tab); + tab = new Setup_Colors(); + panel->addTab(_("Colors"), tab); + mTabs.push_back(tab); + + tab = new Setup_Players(); + panel->addTab(_("Players"), tab); + mTabs.push_back(tab); + add(panel); setLocationRelativeTo(getParent()); @@ -109,6 +126,11 @@ void Setup::action(const gcn::ActionEvent &event) } else if (event.getId() == "Reset Windows") { + // Bail out if this action happens to be activated before the windows + // are created (though it should be disabled then) + if (!statusWindow) + return; + statusWindow->resetToDefaultSize(); minimap->resetToDefaultSize(); chatWindow->resetToDefaultSize(); @@ -116,8 +138,13 @@ void Setup::action(const gcn::ActionEvent &event) equipmentWindow->resetToDefaultSize(); helpWindow->resetToDefaultSize(); skillDialog->resetToDefaultSize(); + itemShortcutWindow->resetToDefaultSize(); + emoteShortcutWindow->resetToDefaultSize(); + emoteWindow->resetToDefaultSize(); + tradeWindow->resetToDefaultSize(); +#ifdef TMWSERV_SUPPORT magicDialog->resetToDefaultSize(); guildWindow->resetToDefaultSize(); - itemShortcutWindow->resetToDefaultSize(); +#endif } } diff --git a/src/gui/setup.h b/src/gui/setup.h index 2142a67d..e4eb0902 100644 --- a/src/gui/setup.h +++ b/src/gui/setup.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SETUP_H -#define _TMW_SETUP_H +#ifndef SETUP_H +#define SETUP_H #include <list> @@ -28,6 +28,8 @@ #include "window.h" +#include "../guichanfwd.h" + class SetupTab; /** @@ -51,8 +53,7 @@ class Setup : public Window, public gcn::ActionListener /** * Event handling method. */ - void - action(const gcn::ActionEvent &event); + void action(const gcn::ActionEvent &event); private: std::list<SetupTab*> mTabs; diff --git a/src/gui/setup_audio.cpp b/src/gui/setup_audio.cpp index 4f09cde0..43cc28e6 100644 --- a/src/gui/setup_audio.cpp +++ b/src/gui/setup_audio.cpp @@ -1,32 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup_audio.h" - #include <guichan/widgets/label.hpp> #include "checkbox.h" #include "ok_dialog.h" +#include "setup_audio.h" #include "slider.h" +#include "widgets/layouthelper.h" + #include "../configuration.h" #include "../log.h" #include "../sound.h" @@ -54,19 +55,24 @@ Setup_Audio::Setup_Audio(): mMusicSlider->addActionListener(this); mSoundCheckBox->setPosition(10, 10); - mSfxSlider->setDimension(gcn::Rectangle(10, 30, 100, 10)); - mMusicSlider->setDimension(gcn::Rectangle(10, 50, 100, 10)); - sfxLabel->setPosition(20 + mSfxSlider->getWidth(), 27); - musicLabel->setPosition(20 + mMusicSlider->getWidth(), 47); mSfxSlider->setValue(mSfxVolume); mMusicSlider->setValue(mMusicVolume); - add(mSoundCheckBox); - add(mSfxSlider); - add(mMusicSlider); - add(sfxLabel); - add(musicLabel); + mSfxSlider->setWidth(90); + mMusicSlider->setWidth(90); + + // Do the layout + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, mSoundCheckBox); + place(0, 1, mSfxSlider); + place(1, 1, sfxLabel); + place(0, 2, mMusicSlider); + place(1, 2, musicLabel); + + setDimension(gcn::Rectangle(0, 0, 325, 280)); } void Setup_Audio::apply() @@ -104,8 +110,8 @@ void Setup_Audio::cancel() sound.setMusicVolume(mMusicVolume); mMusicSlider->setValue(mMusicVolume); - config.setValue("sound", mSoundEnabled ? 1 : 0); - config.setValue("sfxVolume", mSfxVolume ? 1 : 0); + config.setValue("sound", mSoundEnabled ? true : false); + config.setValue("sfxVolume", mSfxVolume); config.setValue("musicVolume", mMusicVolume); } diff --git a/src/gui/setup_audio.h b/src/gui/setup_audio.h index eaa55de6..9e951895 100644 --- a/src/gui/setup_audio.h +++ b/src/gui/setup_audio.h @@ -1,32 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUI_SETUP_AUDIO_H -#define _TMW_GUI_SETUP_AUDIO_H - -#include "setuptab.h" +#ifndef GUI_SETUP_AUDIO_H +#define GUI_SETUP_AUDIO_H #include <guichan/actionlistener.hpp> -#include "../guichanfwd.h" +#include "setuptab.h" class Setup_Audio : public SetupTab, public gcn::ActionListener { diff --git a/src/gui/setup_colors.cpp b/src/gui/setup_colors.cpp new file mode 100644 index 00000000..49c99996 --- /dev/null +++ b/src/gui/setup_colors.cpp @@ -0,0 +1,249 @@ +/* + * Configurable text colors + * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string> +#include <cmath> + +#include <guichan/listmodel.hpp> +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/slider.hpp> + +#include "browserbox.h" +#include "color.h" +#include "itemlinkhandler.h" +#include "listbox.h" +#include "scrollarea.h" +#include "setup_colors.h" +#include "slider.h" +#include "textfield.h" + +#include "widgets/layouthelper.h" + +#include "../configuration.h" + +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +Setup_Colors::Setup_Colors() : + mSelected(-1) +{ + setOpaque(false); + + mColorBox = new ListBox(textColor); + mColorBox->setActionEventId("color_box"); + mColorBox->addActionListener(this); + + mScroll = new ScrollArea(mColorBox); + mScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + + mPreview = new BrowserBox(BrowserBox::AUTO_WRAP); + mPreview->setOpaque(false); + + // Replace this later with a more appropriate link handler. For now, this'll + // do, as it'll do nothing when clicked on. + mPreview->setLinkHandler(new ItemLinkHandler); + + mPreviewBox = new ScrollArea(mPreview); + mPreviewBox->setHeight(20); + mPreviewBox->setScrollPolicy(gcn::ScrollArea::SHOW_NEVER, + gcn::ScrollArea::SHOW_NEVER); + + mRedLabel = new gcn::Label(_("Red: ")); + + mRedText = new TextField; + mRedText->setWidth(40); + mRedText->setRange(0, 255); + mRedText->setNumeric(true); + mRedText->addListener(this); + + mRedSlider = new Slider(0, 255); + mRedSlider->setWidth(160); + mRedSlider->setValue(mRedText->getValue()); + mRedSlider->setActionEventId("slider_red"); + mRedSlider->addActionListener(this); + + mGreenLabel = new gcn::Label(_("Green: ")); + + mGreenText = new TextField; + mGreenText->setWidth(40); + mGreenText->setRange(0, 255); + mGreenText->setNumeric(true); + mGreenText->addListener(this); + + mGreenSlider = new Slider(0, 255); + mGreenSlider->setWidth(160); + mGreenSlider->setValue(mGreenText->getValue()); + mGreenSlider->setActionEventId("slider_green"); + mGreenSlider->addActionListener(this); + + mBlueLabel = new gcn::Label(_("Blue: ")); + + mBlueText = new TextField; + mBlueText->setWidth(40); + mBlueText->setRange(0, 255); + mBlueText->setNumeric(true); + mBlueText->addListener(this); + + mBlueSlider = new Slider(0, 255); + mBlueSlider->setWidth(160); + mBlueSlider->setValue(mBlueText->getValue()); + mBlueSlider->setActionEventId("slider_blue"); + mBlueSlider->addActionListener(this); + + setOpaque(false); + + // Do the layout + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, mScroll, 4, 7).setPadding(2); + place(0, 7, mPreviewBox, 4).setPadding(2); + place(0, 8, mRedLabel, 2); + place(2, 8, mRedSlider); + place(3, 8, mRedText).setPadding(1); + place(0, 9, mGreenLabel, 2); + place(2, 9, mGreenSlider); + place(3, 9, mGreenText).setPadding(1); + place(0, 10, mBlueLabel, 2); + place(2, 10, mBlueSlider); + place(3, 10, mBlueText).setPadding(1); + + setDimension(gcn::Rectangle(0, 0, 325, 280)); +} + +Setup_Colors::~Setup_Colors() +{ + delete mRedLabel; + delete mRedSlider; + delete mRedText; + + delete mGreenLabel; + delete mGreenSlider; + delete mGreenText; + + delete mBlueLabel; + delete mBlueSlider; + delete mBlueText; + + delete mScroll; +} + +void Setup_Colors::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "color_box") + { + mSelected = mColorBox->getSelected(); + int col = textColor->getColorAt(mSelected); + char ch = textColor->getColorCharAt(mSelected); + std::string msg; + + if (ch == '<') + msg = toString("@@|") + + _("This is what the color looks like") + "@@"; + else + msg = "##" + toString(ch) + + _("This is what the color looks like"); + + mPreview->clearRows(); + mPreview->addRow(msg); + setEntry(mRedSlider, mRedText, col >> 16); + setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff); + setEntry(mBlueSlider, mBlueText, col & 0xff); + return; + } + + if (event.getId() == "slider_red") + { + mRedText->setText(toString(std::floor(mRedSlider->getValue()))); + updateColor(); + return; + } + + if (event.getId() == "slider_green") + { + mGreenText->setText(toString(std::floor(mGreenSlider->getValue()))); + updateColor(); + return; + } + + if (event.getId() == "slider_blue") + { + mBlueText->setText(toString(std::floor(mBlueSlider->getValue()))); + updateColor(); + return; + } +} + +void Setup_Colors::setEntry(gcn::Slider *s, TextField *t, int value) +{ + s->setValue(value); + char buffer[100]; + sprintf(buffer, "%d", value); + t->setText(buffer); +} + +void Setup_Colors::apply() +{ + textColor->commit(); +} + +void Setup_Colors::cancel() +{ + textColor->rollback(); + int col = textColor->getColorAt(mSelected); + setEntry(mRedSlider, mRedText, col >> 16); + setEntry(mGreenSlider, mGreenText, (col >> 8) & 0xff); + setEntry(mBlueSlider, mBlueText, col & 0xff); +} + +void Setup_Colors::listen(const TextField *tf) +{ + if (tf == mRedText) + { + mRedSlider->setValue(tf->getValue()); + updateColor(); + return; + } + if (tf == mGreenText) + { + mGreenSlider->setValue(tf->getValue()); + updateColor(); + return; + } + if (tf == mBlueText) + { + mBlueSlider->setValue(tf->getValue()); + updateColor(); + return; + } +} + +void Setup_Colors::updateColor() +{ + if (mSelected == -1) + { + return; + } + int rgb = static_cast<int>(mRedSlider->getValue()) << 16 | + static_cast<int>(mGreenSlider->getValue()) << 8 | + static_cast<int>(mBlueSlider->getValue()); + textColor->setColorAt(mSelected, rgb); +} diff --git a/src/gui/setup_colors.h b/src/gui/setup_colors.h new file mode 100644 index 00000000..2831297f --- /dev/null +++ b/src/gui/setup_colors.h @@ -0,0 +1,75 @@ +/* + * Configurable text colors + * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SETUP_COLORS_H +#define SETUP_COLORS_H + +#include <string> + +#include <guichan/actionlistener.hpp> + +#include <guichan/widgets/label.hpp> +#include <guichan/widgets/listbox.hpp> + +#include "setuptab.h" +#include "textfield.h" + +#include "../guichanfwd.h" + +class BrowserBox; + +class Setup_Colors : public SetupTab, public gcn::ActionListener, + public TextFieldListener +{ + public: + Setup_Colors(); + ~Setup_Colors(); + void apply(); + void cancel(); + void action(const gcn::ActionEvent &event); + + void listen(const TextField *tf); + private: + gcn::ListBox *mColorBox; + gcn::ScrollArea *mScroll; + BrowserBox *mPreview; + gcn::ScrollArea *mPreviewBox; + int mSelected; + + gcn::Label *mRedLabel; + gcn::Slider *mRedSlider; + TextField *mRedText; + int mRedValue; + + gcn::Label *mGreenLabel; + gcn::Slider *mGreenSlider; + TextField *mGreenText; + int mGreenValue; + + gcn::Label *mBlueLabel; + gcn::Slider *mBlueSlider; + TextField *mBlueText; + int mBlueValue; + + void setEntry(gcn::Slider *s, TextField *t, int value); + void updateColor(); +}; +#endif diff --git a/src/gui/setup_joystick.cpp b/src/gui/setup_joystick.cpp index 9de5be9f..c0c04949 100644 --- a/src/gui/setup_joystick.cpp +++ b/src/gui/setup_joystick.cpp @@ -1,30 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "setup_joystick.h" - #include <guichan/widgets/label.hpp> #include "button.h" #include "checkbox.h" +#include "setup_joystick.h" + +#include "widgets/layouthelper.h" + #include "../configuration.h" #include "../joystick.h" @@ -38,25 +40,29 @@ Setup_Joystick::Setup_Joystick(): mJoystickEnabled(new CheckBox(_("Enable joystick"))) { setOpaque(false); - setDimension(gcn::Rectangle(0, 0, 250, 200)); - mJoystickEnabled->setPosition(10, 10); - mCalibrateLabel->setPosition(10, 25); - mCalibrateButton->setPosition(10, 30 + mCalibrateLabel->getHeight()); - - mOriginalJoystickEnabled = (int)config.getValue("joystickEnabled", 0) != 0; + mOriginalJoystickEnabled = !config.getValue("joystickEnabled", false); mJoystickEnabled->setSelected(mOriginalJoystickEnabled); mJoystickEnabled->addActionListener(this); - add(mCalibrateLabel); - add(mCalibrateButton); - add(mJoystickEnabled); + // Do the layout + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, mJoystickEnabled); + place(0, 1, mCalibrateLabel); + place.getCell().matchColWidth(0, 0); + place = h.getPlacer(0, 1); + place(0, 0, mCalibrateButton); + + setDimension(gcn::Rectangle(0, 0, 325, 75)); } void Setup_Joystick::action(const gcn::ActionEvent &event) { - if (!joystick) { + if (!joystick) + { return; } @@ -66,12 +72,15 @@ void Setup_Joystick::action(const gcn::ActionEvent &event) } else { - if (joystick->isCalibrating()) { + if (joystick->isCalibrating()) + { mCalibrateButton->setCaption(_("Calibrate")); mCalibrateLabel->setCaption (_("Press the button to start calibration")); joystick->finishCalibration(); - } else { + } + else + { mCalibrateButton->setCaption(_("Stop")); mCalibrateLabel->setCaption(_("Rotate the stick")); joystick->startCalibration(); diff --git a/src/gui/setup_joystick.h b/src/gui/setup_joystick.h index 0b7ebe98..eba8a2cc 100644 --- a/src/gui/setup_joystick.h +++ b/src/gui/setup_joystick.h @@ -1,32 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUI_SETUP_JOYSTICK_H -#define _TMW_GUI_SETUP_JOYSTICK_H - -#include "setuptab.h" +#ifndef GUI_SETUP_JOYSTICK_H +#define GUI_SETUP_JOYSTICK_H #include <guichan/actionlistener.hpp> -#include "../guichanfwd.h" +#include "setuptab.h" class Setup_Joystick : public SetupTab, public gcn::ActionListener { diff --git a/src/gui/setup_keyboard.cpp b/src/gui/setup_keyboard.cpp index e4d1af0c..aba8cf35 100644 --- a/src/gui/setup_keyboard.cpp +++ b/src/gui/setup_keyboard.cpp @@ -1,25 +1,26 @@ /* - * The Mana World - * Copyright 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> + * Copyright (C) 2009 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * 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 +29,14 @@ #include "listbox.h" #include "ok_dialog.h" #include "scrollarea.h" +#include "setup_keyboard.h" + +#include "widgets/layouthelper.h" -#include "../configuration.h" #include "../keyboardconfig.h" #include "../utils/gettext.h" -#include "../utils/tostring.h" - -#include <SDL_keyboard.h> +#include "../utils/stringutils.h" /** * The list model for key function list. @@ -68,34 +69,36 @@ class KeyListModel : public gcn::ListModel }; Setup_Keyboard::Setup_Keyboard(): - mKeyListModel(new KeyListModel()), + mKeyListModel(new KeyListModel), mKeyList(new ListBox(mKeyListModel)), mKeySetting(false) { keyboard.setSetupKeyboard(this); setOpaque(false); - setDimension(gcn::Rectangle(0, 0, 250, 200)); refreshKeys(); - mKeyList->setDimension(gcn::Rectangle(0, 0, 185, 140)); mKeyList->addActionListener(this); - mKeyList->setSelected(-1); ScrollArea *scrollArea = new ScrollArea(mKeyList); - scrollArea->setDimension(gcn::Rectangle(10, 10, 200, 140)); - add(scrollArea); + scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mAssignKeyButton = new Button(_("Assign"), "assign", this); - mAssignKeyButton->setPosition(165, 155); mAssignKeyButton->addActionListener(this); mAssignKeyButton->setEnabled(false); - add(mAssignKeyButton); mMakeDefaultButton = new Button(_("Default"), "makeDefault", this); - mMakeDefaultButton->setPosition(10, 155); mMakeDefaultButton->addActionListener(this); - add(mMakeDefaultButton); + + // Do the layout + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, scrollArea, 4, 6).setPadding(2); + place(0, 6, mMakeDefaultButton); + place(3, 6, mAssignKeyButton); + + setDimension(gcn::Rectangle(0, 0, 325, 280)); } Setup_Keyboard::~Setup_Keyboard() @@ -135,9 +138,8 @@ void Setup_Keyboard::action(const gcn::ActionEvent &event) { if (event.getSource() == mKeyList) { - if (!mKeySetting) { + if (!mKeySetting) mAssignKeyButton->setEnabled(true); - } } else if (event.getId() == "assign") { @@ -181,7 +183,8 @@ void Setup_Keyboard::refreshKeys() void Setup_Keyboard::keyUnresolved() { - if (mKeySetting) { + if (mKeySetting) + { newKeyCallback(keyboard.getNewKeyIndex()); keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE); } diff --git a/src/gui/setup_keyboard.h b/src/gui/setup_keyboard.h index 50fa76fb..dee12135 100644 --- a/src/gui/setup_keyboard.h +++ b/src/gui/setup_keyboard.h @@ -1,35 +1,34 @@ /* - * The Mana World - * Copyright 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUI_SETUP_KEYBOARD_H -#define _TMW_GUI_SETUP_KEYBOARD_H +#ifndef GUI_SETUP_KEYBOARD_H +#define GUI_SETUP_KEYBOARD_H -#include "setuptab.h" -#include "button.h" -#include "../guichanfwd.h" +#include <string> #include <guichan/actionlistener.hpp> +#include "setuptab.h" -#include <string> +#include "../guichanfwd.h" class Setup_Keyboard : public SetupTab, public gcn::ActionListener { diff --git a/src/gui/setup_players.cpp b/src/gui/setup_players.cpp new file mode 100644 index 00000000..96792436 --- /dev/null +++ b/src/gui/setup_players.cpp @@ -0,0 +1,388 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string> +#include <vector> + +#include <guichan/widgets/label.hpp> + +#include "button.h" +#include "checkbox.h" +#include "listbox.h" +#include "ok_dialog.h" +#include "scrollarea.h" +#include "setup_players.h" +#include "table.h" + +#include "widgets/dropdown.h" +#include "widgets/layouthelper.h" + +#include "../configuration.h" +#include "../log.h" + +#include "../utils/gettext.h" + +#define COLUMNS_NR 2 // name plus listbox +#define NAME_COLUMN 0 +#define RELATION_CHOICE_COLUMN 1 + +#define ROW_HEIGHT 12 +// The following column widths really shouldn't be hardcoded but should scale with the size of the widget... except +// that, right now, the widget doesn't exactly scale either. +#define NAME_COLUMN_WIDTH 230 +#define RELATION_CHOICE_COLUMN_WIDTH 80 + +#define WIDGET_AT(row, column) (((row) * COLUMNS_NR) + column) + +static const char *table_titles[COLUMNS_NR] = +{ + N_("Name"), + N_("Relation") +}; + +static const char *RELATION_NAMES[PlayerRelation::RELATIONS_NR] = +{ + N_("Neutral"), + N_("Friend"), + N_("Disregarded"), + N_("Ignored") +}; + +class PlayerRelationListModel : public gcn::ListModel +{ +public: + virtual ~PlayerRelationListModel() { } + + virtual int getNumberOfElements() + { + return PlayerRelation::RELATIONS_NR; + } + + virtual std::string getElementAt(int i) + { + if (i >= getNumberOfElements() || i < 0) + return ""; + return gettext(RELATION_NAMES[i]); + } +}; + +class PlayerTableModel : public TableModel +{ +public: + PlayerTableModel() : + mPlayers(NULL) + { + playerRelationsUpdated(); + } + + virtual ~PlayerTableModel() + { + freeWidgets(); + if (mPlayers) + delete mPlayers; + } + + virtual int getRows() + { + return mPlayers->size(); + } + + virtual int getColumns() + { + return COLUMNS_NR; + } + + virtual int getRowHeight() + { + return ROW_HEIGHT; + } + + virtual int getColumnWidth(int index) + { + if (index == NAME_COLUMN) + return NAME_COLUMN_WIDTH; + else + return RELATION_CHOICE_COLUMN_WIDTH; + } + + virtual void playerRelationsUpdated() + { + signalBeforeUpdate(); + + freeWidgets(); + std::vector<std::string> *player_names = player_relations.getPlayers(); + if (mPlayers) + delete mPlayers; + mPlayers = player_names; + + // set up widgets + for (unsigned int r = 0; r < player_names->size(); ++r) + { + std::string name = (*player_names)[r]; + gcn::Widget *widget = new gcn::Label(name); + mWidgets.push_back(widget); + gcn::ListModel *playerRelation = new PlayerRelationListModel; + + gcn::DropDown *choicebox = new DropDown(playerRelation, + new ScrollArea, + new ListBox(playerRelation), + false); + choicebox->setSelected(player_relations.getRelation(name)); + mWidgets.push_back(choicebox); + } + + signalAfterUpdate(); + } + + virtual void updateModelInRow(int row) + { + gcn::DropDown *choicebox = dynamic_cast<gcn::DropDown *>( + getElementAt(row, RELATION_CHOICE_COLUMN)); + player_relations.setRelation(getPlayerAt(row), + static_cast<PlayerRelation::relation>( + choicebox->getSelected())); + } + + + virtual gcn::Widget *getElementAt(int row, int column) + { + return mWidgets[WIDGET_AT(row, column)]; + } + + virtual void freeWidgets() + { + if (mPlayers) + delete mPlayers; + mPlayers = NULL; + + for (std::vector<gcn::Widget *>::const_iterator it = mWidgets.begin(); + it != mWidgets.end(); it++) + { + delete *it; + } + + mWidgets.clear(); + } + + std::string getPlayerAt(int index) + { + return (*mPlayers)[index]; + } + +protected: + std::vector<std::string> *mPlayers; + std::vector<gcn::Widget *> mWidgets; +}; + +/** + * Class for choosing one of the various `what to do when ignoring a player' options + */ +class IgnoreChoicesListModel : public gcn::ListModel +{ +public: + virtual ~IgnoreChoicesListModel() { } + + virtual int getNumberOfElements() + { + return player_relations.getPlayerIgnoreStrategies()->size(); + } + + virtual std::string getElementAt(int i) + { + if (i >= getNumberOfElements()) + return _("???"); + + return (*player_relations.getPlayerIgnoreStrategies())[i]->mDescription; + } +}; + +#define ACTION_DELETE "delete" +#define ACTION_TABLE "table" +#define ACTION_STRATEGY "strategy" + +Setup_Players::Setup_Players(): + mPlayerTableTitleModel(new StaticTableModel(1, COLUMNS_NR)), + mPlayerTableModel(new PlayerTableModel), + mPlayerTable(new GuiTable(mPlayerTableModel)), + mPlayerTitleTable(new GuiTable(mPlayerTableTitleModel)), + mPlayerScrollArea(new ScrollArea(mPlayerTable)), + mPersistIgnores(new CheckBox(_("Save player list"), + player_relations.getPersistIgnores())), + mDefaultTrading(new CheckBox(_("Allow trading"), + player_relations.getDefault() & PlayerRelation::TRADE)), + mDefaultWhisper(new CheckBox(_("Allow whispers"), + player_relations.getDefault() & PlayerRelation::WHISPER)), + mDeleteButton(new Button(_("Delete"), ACTION_DELETE, this)) +{ + setOpaque(false); + mPlayerTable->setOpaque(false); + + mPlayerTableTitleModel->fixColumnWidth(NAME_COLUMN, NAME_COLUMN_WIDTH); + mPlayerTableTitleModel->fixColumnWidth(RELATION_CHOICE_COLUMN, + RELATION_CHOICE_COLUMN_WIDTH); + mPlayerTitleTable->setBackgroundColor(gcn::Color(0xbf, 0xbf, 0xbf)); + + gcn::ListModel *ignoreChoices = new IgnoreChoicesListModel; + mIgnoreActionChoicesBox = new DropDown(ignoreChoices, new ScrollArea, + new ListBox(ignoreChoices), false); + + for (int i = 0; i < COLUMNS_NR; i++) + { + mPlayerTableTitleModel->set(0, i, + new gcn::Label(gettext(table_titles[i]))); + } + + mPlayerTitleTable->setLinewiseSelection(true); + + mPlayerScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mPlayerTable->setActionEventId(ACTION_TABLE); + mPlayerTable->setLinewiseSelection(true); + mPlayerTable->addActionListener(this); + + gcn::Label *ignore_action_label = new gcn::Label(_("When ignoring:")); + + mIgnoreActionChoicesBox->setActionEventId(ACTION_STRATEGY); + mIgnoreActionChoicesBox->addActionListener(this); + + int ignore_strategy_index = 0; // safe default + + if (player_relations.getPlayerIgnoreStrategy()) + { + ignore_strategy_index = player_relations.getPlayerIgnoreStrategyIndex( + player_relations.getPlayerIgnoreStrategy()->mShortName); + if (ignore_strategy_index < 0) + ignore_strategy_index = 0; + } + mIgnoreActionChoicesBox->setSelected(ignore_strategy_index); + mIgnoreActionChoicesBox->adjustHeight(); + + reset(); + + // Do the layout + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, mPlayerTitleTable, 4); + place(0, 1, mPlayerScrollArea, 4, 4).setPadding(2); + place(0, 5, mDeleteButton); + place(2, 5, ignore_action_label); + place(2, 6, mIgnoreActionChoicesBox, 2).setPadding(2); + place(2, 7, mPersistIgnores); + place(2, 8, mDefaultTrading); + place(2, 9, mDefaultWhisper); + + player_relations.addListener(this); + + setDimension(gcn::Rectangle(0, 0, 325, 280)); +} + +Setup_Players::~Setup_Players() +{ + player_relations.removeListener(this); +} + + +void Setup_Players::reset() +{ + // We now have to search through the list of ignore choices to find the + // current selection. We could use an index into the table of config + // options in player_relations instead of strategies to sidestep this. + int selection = 0; + for (unsigned int i = 0; + i < player_relations.getPlayerIgnoreStrategies()->size(); + ++i) + if ((*player_relations.getPlayerIgnoreStrategies())[i] == + player_relations.getPlayerIgnoreStrategy()) + { + + selection = i; + break; + } + + mIgnoreActionChoicesBox->setSelected(selection); +} + +void Setup_Players::apply() +{ + player_relations.setPersistIgnores(mPersistIgnores->isSelected()); + player_relations.store(); + + unsigned int old_default_relations = player_relations.getDefault() & + ~(PlayerRelation::TRADE | + PlayerRelation::WHISPER); + player_relations.setDefault(old_default_relations + | (mDefaultTrading->isSelected() ? + PlayerRelation::TRADE : 0) + | (mDefaultWhisper->isSelected() ? + PlayerRelation::WHISPER : 0)); +} + +void Setup_Players::cancel() +{ +} + +void Setup_Players::action(const gcn::ActionEvent &event) +{ + if (event.getId() == ACTION_TABLE) + { + // temporarily eliminate ourselves: we are fully aware of this change, + // so there is no need for asynchronous updates. (In fact, thouse + // might destroy the widet that triggered them, which would be rather + // embarrassing.) + player_relations.removeListener(this); + + int row = mPlayerTable->getSelectedRow(); + if (row >= 0) + mPlayerTableModel->updateModelInRow(row); + + player_relations.addListener(this); + + } + else if (event.getId() == ACTION_DELETE) + { + int player_index = mPlayerTable->getSelectedRow(); + + if (player_index < 0) + return; + + std::string name = mPlayerTableModel->getPlayerAt(player_index); + + player_relations.removePlayer(name); + + } + else if (event.getId() == ACTION_STRATEGY) + { + PlayerIgnoreStrategy *s = + (*player_relations.getPlayerIgnoreStrategies())[ + mIgnoreActionChoicesBox->getSelected()]; + + player_relations.setPlayerIgnoreStrategy(s); + } +} + +void Setup_Players::updatedPlayer(const std::string &name) +{ + mPlayerTableModel->playerRelationsUpdated(); + mDefaultTrading->setSelected( + player_relations.getDefault() & PlayerRelation::TRADE); + mDefaultWhisper->setSelected( + player_relations.getDefault() & PlayerRelation::WHISPER); +} diff --git a/src/gui/setup_players.h b/src/gui/setup_players.h new file mode 100644 index 00000000..72d81f71 --- /dev/null +++ b/src/gui/setup_players.h @@ -0,0 +1,67 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GUI_SETUP_PLAYERS_H +#define GUI_SETUP_PLAYERS_H + +#include <guichan/actionlistener.hpp> + +#include "setuptab.h" + +#include "../player_relations.h" + +class GuiTable; +class PlayerTableModel; +class StaticTableModel; + +class Setup_Players : public SetupTab, + public gcn::ActionListener, + public PlayerRelationsListener +{ +public: + Setup_Players(); + virtual ~Setup_Players(); + + void apply(); + void cancel(); + + void reset(); + + void action(const gcn::ActionEvent &event); + + virtual void updatedPlayer(const std::string &name); + +private: + StaticTableModel *mPlayerTableTitleModel; + PlayerTableModel *mPlayerTableModel; + GuiTable *mPlayerTable; + GuiTable *mPlayerTitleTable; + gcn::ScrollArea *mPlayerScrollArea; + + gcn::CheckBox *mPersistIgnores; + gcn::CheckBox *mDefaultTrading; + gcn::CheckBox *mDefaultWhisper; + + gcn::Button *mDeleteButton; + gcn::DropDown *mIgnoreActionChoicesBox; +}; + +#endif diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index bac342a0..526c67ce 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -1,29 +1,27 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * 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,16 +32,21 @@ #include "listbox.h" #include "ok_dialog.h" #include "scrollarea.h" +#include "setup_video.h" #include "slider.h" #include "textfield.h" +#include "widgets/layouthelper.h" + #include "../configuration.h" #include "../graphics.h" +#include "../localplayer.h" #include "../log.h" #include "../main.h" +#include "../particle.h" #include "../utils/gettext.h" -#include "../utils/tostring.h" +#include "../utils/stringutils.h" extern Graphics *graphics; @@ -101,18 +104,25 @@ ModeListModel::ModeListModel() } Setup_Video::Setup_Video(): - mFullScreenEnabled(config.getValue("screen", 0)), - mOpenGLEnabled(config.getValue("opengl", 0)), - mCustomCursorEnabled(config.getValue("customcursor", 1)), + mFullScreenEnabled(config.getValue("screen", false)), + mOpenGLEnabled(config.getValue("opengl", false)), + mCustomCursorEnabled(config.getValue("customcursor", true)), mVisibleNamesEnabled(config.getValue("visiblenames", 1)), + mParticleEffectsEnabled(config.getValue("particleeffects", true)), + mNameEnabled(config.getValue("showownname", false)), mOpacity(config.getValue("guialpha", 0.8)), mFps((int) config.getValue("fpslimit", 0)), + mSpeechMode((int) config.getValue("speech", 3)), mModeListModel(new ModeListModel), mModeList(new ListBox(mModeListModel)), mFsCheckBox(new CheckBox(_("Full screen"), mFullScreenEnabled)), mOpenGLCheckBox(new CheckBox(_("OpenGL"), mOpenGLEnabled)), mCustomCursorCheckBox(new CheckBox(_("Custom cursor"), mCustomCursorEnabled)), mVisibleNamesCheckBox(new CheckBox(_("Visible names"), mVisibleNamesEnabled)), + mParticleEffectsCheckBox(new CheckBox(_("Particle effects"), mParticleEffectsEnabled)), + mNameCheckBox(new CheckBox(_("Show name"), mNameEnabled)), + mSpeechSlider(new Slider(0, 3)), + mSpeechLabel(new gcn::Label("")), mAlphaSlider(new Slider(0.2, 1.0)), mFpsCheckBox(new CheckBox(_("FPS Limit:"))), mFpsSlider(new Slider(10, 200)), @@ -125,46 +135,47 @@ Setup_Video::Setup_Video(): mScrollRadiusField(new TextField), mOverlayDetail((int) config.getValue("OverlayDetail", 2)), mOverlayDetailSlider(new Slider(0, 2)), - mOverlayDetailField(new gcn::Label("")) + mOverlayDetailField(new gcn::Label("")), + mParticleDetail(3 - (int) config.getValue("particleEmitterSkip", 1)), + mParticleDetailSlider(new Slider(0, 3)), + mParticleDetailField(new gcn::Label("")) { setOpaque(false); - setDimension(gcn::Rectangle(0, 0, 250, 200)); ScrollArea *scrollArea = new ScrollArea(mModeList); - gcn::Label *alphaLabel = new gcn::Label(_("Gui opacity")); + scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mModeList->setEnabled(false); + speechLabel = new gcn::Label(_("Overhead text")); + alphaLabel = new gcn::Label(_("Gui opacity")); + scrollRadiusLabel = new gcn::Label(_("Scroll radius")); + scrollLazinessLabel = new gcn::Label(_("Scroll laziness")); + overlayDetailLabel = new gcn::Label(_("Ambient FX")); + particleDetailLabel = new gcn::Label(_("Particle Detail")); + + mModeList->setEnabled(true); #ifndef USE_OPENGL mOpenGLCheckBox->setEnabled(false); #endif - mModeList->setDimension(gcn::Rectangle(0, 0, 60, 50)); - scrollArea->setDimension(gcn::Rectangle(10, 10, 90, 50)); - mFsCheckBox->setPosition(110, 10); - mOpenGLCheckBox->setPosition(110, 30); - mCustomCursorCheckBox->setPosition(110, 50); - mVisibleNamesCheckBox->setPosition(110, 70); - mAlphaSlider->setDimension(gcn::Rectangle(10, 100, 100, 10)); - alphaLabel->setPosition(20 + mAlphaSlider->getWidth(), - mAlphaSlider->getY()); - mFpsCheckBox->setPosition(90, 120); - mFpsSlider->setDimension(gcn::Rectangle(10, 120, 75, 10)); - mFpsField->setPosition(100 + mFpsCheckBox->getWidth(), 120); - mFpsField->setWidth(30); - mModeList->setSelected(-1); mAlphaSlider->setValue(mOpacity); + mAlphaSlider->setWidth(90); mFpsField->setText(toString(mFps)); mFpsField->setEnabled(mFps > 0); + mFpsField->setWidth(30); mFpsSlider->setValue(mFps); mFpsSlider->setEnabled(mFps > 0); mFpsCheckBox->setSelected(mFps > 0); + mModeList->setActionEventId("videomode"); mCustomCursorCheckBox->setActionEventId("customcursor"); mVisibleNamesCheckBox->setActionEventId("visiblenames"); + mParticleEffectsCheckBox->setActionEventId("particleeffects"); + mNameCheckBox->setActionEventId("showownname"); mAlphaSlider->setActionEventId("guialpha"); mFpsCheckBox->setActionEventId("fpslimitcheckbox"); + mSpeechSlider->setActionEventId("speech"); mFpsSlider->setActionEventId("fpslimitslider"); mScrollRadiusSlider->setActionEventId("scrollradiusslider"); mScrollRadiusField->setActionEventId("scrollradiusfield"); @@ -172,11 +183,17 @@ Setup_Video::Setup_Video(): mScrollLazinessField->setActionEventId("scrolllazinessfield"); mOverlayDetailSlider->setActionEventId("overlaydetailslider"); mOverlayDetailField->setActionEventId("overlaydetailfield"); + mParticleDetailSlider->setActionEventId("particledetailslider"); + mParticleDetailField->setActionEventId("particledetailfield"); + mModeList->addActionListener(this); mCustomCursorCheckBox->addActionListener(this); mVisibleNamesCheckBox->addActionListener(this); + mParticleEffectsCheckBox->addActionListener(this); + mNameCheckBox->addActionListener(this); mAlphaSlider->addActionListener(this); mFpsCheckBox->addActionListener(this); + mSpeechSlider->addActionListener(this); mFpsSlider->addActionListener(this); mFpsField->addKeyListener(this); mScrollRadiusSlider->addActionListener(this); @@ -185,28 +202,32 @@ Setup_Video::Setup_Video(): mScrollLazinessField->addKeyListener(this); mOverlayDetailSlider->addActionListener(this); mOverlayDetailField->addKeyListener(this); + mParticleDetailSlider->addActionListener(this); + mParticleDetailField->addKeyListener(this); - mScrollRadiusSlider->setDimension(gcn::Rectangle(10, 140, 75, 10)); - gcn::Label *scrollRadiusLabel = new gcn::Label(_("Scroll radius")); - scrollRadiusLabel->setPosition(90, 140); - mScrollRadiusField->setPosition(mFpsField->getX(), 140); - mScrollRadiusField->setWidth(30); mScrollRadiusField->setText(toString(mOriginalScrollRadius)); mScrollRadiusSlider->setValue(mOriginalScrollRadius); - mScrollLazinessSlider->setDimension(gcn::Rectangle(10, 160, 75, 10)); - gcn::Label *scrollLazinessLabel = new gcn::Label(_("Scroll laziness")); - scrollLazinessLabel->setPosition(90, 160); - mScrollLazinessField->setPosition(mFpsField->getX(), 160); - mScrollLazinessField->setWidth(30); mScrollLazinessField->setText(toString(mOriginalScrollLaziness)); mScrollLazinessSlider->setValue(mOriginalScrollLaziness); - mOverlayDetailSlider->setDimension(gcn::Rectangle(10, 180, 75, 10)); - gcn::Label *overlayDetailLabel = new gcn::Label(_("Ambient FX")); - overlayDetailLabel->setPosition(90, 180); - mOverlayDetailField->setPosition(180, 180); - mOverlayDetailField->setWidth(30); + switch (mSpeechMode) + { + case 0: + mSpeechLabel->setCaption(_("No text")); + break; + case 1: + mSpeechLabel->setCaption(_("Text")); + break; + case 2: + mSpeechLabel->setCaption(_("Bubbles, no names")); + break; + case 3: + mSpeechLabel->setCaption(_("Bubbles with names")); + break; + } + mSpeechSlider->setValue(mSpeechMode); + switch (mOverlayDetail) { case 0: @@ -221,37 +242,66 @@ Setup_Video::Setup_Video(): } mOverlayDetailSlider->setValue(mOverlayDetail); - add(scrollArea); - add(mFsCheckBox); - add(mOpenGLCheckBox); - add(mCustomCursorCheckBox); - add(mVisibleNamesCheckBox); - add(mAlphaSlider); - add(alphaLabel); - add(mFpsCheckBox); - add(mFpsSlider); - add(mFpsField); - add(mScrollRadiusSlider); - add(scrollRadiusLabel); - add(mScrollRadiusField); - add(mScrollLazinessSlider); - add(scrollLazinessLabel); - add(mScrollLazinessField); - add(mOverlayDetailSlider); - add(overlayDetailLabel); - add(mOverlayDetailField); -} - -Setup_Video::~Setup_Video() -{ - delete mModeListModel; + switch (mParticleDetail) + { + case 0: + mParticleDetailField->setCaption(_("low")); + break; + case 1: + mParticleDetailField->setCaption(_("medium")); + break; + case 2: + mParticleDetailField->setCaption(_("high")); + break; + case 3: + mParticleDetailField->setCaption(_("max")); + break; + } + mParticleDetailSlider->setValue(mParticleDetail); + + // Do the layout + LayoutHelper h(this); + ContainerPlacer place = h.getPlacer(0, 0); + + place(0, 0, scrollArea, 1, 6).setPadding(2); + place(1, 0, mFsCheckBox, 3); + place(1, 1, mOpenGLCheckBox, 3); + place(1, 2, mCustomCursorCheckBox, 3); + place(1, 3, mVisibleNamesCheckBox, 3); + place(1, 4, mNameCheckBox, 3); + place(1, 5, mParticleEffectsCheckBox, 3); + + place(0, 6, mAlphaSlider); + place(0, 7, mFpsSlider); + place(0, 8, mScrollRadiusSlider); + place(0, 9, mScrollLazinessSlider); + place(0, 10, mSpeechSlider); + place(0, 11, mOverlayDetailSlider); + place(0, 12, mParticleDetailSlider); + + place(1, 6, alphaLabel, 2); + place(1, 7, mFpsCheckBox).setPadding(3); + place(1, 8, scrollRadiusLabel); + place(1, 9, scrollLazinessLabel); + place(1, 10, speechLabel); + place(1, 11, overlayDetailLabel); + place(1, 12, particleDetailLabel); + + place(2, 7, mFpsField).setPadding(1); + place(2, 8, mScrollRadiusField).setPadding(1); + place(2, 9, mScrollLazinessField).setPadding(1); + place(2, 10, mSpeechLabel, 2).setPadding(2); + place(2, 11, mOverlayDetailField, 2).setPadding(2); + place(2, 12, mParticleDetailField, 2).setPadding(2); + + setDimension(gcn::Rectangle(0, 0, 325, 280)); } void Setup_Video::apply() { // Full screen changes bool fullscreen = mFsCheckBox->isSelected(); - if (fullscreen != (config.getValue("screen", 0) == 1)) + if (fullscreen != (config.getValue("screen", false) == 1)) { /* The OpenGL test is only necessary on Windows, since switching * to/from full screen works fine on Linux. On Windows we'd have to @@ -260,9 +310,9 @@ void Setup_Video::apply() * See http://libsdl.org/cgi/docwiki.cgi/SDL_SetVideoMode */ -#ifdef WIN32 +#if defined(WIN32) || defined(__APPLE__) // checks for opengl usage - if (!(config.getValue("opengl", 0) == 1)) + if (!(config.getValue("opengl", false) == 1)) { #endif if (!graphics->setFullscreen(fullscreen)) @@ -271,26 +321,26 @@ void Setup_Video::apply() if (!graphics->setFullscreen(fullscreen)) { std::stringstream error; - error << "Failed to switch to " << - (fullscreen ? "windowed" : "fullscreen") << - "mode and restoration of old mode also failed!" << + error << _("Failed to switch to ") << + (fullscreen ? _("windowed") : _("fullscreen")) << + _("mode and restoration of old mode also failed!") << std::endl; logger->error(error.str()); } } -#ifdef WIN32 +#if defined(WIN32) || defined(__APPLE__) } else { new OkDialog(_("Switching to full screen"), _("Restart needed for changes to take effect.")); } #endif - config.setValue("screen", fullscreen ? 1 : 0); + config.setValue("screen", fullscreen ? true : false); } // OpenGL change if (mOpenGLCheckBox->isSelected() != mOpenGLEnabled) { - config.setValue("opengl", mOpenGLCheckBox->isSelected() ? 1 : 0); + config.setValue("opengl", mOpenGLCheckBox->isSelected() ? true : false); // OpenGL can currently only be changed by restarting, notify user. new OkDialog(_("Changing OpenGL"), @@ -301,17 +351,19 @@ void Setup_Video::apply() config.setValue("fpslimit", mFps); // We sync old and new values at apply time - mFullScreenEnabled = config.getValue("screen", 0); - mCustomCursorEnabled = config.getValue("customcursor", 1); + mFullScreenEnabled = config.getValue("screen", false); + mCustomCursorEnabled = config.getValue("customcursor", true); mVisibleNamesEnabled = config.getValue("visiblenames", 1); + mParticleEffectsEnabled = config.getValue("particleeffects", true); + mNameEnabled = config.getValue("showownname", false); + mSpeechMode = (int) config.getValue("speech", 3); mOpacity = config.getValue("guialpha", 0.8); - mOverlayDetail = (int)config.getValue("OverlayDetail", 2); - mOpenGLEnabled = config.getValue("opengl", 0); + mOverlayDetail = (int) config.getValue("OverlayDetail", 2); + mOpenGLEnabled = config.getValue("opengl", false); } -int -Setup_Video::updateSlider(gcn::Slider *slider, gcn::TextField *field, - const std::string &configName) +int Setup_Video::updateSlider(gcn::Slider *slider, gcn::TextField *field, + const std::string &configName) { int value; std::stringstream temp(field->getText()); @@ -336,37 +388,94 @@ void Setup_Video::cancel() mOpenGLCheckBox->setSelected(mOpenGLEnabled); mCustomCursorCheckBox->setSelected(mCustomCursorEnabled); mVisibleNamesCheckBox->setSelected(mVisibleNamesEnabled); + mParticleEffectsCheckBox->setSelected(mParticleEffectsEnabled); + mSpeechSlider->setValue(mSpeechMode); + mNameCheckBox->setSelected(mNameEnabled); mAlphaSlider->setValue(mOpacity); mOverlayDetailSlider->setValue(mOverlayDetail); + mParticleDetailSlider->setValue(mParticleDetail); mScrollRadiusField->setText(toString(mOriginalScrollRadius)); mScrollLazinessField->setText(toString(mOriginalScrollLaziness)); updateSlider(mScrollRadiusSlider, mScrollRadiusField, "ScrollRadius"); updateSlider(mScrollLazinessSlider, mScrollLazinessField, "ScrollLaziness"); - config.setValue("screen", mFullScreenEnabled ? 1 : 0); - config.setValue("customcursor", mCustomCursorEnabled ? 1 : 0); + config.setValue("screen", mFullScreenEnabled ? true : false); + config.setValue("customcursor", mCustomCursorEnabled ? true : false); config.setValue("visiblenames", mVisibleNamesEnabled ? 1 : 0); + config.setValue("particleeffects", mParticleEffectsEnabled ? true : false); + config.setValue("speech", mSpeechMode); + config.setValue("showownname", mNameEnabled ? true : false); config.setValue("guialpha", mOpacity); - config.setValue("opengl", mOpenGLEnabled ? 1 : 0); + config.setValue("opengl", mOpenGLEnabled ? true : false); } void Setup_Video::action(const gcn::ActionEvent &event) { - if (event.getId() == "guialpha") + if (event.getId() == "videomode") + { + const std::string mode = mModeListModel->getElementAt(mModeList->getSelected()); + const int width = atoi(mode.substr(0, mode.find("x")).c_str()); + const int height = atoi(mode.substr(mode.find("x") + 1).c_str()); + + // TODO: Find out why the drawing area doesn't resize without a restart. + new OkDialog(_("Screen resolution changed"), + _("Restart your client for the change to take effect.")); + + config.setValue("screenwidth", width); + config.setValue("screenheight", height); + } + else if (event.getId() == "guialpha") { config.setValue("guialpha", mAlphaSlider->getValue()); } else if (event.getId() == "customcursor") { config.setValue("customcursor", - mCustomCursorCheckBox->isSelected() ? 1 : 0); + mCustomCursorCheckBox->isSelected() ? true : false); } else if (event.getId() == "visiblenames") { config.setValue("visiblenames", mVisibleNamesCheckBox->isSelected() ? 1 : 0); } + else if (event.getId() == "particleeffects") + { + config.setValue("particleeffects", + mParticleEffectsCheckBox->isSelected() ? true : false); + new OkDialog(_("Particle effect settings changed"), + _("Restart your client or change maps for the change to take effect.")); + } + else if (event.getId() == "speech") + { + int val = (int) mSpeechSlider->getValue(); + switch (val) + { + case 0: + mSpeechLabel->setCaption(_("No text")); + break; + case 1: + mSpeechLabel->setCaption(_("Text")); + break; + case 2: + mSpeechLabel->setCaption(_("Bubbles, no names")); + break; + case 3: + mSpeechLabel->setCaption(_("Bubbles with names")); + break; + } + mSpeechSlider->setValue(val); + config.setValue("speech", val); + } + else if (event.getId() == "showownname") + { + // Notify the local player that settings have changed for the name + // and requires an update + if (player_node) + player_node->mUpdateName = true; + config.setValue("showownname", + mNameCheckBox->isSelected() ? true : false); + } else if (event.getId() == "fpslimitslider") { mFps = (int) mFpsSlider->getValue(); @@ -401,6 +510,27 @@ void Setup_Video::action(const gcn::ActionEvent &event) } config.setValue("OverlayDetail", val); } + else if (event.getId() == "particledetailslider") + { + int val = (int) mParticleDetailSlider->getValue(); + switch (val) + { + case 0: + mParticleDetailField->setCaption(_("low")); + break; + case 1: + mParticleDetailField->setCaption(_("medium")); + break; + case 2: + mParticleDetailField->setCaption(_("high")); + break; + case 3: + mParticleDetailField->setCaption(_("max")); + break; + } + config.setValue("particleEmitterSkip", 3 - val); + Particle::emitterSkip = 4 - val; + } else if (event.getId() == "fpslimitcheckbox") { if (mFpsCheckBox->isSelected()) @@ -418,8 +548,7 @@ void Setup_Video::action(const gcn::ActionEvent &event) } } -void -Setup_Video::keyPressed(gcn::KeyEvent &event) +void Setup_Video::keyPressed(gcn::KeyEvent &event) { std::stringstream tempFps(mFpsField->getText()); diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h index 17ca1241..44ecdfe5 100644 --- a/src/gui/setup_video.h +++ b/src/gui/setup_video.h @@ -1,40 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUI_SETUP_VIDEO_H -#define _TMW_GUI_SETUP_VIDEO_H - -#include "setuptab.h" +#ifndef GUI_SETUP_VIDEO_H +#define GUI_SETUP_VIDEO_H #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> -#include "../guichanfwd.h" +#include "setuptab.h" class Setup_Video : public SetupTab, public gcn::ActionListener, public gcn::KeyListener { public: Setup_Video(); - ~Setup_Video(); void apply(); void cancel(); @@ -42,25 +39,43 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, void action(const gcn::ActionEvent &event); /** Called when key is pressed */ - void - keyPressed(gcn::KeyEvent &event); + void keyPressed(gcn::KeyEvent &event); private: + void updateSliders(bool originalValues); + + int updateSlider(gcn::Slider *slider, gcn::TextField *field, + const std::string &configName); + bool mFullScreenEnabled; bool mOpenGLEnabled; bool mCustomCursorEnabled; bool mVisibleNamesEnabled; + bool mParticleEffectsEnabled; + bool mNameEnabled; double mOpacity; int mFps; + int mSpeechMode; class ModeListModel *mModeListModel; + gcn::Label *speechLabel; + gcn::Label *alphaLabel; + gcn::Label *scrollRadiusLabel; + gcn::Label *scrollLazinessLabel; + gcn::Label *overlayDetailLabel; + gcn::Label *particleDetailLabel; + gcn::ListBox *mModeList; gcn::CheckBox *mFsCheckBox; gcn::CheckBox *mOpenGLCheckBox; gcn::CheckBox *mCustomCursorCheckBox; gcn::CheckBox *mVisibleNamesCheckBox; + gcn::CheckBox *mParticleEffectsCheckBox; + gcn::CheckBox *mNameCheckBox; + gcn::Slider *mSpeechSlider; + gcn::Label *mSpeechLabel; gcn::Slider *mAlphaSlider; gcn::CheckBox *mFpsCheckBox; gcn::Slider *mFpsSlider; @@ -78,12 +93,9 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, gcn::Slider *mOverlayDetailSlider; gcn::Label *mOverlayDetailField; - void - updateSliders(bool originalValues); - - int - updateSlider(gcn::Slider *slider, gcn::TextField *field, - const std::string &configName); + int mParticleDetail; + gcn::Slider *mParticleDetailSlider; + gcn::Label *mParticleDetailField; }; #endif diff --git a/src/gui/setuptab.h b/src/gui/setuptab.h index 6c276c35..3e0c51e2 100644 --- a/src/gui/setuptab.h +++ b/src/gui/setuptab.h @@ -1,34 +1,34 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUI_SETUPTAB_H -#define _TMW_GUI_SETUPTAB_H +#ifndef GUI_SETUPTAB_H +#define GUI_SETUPTAB_H #include "gccontainer.h" class SetupTab : public GCContainer { public: - virtual void apply() =0; - virtual void cancel() =0; + virtual void apply() = 0; + virtual void cancel() = 0; }; #endif diff --git a/src/gui/shop.cpp b/src/gui/shop.cpp index a521c75b..7b28cef4 100644 --- a/src/gui/shop.cpp +++ b/src/gui/shop.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -43,7 +43,16 @@ void ShopItems::addItem(int id, int amount, int price) mShopItems.push_back(new ShopItem(id, amount, price)); } -ShopItem* ShopItems::at(int i) +#ifdef EATHENA_SUPPORT +void ShopItems::addItem(int inventoryIndex, int id, int amount, int price) +{ + ShopItem *item = new ShopItem(id, amount, price); + item->setInvIndex(inventoryIndex); + mShopItems.push_back(item); +} +#endif + +ShopItem* ShopItems::at(int i) const { return mShopItems.at(i); } diff --git a/src/gui/shop.h b/src/gui/shop.h index 62b60cae..aa72bf2a 100644 --- a/src/gui/shop.h +++ b/src/gui/shop.h @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -27,10 +27,10 @@ #include <guichan/listmodel.hpp> -#include "../resources/image.h" - #include "../shopitem.h" +class ShopItem; + class ShopItems : public gcn::ListModel { public: @@ -40,10 +40,17 @@ class ShopItems : public gcn::ListModel ~ShopItems(); /** - * Adds an item and its associated picture. + * Adds an item to the list. */ void addItem(int id, int amount, int price); +#ifdef EATHENA_SUPPORT + /** + * Adds an item to the list (used by eAthena sell dialog). + */ + void addItem(int inventoryIndex, int id, int amount, int price); +#endif + /** * Returns the number of items in the shop. */ @@ -57,7 +64,7 @@ class ShopItems : public gcn::ListModel /** * Returns the item number i in the shop. */ - ShopItem* at(int i); + ShopItem* at(int i) const; /** * Clear the vector. diff --git a/src/gui/shoplistbox.cpp b/src/gui/shoplistbox.cpp index bce6a48c..8aed3c77 100644 --- a/src/gui/shoplistbox.cpp +++ b/src/gui/shoplistbox.cpp @@ -1,37 +1,38 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "shoplistbox.h" - #include <guichan/font.hpp> -#include <guichan/graphics.hpp> #include <guichan/listmodel.hpp> -#include <guichan/mouseinput.hpp> -#include <guichan/imagefont.hpp> -#include <guichan/basiccontainer.hpp> +#include "color.h" +#include "shop.h" +#include "shoplistbox.h" + +#include "../configuration.h" #include "../graphics.h" const int ITEM_ICON_SIZE = 32; +float ShopListBox::mAlpha = config.getValue("guialpha", 0.8); + ShopListBox::ShopListBox(gcn::ListModel *listModel): ListBox(listModel), mPlayerMoney(0) @@ -59,6 +60,15 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) if (!mListModel) return; + if (config.getValue("guialpha", 0.8) != mAlpha) + mAlpha = config.getValue("guialpha", 0.8); + + bool valid; + const int red = (textColor->getColor('H', valid) >> 16) & 0xFF; + const int green = (textColor->getColor('H', valid) >> 8) & 0xFF; + const int blue = textColor->getColor('H', valid) & 0xFF; + const int alpha = (int)(mAlpha * 255.0f); + Graphics *graphics = static_cast<Graphics*>(gcnGraphics); graphics->setFont(getFont()); @@ -68,16 +78,16 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics) i < mListModel->getNumberOfElements(); ++i, y += mRowHeight) { - gcn::Color backgroundColor = gcn::Color(0xffffff); + gcn::Color backgroundColor = gcn::Color(255, 255, 255, alpha); if (i == mSelected) { - backgroundColor = gcn::Color(110, 160, 255); + backgroundColor = gcn::Color(red, green, blue, alpha); } else if (mShopItems && mPlayerMoney < mShopItems->at(i)->getPrice() && mPriceCheck) { - backgroundColor = gcn::Color(0x919191); + backgroundColor = gcn::Color(145, 145, 145, alpha); } graphics->setColor(backgroundColor); diff --git a/src/gui/shoplistbox.h b/src/gui/shoplistbox.h index 75f514ab..cde4786e 100644 --- a/src/gui/shoplistbox.h +++ b/src/gui/shoplistbox.h @@ -1,29 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SHOPLISTBOX_H -#define _TMW_SHOPLISTBOX_H +#ifndef SHOPLISTBOX_H +#define SHOPLISTBOX_H #include "listbox.h" -#include "shop.h" + +class ShopItems; /** * A list box, meant to be used inside a scroll area. Same as the Guichan list @@ -84,6 +85,8 @@ class ShopListBox : public ListBox unsigned int mRowHeight; /**< Row Height */ + static float mAlpha; + bool mPriceCheck; }; diff --git a/src/gui/shortcutcontainer.cpp b/src/gui/shortcutcontainer.cpp new file mode 100644 index 00000000..74609fa1 --- /dev/null +++ b/src/gui/shortcutcontainer.cpp @@ -0,0 +1,71 @@ +/* + * The Mana World + * Copyright (C) 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "shortcutcontainer.h" + +#include "../configuration.h" + +#include "../resources/image.h" + +#include "../utils/stringutils.h" + +float ShortcutContainer::mAlpha = config.getValue("guialpha", 0.8); + +ShortcutContainer::ShortcutContainer(): + mGridWidth(1), + mGridHeight(1) +{ +} + +void ShortcutContainer::widgetResized(const gcn::Event &event) +{ + mGridWidth = getWidth() / mBoxWidth; + if (mGridWidth < 1) + { + mGridWidth = 1; + } + + setHeight((mMaxItems / mGridWidth + + (mMaxItems % mGridWidth > 0 ? 1 : 0)) * mBoxHeight); + + mGridHeight = getHeight() / mBoxHeight; + if (mGridHeight < 1) + { + mGridHeight = 1; + } +} + +int ShortcutContainer::getIndexFromGrid(int pointX, int pointY) const +{ + const gcn::Rectangle tRect = gcn::Rectangle( + 0, 0, mGridWidth * mBoxWidth, mGridHeight * mBoxHeight); + if (!tRect.isPointInRect(pointX, pointY)) + { + return -1; + } + const int index = ((pointY / mBoxHeight) * mGridWidth) + + pointX / mBoxWidth; + if (index >= mMaxItems) + { + return -1; + } + return index; +} diff --git a/src/gui/shortcutcontainer.h b/src/gui/shortcutcontainer.h new file mode 100644 index 00000000..7b09fb96 --- /dev/null +++ b/src/gui/shortcutcontainer.h @@ -0,0 +1,107 @@ +/* + * The Mana World + * Copyright (C) 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SHORTCUTCONTAINER_H +#define SHORTCUTCONTAINER_H + +#include <guichan/mouselistener.hpp> +#include <guichan/widget.hpp> +#include <guichan/widgetlistener.hpp> + +class Image; + +/** + * A generic shortcut container. + * + * \ingroup GUI + */ +class ShortcutContainer : public gcn::Widget, + public gcn::WidgetListener, + public gcn::MouseListener +{ + public: + /** + * Constructor. Initializes the shortcut container. + */ + ShortcutContainer(); + + /** + * Destructor. + */ + ~ShortcutContainer(){} + + /** + * Draws the shortcuts + */ + virtual void draw(gcn::Graphics *graphics) = 0; + + /** + * Invoked when a widget changes its size. This is used to determine + * the new height of the container. + */ + virtual void widgetResized(const gcn::Event &event); + + /** + * Handles mouse when dragged. + */ + virtual void mouseDragged(gcn::MouseEvent &event) = 0; + + /** + * Handles mouse when pressed. + */ + virtual void mousePressed(gcn::MouseEvent &event) = 0; + + /** + * Handles mouse release. + */ + virtual void mouseReleased(gcn::MouseEvent &event) = 0; + + virtual int getMaxItems() + { return mMaxItems; } + + virtual int getBoxWidth() + { return mBoxWidth; } + + virtual int getBoxHeight() + { return mBoxHeight; } + + protected: + /** + * Gets the index from the grid provided the point is in an item box. + * + * @param pointX X coordinate of the point. + * @param pointY Y coordinate of the point. + * @return index on success, -1 on failure. + */ + int getIndexFromGrid(int pointX, int pointY) const; + + Image *mBackgroundImg; + + static float mAlpha; + + int mMaxItems; + int mBoxWidth; + int mBoxHeight; + int mCursorPosX, mCursorPosY; + int mGridWidth, mGridHeight; +}; + +#endif diff --git a/src/gui/shortcutwindow.cpp b/src/gui/shortcutwindow.cpp new file mode 100644 index 00000000..c704fc44 --- /dev/null +++ b/src/gui/shortcutwindow.cpp @@ -0,0 +1,83 @@ +/* + * The Mana World + * Copyright (C) 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "scrollarea.h" +#include "shortcutcontainer.h" +#include "shortcutwindow.h" + +#include "../configuration.h" + +static const int SCROLL_PADDING = 0; + +int ShortcutWindow::mInstances = 0; + +ShortcutWindow::ShortcutWindow(const char *title, ShortcutContainer *content) +{ + setWindowName(title); + // no title presented, title bar is padding so window can be moved. + gcn::Window::setTitleBarHeight(gcn::Window::getPadding()); + setShowTitle(false); + setResizable(true); + + mItems = content; + + mInstances++; + + const int border = SCROLL_PADDING * 2 + getPadding() * 2; + setMinWidth(mItems->getBoxWidth() + border); + setMinHeight(mItems->getBoxHeight() + border); + setMaxWidth(mItems->getBoxWidth() * mItems->getMaxItems() + border); + setMaxHeight(mItems->getBoxHeight() * mItems->getMaxItems() + border); + + const int width = (int) config.getValue("screenwidth", 800); + const int height = (int) config.getValue("screenheight", 600); + + setDefaultSize(width - (mInstances * mItems->getBoxWidth()) - + (mInstances * border), height - (mItems->getBoxHeight() * + mItems->getMaxItems()) - border, mItems->getBoxWidth() + + border, (mItems->getBoxHeight() * mItems->getMaxItems()) + + border); + + mScrollArea = new ScrollArea(mItems); + mScrollArea->setPosition(SCROLL_PADDING, SCROLL_PADDING); + mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mScrollArea->setOpaque(false); + + add(mScrollArea); + + loadWindowState(); +} + +ShortcutWindow::~ShortcutWindow() +{ + delete mItems; +} + +void ShortcutWindow::widgetResized(const gcn::Event &event) +{ + Window::widgetResized(event); + + const gcn::Rectangle &area = getChildrenArea(); + + mScrollArea->setSize( + area.width - SCROLL_PADDING, + area.height - SCROLL_PADDING); +} diff --git a/src/gui/shortcutwindow.h b/src/gui/shortcutwindow.h new file mode 100644 index 00000000..64592328 --- /dev/null +++ b/src/gui/shortcutwindow.h @@ -0,0 +1,65 @@ +/* + * The Mana World + * Copyright (C) 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SHORTCUTWINDOW_H +#define SHORTCUTWINDOW_H + +#include "window.h" + +class ScrollArea; +class ShortcutContainer; + +/** + * A window around the ItemShortcutContainer. + * + * \ingroup Interface + */ +class ShortcutWindow : public Window +{ + public: + /** + * Constructor. + */ + ShortcutWindow(const char *title, ShortcutContainer *content); + + /** + * Destructor. + */ + ~ShortcutWindow(); + + /** + * Called whenever the widget changes size. + */ + void widgetResized(const gcn::Event &event); + + private: + ShortcutWindow(); + ShortcutContainer *mItems; + + ScrollArea *mScrollArea; + + static int mInstances; +}; + +extern ShortcutWindow *itemShortcutWindow; +extern ShortcutWindow *emoteShortcutWindow; + +#endif diff --git a/src/gui/skill.cpp b/src/gui/skill.cpp index 6d747641..61bb9ce9 100644 --- a/src/gui/skill.cpp +++ b/src/gui/skill.cpp @@ -1,73 +1,161 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <guichan/widgets/label.hpp> -#include <guichan/widgets/container.hpp> -#include <guichan/widgets/icon.hpp> -#include "skill.h" - -#include "icon.h" #include "button.h" #include "listbox.h" #include "scrollarea.h" +#include "skill.h" +#include "table.h" #include "windowcontainer.h" -#include "progressbar.h" -#include "widgets/tabbedarea.h" +#include "widgets/layout.h" #include "../localplayer.h" +#include "../log.h" #include "../utils/dtor.h" -#include "../utils/tostring.h" #include "../utils/gettext.h" +#include "../utils/strprintf.h" +#include "../utils/xml.h" + +static const char *SKILLS_FILE = _("skills.xml"); + +struct SkillInfo +{ + std::string name; + bool modifiable; +}; + +static const SkillInfo fakeSkillInfo = { + _("Mystery Skill"), + false +}; + +std::vector<SkillInfo> skill_db; + +static void initSkillinfo(); + +class SkillGuiTableModel : public StaticTableModel +{ +public: + SkillGuiTableModel(SkillDialog *dialog) : + StaticTableModel(0, 3) + { + mEntriesNr = 0; + mDialog = dialog; + update(); + } + + virtual int getRows(void) + { + return mEntriesNr; + } + + virtual int getColumnWidth(int index) + { + if (index == 0) + return 160; + + return 35; + } + + virtual int getRowHeight() + { + return 12; + } + + virtual void update() + { + mEntriesNr = mDialog->getSkills().size(); + resize(); + + for (int i = 0; i < mEntriesNr; i++) + { + SKILL *skill = mDialog->getSkills()[i]; + SkillInfo const *info; + char tmp[128]; + + if (skill->id >= 0 + && (unsigned int) skill->id < skill_db.size()) + info = &skill_db[skill->id]; + else + info = &fakeSkillInfo; + + sprintf(tmp, "%c%s", info->modifiable? ' ' : '*', info->name.c_str()); + gcn::Label *name_label = new gcn::Label(tmp); + + sprintf(tmp, "Lv:%i", skill->lv); + gcn::Label *lv_label = new gcn::Label(tmp); + + sprintf(tmp, "Sp:%i", skill->sp); + gcn::Label *sp_label = new gcn::Label(tmp); + + set(i, 0, name_label); + set(i, 1, lv_label); + set(i, 2, sp_label); + } + } + +private: + SkillDialog *mDialog; + int mEntriesNr; +}; + SkillDialog::SkillDialog(): Window(_("Skills")) { + initSkillinfo(); + mTableModel = new SkillGuiTableModel(this); + mTable = new GuiTable(mTableModel); + mTable->setOpaque(false); + mTable->setLinewiseSelection(true); + mTable->setWrappingEnabled(true); + mTable->setActionEventId("skill"); + mTable->addActionListener(this); + setWindowName("Skills"); setCloseButton(true); - setDefaultSize(windowContainer->getWidth() - 280, 30, 275, 425); + setDefaultSize(windowContainer->getWidth() - 260, 25, 255, 260); - TabbedArea *panel = new TabbedArea(); - panel->setDimension(gcn::Rectangle(5, 5, 270, 420)); + setMinHeight(50 + mTableModel->getHeight()); + setMinWidth(200); - Skill_Tab* tab; + ScrollArea *skillScrollArea = new ScrollArea(mTable); + mPointsLabel = new gcn::Label(strprintf(_("Skill points: %d"), 0)); + mIncButton = new Button(_("Up"), _("inc"), this); + mUseButton = new Button(_("Use"), _("use"), this); + mUseButton->setEnabled(false); - // Add each type of skill tab to the panel - tab = new Skill_Tab("Weapon"); - panel->addTab(_("Weapons"), tab); - mTabs.push_back(tab); + skillScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - tab = new Skill_Tab("Magic"); - panel->addTab(_("Magic"), tab); - mTabs.push_back(tab); + place(0, 0, skillScrollArea, 5).setPadding(3); + place(0, 1, mPointsLabel, 2); + place(3, 2, mIncButton); + place(4, 2, mUseButton); - tab = new Skill_Tab("Craft"); - panel->addTab(_("Crafts"), tab); - mTabs.push_back(tab); - - add(panel); - - update(); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); setLocationRelativeTo(getParent()); loadWindowState(); @@ -75,189 +163,135 @@ SkillDialog::SkillDialog(): SkillDialog::~SkillDialog() { - delete_all(mTabs); + delete mTable; } void SkillDialog::action(const gcn::ActionEvent &event) { - if (event.getId() == "skill") + if (event.getId() == "inc") { + // Increment skill + int selectedSkill = mTable->getSelectedRow(); + if (selectedSkill >= 0) + player_node->raiseSkill(mSkillList[selectedSkill]->id); } - else if (event.getId() == "close") + else if (event.getId() == "skill" && mTable->getSelectedRow() > -1) { - setVisible(false); - } -} - -void SkillDialog::draw(gcn::Graphics *g) -{ - update(); + SKILL *skill = mSkillList[mTable->getSelectedRow()]; + SkillInfo const *info; - Window::draw(g); -} + if (skill->id >= 0 && (unsigned int) skill->id < skill_db.size()) + info = &skill_db[skill->id]; + else + info = &fakeSkillInfo; -void SkillDialog::update() -{ - for(std::list<Skill_Tab*>::const_iterator i = mTabs.begin(); - i != mTabs.end(); ++i) - { - (*i)->update(); + mIncButton->setEnabled(player_node->mSkillPoint > 0 && + info->modifiable); } + else if (event.getId() == "close") + setVisible(false); } -Skill_Tab::Skill_Tab(const std::string &type): type(type) +void SkillDialog::update() { - setOpaque(false); - setDimension(gcn::Rectangle(0, 0, 270, 420)); - int skillNum = getSkillNum(); - - mSkillIcons.resize(skillNum); - mSkillNameLabels.resize(skillNum); - mSkillLevelLabels.resize(skillNum); - mSkillExpLabels.resize(skillNum); - mSkillProgress.resize(skillNum); - - // Set the initial positions of the skill information - for (int a=0; a < skillNum; a++) - { - mSkillIcons.at(a) = getIcon(a); - mSkillIcons.at(a)->setPosition(1, a*32); - add(mSkillIcons.at(a)); + mPointsLabel->setCaption(strprintf(_("Skill points: %d"), + player_node->mSkillPoint)); - mSkillNameLabels.at(a) = new gcn::Label(""); - mSkillNameLabels.at(a)->setPosition(35, a*32 ); - add(mSkillNameLabels.at(a)); + int selectedSkill = mTable->getSelectedRow(); - mSkillProgress.at(a) = new ProgressBar(0.0f, 200, 20, 150, 150, 150); - mSkillProgress.at(a)->setPosition(35, a*32 + 13); - add(mSkillProgress.at(a)); + if (selectedSkill >= 0) + { + int skillId = mSkillList[selectedSkill]->id; + bool modifiable; - mSkillExpLabels.at(a) = new gcn::Label(""); - mSkillExpLabels.at(a)->setPosition(45, a*32 + 16); - add(mSkillExpLabels.at(a)); + if (skillId >= 0 && (unsigned int) skillId < skill_db.size()) + modifiable = skill_db[skillId].modifiable; + else + modifiable = false; - mSkillLevelLabels.at(a) = new gcn::Label(""); - mSkillLevelLabels.at(a)->setPosition(165, a*32); - add(mSkillLevelLabels.at(a)); + mIncButton->setEnabled(modifiable + && player_node->mSkillPoint > 0); } + else + mIncButton->setEnabled(false); - update(); - + mTableModel->update(); + setMinHeight(50 + mTableModel->getHeight()); } -int Skill_Tab::getSkillNum() +int SkillDialog::getNumberOfElements() { - int skillNum = 0; + return mSkillList.size(); +} - if (type == "Weapon") - { - skillNum = CHAR_SKILL_WEAPON_NB; - return skillNum; - } - else if (type == "Magic") - { - skillNum = CHAR_SKILL_MAGIC_NB; - return skillNum; - } - else if (type == "Craft") +bool SkillDialog::hasSkill(int id) +{ + for (unsigned int i = 0; i < mSkillList.size(); i++) { - skillNum = CHAR_SKILL_CRAFT_NB; - return skillNum; + if (mSkillList[i]->id == id) + return true; } - else return skillNum; + return false; } -int Skill_Tab::getSkillBegin() +void SkillDialog::addSkill(int id, int lvl, int mp) { - int skillBegin = 0; + SKILL *tmp = new SKILL; + tmp->id = id; + tmp->lv = lvl; + tmp->sp = mp; + mSkillList.push_back(tmp); +} - if (type == "Weapon") - { - skillBegin = CHAR_SKILL_WEAPON_BEGIN - CHAR_SKILL_BEGIN; - return skillBegin; - } - else if (type == "Magic") - { - skillBegin = CHAR_SKILL_MAGIC_BEGIN - CHAR_SKILL_BEGIN; - return skillBegin; - } - else if (type == "Craft") +void SkillDialog::setSkill(int id, int lvl, int mp) +{ + for (unsigned int i = 0; i < mSkillList.size(); i++) { - skillBegin = CHAR_SKILL_CRAFT_BEGIN - CHAR_SKILL_BEGIN; - return skillBegin; + if (mSkillList[i]->id == id) + { + mSkillList[i]->lv = lvl; + mSkillList[i]->sp = mp; + } } - else return skillBegin; } -Icon* Skill_Tab::getIcon(int index) +void SkillDialog::cleanList() { - int skillBegin = getSkillBegin(); - std::string icon = LocalPlayer::getSkillInfo(index + skillBegin).icon; - return new Icon(icon); + delete_all(mSkillList); + mSkillList.clear(); } -void Skill_Tab::updateSkill(int index) +static void initSkillinfo() { - int skillBegin = getSkillBegin(); + SkillInfo emptySkillInfo = { "", false }; - int baseLevel = player_node->getAttributeBase(index + - skillBegin + - CHAR_SKILL_BEGIN); + XML::Document doc(SKILLS_FILE); + xmlNodePtr root = doc.rootNode(); - int effLevel = player_node->getAttributeEffective(index + - skillBegin + - CHAR_SKILL_BEGIN); - if(baseLevel <= 0) + if (!root || !xmlStrEqual(root->name, BAD_CAST "skills")) { - mSkillProgress.at(index)->setVisible(false); - mSkillExpLabels.at(index)->setVisible(false); - mSkillLevelLabels.at(index)->setVisible(false); - mSkillNameLabels.at(index)->setVisible(false); - mSkillIcons.at(index)->setVisible(false); + logger->log("Error loading skills file: %s", SKILLS_FILE); + skill_db.resize(2, emptySkillInfo); + skill_db[1].name = "Basic"; + skill_db[1].modifiable = true; + return; } - else + + for_each_xml_child_node(node, root) { - mSkillProgress.at(index)->setVisible(true); - mSkillExpLabels.at(index)->setVisible(true); - mSkillLevelLabels.at(index)->setVisible(true); - mSkillNameLabels.at(index)->setVisible(true); - mSkillIcons.at(index)->setVisible(true); - std::string skillLevel("Lvl: " + toString(baseLevel)); - if (effLevel < baseLevel) - { - skillLevel.append(" - " + toString(baseLevel - effLevel)); - } - else if (effLevel > baseLevel) + if (xmlStrEqual(node->name, BAD_CAST "skill")) { - skillLevel.append(" + " + toString(effLevel - baseLevel)); + int index = atoi(XML::getProperty(node, "id", "-1").c_str()); + std::string name = XML::getProperty(node, "name", ""); + bool modifiable = !atoi(XML::getProperty(node, "fixed", "0").c_str()); + + if (index >= 0) + { + skill_db.resize(index + 1, emptySkillInfo); + skill_db[index].name = name; + skill_db[index].modifiable = modifiable; + } } - mSkillLevelLabels.at(index)->setCaption(skillLevel); - - std::pair<int, int> exp = player_node->getExperience(index + skillBegin); - std::string sExp (toString(exp.first) + " / " + toString(exp.second)); - - - mSkillNameLabels.at(index)->setCaption(LocalPlayer::getSkillInfo(index + skillBegin).name); - mSkillNameLabels.at(index)->adjustSize(); - mSkillLevelLabels.at(index)->adjustSize(); - mSkillExpLabels.at(index)->setCaption(sExp); - mSkillExpLabels.at(index)->adjustSize(); - mSkillExpLabels.at(index)->setAlignment(gcn::Graphics::RIGHT); - - // More intense red as exp grows - int color = 150 - (int)(150 * ((float) exp.first / exp.second)); - mSkillProgress.at(index)->setColor(244, color, color); - mSkillProgress.at(index)->setProgress((float) exp.first / exp.second); } } -void Skill_Tab::update() -{ - int skillNum = getSkillNum(); - - // Update the skill information for reach skill - for (int a = 0; a < skillNum; a++) - { - updateSkill(a); - } -} diff --git a/src/gui/skill.h b/src/gui/skill.h index 3d010daa..0600d106 100644 --- a/src/gui/skill.h +++ b/src/gui/skill.h @@ -1,95 +1,40 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SKILL_H -#define _TMW_SKILL_H +#ifndef SKILL_H +#define SKILL_H #include <vector> -#include <list> -#include <guichan/listmodel.hpp> #include <guichan/actionlistener.hpp> #include "window.h" -#include "gccontainer.h" -#include "../guichanfwd.h" - -class ProgressBar; -class Icon; - -class Skill_Tab : public GCContainer, public gcn::ActionListener -{ - public: - /** - * The type of this skill tab - */ - const std::string type; - - /** - * Constructor - */ - Skill_Tab(const std::string &type); - - /** - * Update this tab - */ - void update(); - - /** - * Called when receiving actions from widget. - */ - void action(const gcn::ActionEvent &event) {} - - private: - /** - * Update the information of a skill at - * the given index - */ - void updateSkill(int index); - - /** - * Gets the number of skills in this particular - * type of tab. - */ - int getSkillNum(); - - /** - * Get the first enumeration of this skill tab's - * skill type. - */ - int getSkillBegin(); - - /** - * Get the icon associated with the given index - */ - Icon* getIcon(int index); - - std::vector<Icon *> mSkillIcons; - std::vector<gcn::Label *> mSkillNameLabels; - std::vector<gcn::Label *> mSkillLevelLabels; - std::vector<gcn::Label *> mSkillExpLabels; - std::vector<ProgressBar *> mSkillProgress; +struct SKILL { + short id; /**< Index into "skill_db" array */ + short lv, sp; }; +class GuiTable; +class SkillGuiTableModel; /** * The skill dialog. @@ -109,31 +54,30 @@ class SkillDialog : public Window, public gcn::ActionListener */ ~SkillDialog(); - /** - * Called when receiving actions from widget. - */ void action(const gcn::ActionEvent &event); - /** - * Update the tabs in this dialog - */ void update(); - /** - * Draw this window. - */ - void draw(gcn::Graphics *g); - - private: + int getNumberOfElements(); + bool hasSkill(int id); + void addSkill(int id, int lv, int sp); + void setSkill(int id, int lv, int sp); + void cleanList(); - std::list<Skill_Tab*> mTabs; + const std::vector<SKILL*>& getSkills() const { return mSkillList; } + private: + GuiTable *mTable; + ScrollArea *skillScrollArea; + SkillGuiTableModel *mTableModel; + gcn::Label *mPointsLabel; + gcn::Button *mIncButton; + gcn::Button *mUseButton; + + std::vector<SKILL*> mSkillList; }; - - - extern SkillDialog *skillDialog; #endif diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp new file mode 100644 index 00000000..22d1db60 --- /dev/null +++ b/src/gui/skilldialog.cpp @@ -0,0 +1,263 @@ +/* + * 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/widgets/label.hpp> +#include <guichan/widgets/container.hpp> +#include <guichan/widgets/icon.hpp> + +#include "skilldialog.h" + +#include "icon.h" +#include "button.h" +#include "listbox.h" +#include "scrollarea.h" +#include "windowcontainer.h" +#include "progressbar.h" + +#include "widgets/tabbedarea.h" + +#include "../localplayer.h" + +#include "../utils/dtor.h" +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + +SkillDialog::SkillDialog(): + Window(_("Skills")) +{ + setWindowName("Skills"); + setCloseButton(true); + setDefaultSize(windowContainer->getWidth() - 280, 30, 275, 425); + + TabbedArea *panel = new TabbedArea(); + panel->setDimension(gcn::Rectangle(5, 5, 270, 420)); + + Skill_Tab* tab; + + // Add each type of skill tab to the panel + tab = new Skill_Tab("Weapon"); + panel->addTab(_("Weapons"), tab); + mTabs.push_back(tab); + + tab = new Skill_Tab("Magic"); + panel->addTab(_("Magic"), tab); + mTabs.push_back(tab); + + tab = new Skill_Tab("Craft"); + panel->addTab(_("Crafts"), tab); + mTabs.push_back(tab); + + add(panel); + + update(); + + setLocationRelativeTo(getParent()); + loadWindowState(); +} + +SkillDialog::~SkillDialog() +{ + delete_all(mTabs); +} + +void SkillDialog::action(const gcn::ActionEvent &event) +{ + if (event.getId() == "skill") + { + } + else if (event.getId() == "close") + { + setVisible(false); + } +} + +void SkillDialog::draw(gcn::Graphics *g) +{ + update(); + + Window::draw(g); +} + +void SkillDialog::update() +{ + for(std::list<Skill_Tab*>::const_iterator i = mTabs.begin(); + i != mTabs.end(); ++i) + { + (*i)->update(); + } +} + +Skill_Tab::Skill_Tab(const std::string &type): type(type) +{ + setOpaque(false); + setDimension(gcn::Rectangle(0, 0, 270, 420)); + int skillNum = getSkillNum(); + + mSkillIcons.resize(skillNum); + mSkillNameLabels.resize(skillNum); + mSkillLevelLabels.resize(skillNum); + mSkillExpLabels.resize(skillNum); + mSkillProgress.resize(skillNum); + + // Set the initial positions of the skill information + for (int a=0; a < skillNum; a++) + { + mSkillIcons.at(a) = getIcon(a); + mSkillIcons.at(a)->setPosition(1, a*32); + add(mSkillIcons.at(a)); + + mSkillNameLabels.at(a) = new gcn::Label(""); + mSkillNameLabels.at(a)->setPosition(35, a*32 ); + add(mSkillNameLabels.at(a)); + + mSkillProgress.at(a) = new ProgressBar(0.0f, 200, 20, 150, 150, 150); + mSkillProgress.at(a)->setPosition(35, a*32 + 13); + add(mSkillProgress.at(a)); + + mSkillExpLabels.at(a) = new gcn::Label(""); + mSkillExpLabels.at(a)->setPosition(45, a*32 + 16); + add(mSkillExpLabels.at(a)); + + mSkillLevelLabels.at(a) = new gcn::Label(""); + mSkillLevelLabels.at(a)->setPosition(165, a*32); + add(mSkillLevelLabels.at(a)); + } + + update(); + +} + +int Skill_Tab::getSkillNum() +{ + int skillNum = 0; + + if (type == "Weapon") + { + skillNum = CHAR_SKILL_WEAPON_NB; + return skillNum; + } + else if (type == "Magic") + { + skillNum = CHAR_SKILL_MAGIC_NB; + return skillNum; + } + else if (type == "Craft") + { + skillNum = CHAR_SKILL_CRAFT_NB; + return skillNum; + } + else return skillNum; +} + +int Skill_Tab::getSkillBegin() +{ + int skillBegin = 0; + + if (type == "Weapon") + { + skillBegin = CHAR_SKILL_WEAPON_BEGIN - CHAR_SKILL_BEGIN; + return skillBegin; + } + else if (type == "Magic") + { + skillBegin = CHAR_SKILL_MAGIC_BEGIN - CHAR_SKILL_BEGIN; + return skillBegin; + } + else if (type == "Craft") + { + skillBegin = CHAR_SKILL_CRAFT_BEGIN - CHAR_SKILL_BEGIN; + return skillBegin; + } + else return skillBegin; +} + +Icon* Skill_Tab::getIcon(int index) +{ + int skillBegin = getSkillBegin(); + std::string icon = LocalPlayer::getSkillInfo(index + skillBegin).icon; + return new Icon(icon); +} + +void Skill_Tab::updateSkill(int index) +{ + int skillBegin = getSkillBegin(); + + int baseLevel = player_node->getAttributeBase(index + + skillBegin + + CHAR_SKILL_BEGIN); + + int effLevel = player_node->getAttributeEffective(index + + skillBegin + + CHAR_SKILL_BEGIN); + if(baseLevel <= 0) + { + mSkillProgress.at(index)->setVisible(false); + mSkillExpLabels.at(index)->setVisible(false); + mSkillLevelLabels.at(index)->setVisible(false); + mSkillNameLabels.at(index)->setVisible(false); + mSkillIcons.at(index)->setVisible(false); + } + else + { + mSkillProgress.at(index)->setVisible(true); + mSkillExpLabels.at(index)->setVisible(true); + mSkillLevelLabels.at(index)->setVisible(true); + mSkillNameLabels.at(index)->setVisible(true); + mSkillIcons.at(index)->setVisible(true); + std::string skillLevel("Lvl: " + toString(baseLevel)); + if (effLevel < baseLevel) + { + skillLevel.append(" - " + toString(baseLevel - effLevel)); + } + else if (effLevel > baseLevel) + { + skillLevel.append(" + " + toString(effLevel - baseLevel)); + } + mSkillLevelLabels.at(index)->setCaption(skillLevel); + + std::pair<int, int> exp = player_node->getExperience(index + skillBegin); + std::string sExp (toString(exp.first) + " / " + toString(exp.second)); + + + mSkillNameLabels.at(index)->setCaption(LocalPlayer::getSkillInfo(index + skillBegin).name); + mSkillNameLabels.at(index)->adjustSize(); + mSkillLevelLabels.at(index)->adjustSize(); + mSkillExpLabels.at(index)->setCaption(sExp); + mSkillExpLabels.at(index)->adjustSize(); + mSkillExpLabels.at(index)->setAlignment(gcn::Graphics::RIGHT); + + // More intense red as exp grows + int color = 150 - (int)(150 * ((float) exp.first / exp.second)); + mSkillProgress.at(index)->setColor(244, color, color); + mSkillProgress.at(index)->setProgress((float) exp.first / exp.second); + } +} + +void Skill_Tab::update() +{ + int skillNum = getSkillNum(); + + // Update the skill information for reach skill + for (int a = 0; a < skillNum; a++) + { + updateSkill(a); + } +} diff --git a/src/gui/skilldialog.h b/src/gui/skilldialog.h new file mode 100644 index 00000000..3d010daa --- /dev/null +++ b/src/gui/skilldialog.h @@ -0,0 +1,139 @@ +/* + * 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_SKILL_H +#define _TMW_SKILL_H + +#include <vector> +#include <list> + +#include <guichan/listmodel.hpp> +#include <guichan/actionlistener.hpp> + +#include "window.h" +#include "gccontainer.h" + +#include "../guichanfwd.h" + +class ProgressBar; +class Icon; + +class Skill_Tab : public GCContainer, public gcn::ActionListener +{ + public: + /** + * The type of this skill tab + */ + const std::string type; + + /** + * Constructor + */ + Skill_Tab(const std::string &type); + + /** + * Update this tab + */ + void update(); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event) {} + + private: + /** + * Update the information of a skill at + * the given index + */ + void updateSkill(int index); + + /** + * Gets the number of skills in this particular + * type of tab. + */ + int getSkillNum(); + + /** + * Get the first enumeration of this skill tab's + * skill type. + */ + int getSkillBegin(); + + /** + * Get the icon associated with the given index + */ + Icon* getIcon(int index); + + std::vector<Icon *> mSkillIcons; + std::vector<gcn::Label *> mSkillNameLabels; + std::vector<gcn::Label *> mSkillLevelLabels; + std::vector<gcn::Label *> mSkillExpLabels; + std::vector<ProgressBar *> mSkillProgress; +}; + + +/** + * The skill dialog. + * + * \ingroup Interface + */ +class SkillDialog : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + SkillDialog(); + + /** + * Destructor. + */ + ~SkillDialog(); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event); + + /** + * Update the tabs in this dialog + */ + void update(); + + /** + * Draw this window. + */ + void draw(gcn::Graphics *g); + + private: + + + std::list<Skill_Tab*> mTabs; + +}; + + + + +extern SkillDialog *skillDialog; + +#endif diff --git a/src/gui/slider.cpp b/src/gui/slider.cpp index afeecf17..9bfa840f 100644 --- a/src/gui/slider.cpp +++ b/src/gui/slider.cpp @@ -1,26 +1,27 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "slider.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -28,6 +29,7 @@ Image *Slider::hStart, *Slider::hMid, *Slider::hEnd, *Slider::hGrip; Image *Slider::vStart, *Slider::vMid, *Slider::vEnd, *Slider::vGrip; +float Slider::mAlpha = config.getValue("guialpha", 0.8); int Slider::mInstances = 0; Slider::Slider(double scaleEnd): @@ -107,6 +109,20 @@ void Slider::draw(gcn::Graphics *graphics) int x = 0; int y = (h - hStart->getHeight()) / 2; + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + hStart->setAlpha(mAlpha); + hMid->setAlpha(mAlpha); + hEnd->setAlpha(mAlpha); + hGrip->setAlpha(mAlpha); + + vStart->setAlpha(mAlpha); + vMid->setAlpha(mAlpha); + vEnd->setAlpha(mAlpha); + vGrip->setAlpha(mAlpha); + } + static_cast<Graphics*>(graphics)->drawImage(hStart, x, y); w -= hStart->getWidth() + hEnd->getWidth(); diff --git a/src/gui/slider.h b/src/gui/slider.h index 3b796425..56ea334a 100644 --- a/src/gui/slider.h +++ b/src/gui/slider.h @@ -1,32 +1,31 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SLIDER_H -#define _TMW_SLIDER_H +#ifndef SLIDER_H +#define SLIDER_H #include <guichan/widgets/slider.hpp> class Image; - /** * Slider widget. Same as the Guichan slider but with custom look. * @@ -67,6 +66,7 @@ class Slider : public gcn::Slider { static Image *hStart, *hMid, *hEnd, *hGrip; static Image *vStart, *vMid, *vEnd, *vGrip; + static float mAlpha; static int mInstances; }; diff --git a/src/gui/speechbubble.cpp b/src/gui/speechbubble.cpp index 843a973d..165d216f 100644 --- a/src/gui/speechbubble.cpp +++ b/src/gui/speechbubble.cpp @@ -1,68 +1,94 @@ /* - * The Mana World + * Speech bubbles * Copyright (C) 2008 The Legend of Mazzeroth Development Team * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <guichan/font.hpp> + +#include <guichan/widgets/label.hpp> + +#include "gui.h" +#include "scrollarea.h" #include "speechbubble.h" +#include "textbox.h" -#include "../resources/image.h" -#include "../resources/resourcemanager.h" +#include "../utils/gettext.h" -SpeechBubble::SpeechBubble() +SpeechBubble::SpeechBubble(): + Window(_("Speech"), false, NULL, "graphics/gui/speechbubble.xml") { - mSpeechBox = new TextBox(); + setContentSize(140, 46); + setShowTitle(false); + setTitleBarHeight(0); + + mCaption = new gcn::Label(""); + mCaption->setFont(boldFont); + mCaption->setPosition(5, 3); + + mSpeechBox = new TextBox; mSpeechBox->setEditable(false); mSpeechBox->setOpaque(false); mSpeechArea = new ScrollArea(mSpeechBox); - // Height == Top Graphic (14px) + 1 Row of Text (15px) + Bottom Graphic (17px) - setContentSize(135, 46); - setTitleBarHeight(0); - loadSkin("graphics/gui/speechbubble.xml"); - mSpeechArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mSpeechArea->setVerticalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - mSpeechArea->setDimension(gcn::Rectangle(4, 15, 130, 28)); + mSpeechArea->setDimension(gcn::Rectangle(4, boldFont->getHeight() + 3, + 130, 28)); mSpeechArea->setOpaque(false); + add(mCaption); add(mSpeechArea); setLocationRelativeTo(getParent()); +} - // LEEOR / TODO: This causes an exception error. - //moveToBottom(getParent()); - - mSpeechBox->setTextWrapped( "" ); +void SpeechBubble::setCaption(const std::string &name, const gcn::Color &color) +{ + mCaption->setCaption(name); + mCaption->adjustSize(); + mCaption->setForegroundColor(color); } -void SpeechBubble::setText(const std::string mText) +void SpeechBubble::setText(std::string mText, bool showName) { - mSpeechBox->setTextWrapped( mText ); + int width = mCaption->getWidth(); + mSpeechBox->setTextWrapped(mText, 130 > width ? 130 : width); + + const int fontHeight = getFont()->getHeight(); + const int numRows = showName ? mSpeechBox->getNumberOfRows() + 1 : + mSpeechBox->getNumberOfRows(); + int yPos = showName ? fontHeight + 3 : 3; + int height = (numRows * fontHeight); + + if (width < mSpeechBox->getMinWidth()) + width = mSpeechBox->getMinWidth(); - int numRows = mSpeechBox->getNumberOfRows(); + if (numRows == 1) + { + yPos = (fontHeight / 4) + 3; + height = ((3 * fontHeight) / 2) + 1; + } - // 31 == speechbubble Top + Bottom graphic pixel heights - // 15 == height of each line of text (based on font heights) - setContentSize(135, 31 + (numRows * 15) ); - mSpeechArea->setDimension(gcn::Rectangle(4, 15, 130, (31 + (numRows * 14)) - 18 )); + setContentSize(width + fontHeight, height + 6); + mSpeechArea->setDimension(gcn::Rectangle(4, yPos, width + 5, height)); } unsigned int SpeechBubble::getNumRows() diff --git a/src/gui/speechbubble.h b/src/gui/speechbubble.h index 9fe61943..5d582b1d 100644 --- a/src/gui/speechbubble.h +++ b/src/gui/speechbubble.h @@ -1,44 +1,48 @@ /* - * The Mana World + * Speech bubbles * Copyright (C) 2008 The Legend of Mazzeroth Development Team * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SPEECHBUBBLE_H__ -#define _TMW_SPEECHBUBBLE_H__ +#ifndef SPEECHBUBBLE_H +#define SPEECHBUBBLE_H -#include "textbox.h" -#include "scrollarea.h" #include "window.h" +class ScrollArea; +class TextBox; + class SpeechBubble : public Window { public: SpeechBubble(); - void setText(const std::string mText); + void setCaption(const std::string &name, + const gcn::Color &color = 0x000000); + void setText(std::string mText, bool showName = true); void setLocation(int x, int y); unsigned int getNumRows(); private: + gcn::Label *mCaption; TextBox *mSpeechBox; ScrollArea *mSpeechArea; }; -#endif // _TMW_SPEECHBUBBLE_H__ +#endif diff --git a/src/gui/status.cpp b/src/gui/status.cpp index 283a771b..3c48d045 100644 --- a/src/gui/status.cpp +++ b/src/gui/status.cpp @@ -1,226 +1,204 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "status.h" - #include <guichan/widgets/label.hpp> #include "button.h" #include "progressbar.h" +#include "status.h" #include "windowcontainer.h" +#include "widgets/layout.h" + #include "../localplayer.h" +#include "../units.h" +#include "../utils/gettext.h" #include "../utils/strprintf.h" -#include "../utils/tostring.h" +#include "../utils/stringutils.h" StatusWindow::StatusWindow(LocalPlayer *player): Window(player->getName()), - mPlayer(player) + mPlayer(player), + mCurrency(0) { setWindowName("Status"); - setResizable(true); setCloseButton(true); setDefaultSize((windowContainer->getWidth() - 365) / 2, - (windowContainer->getHeight() - 255) / 2, 365, 275); - loadWindowState(); + (windowContainer->getHeight() - 255) / 2, 400, 345); // ---------------------- // Status Part // ---------------------- - mLvlLabel = new gcn::Label("Level:"); - mMoneyLabel = new gcn::Label("Money:"); + mLvlLabel = new gcn::Label(strprintf(_("Level: %d"), 0)); + mJobLvlLabel = new gcn::Label(strprintf(_("Job: %d"), 0)); + mGpLabel = new gcn::Label(strprintf(_("Money: %s"), + Units::formatCurrency(mCurrency).c_str())); - mHpLabel = new gcn::Label("HP:"); + mHpLabel = new gcn::Label(_("HP:")); mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34); - mHpValueLabel = new gcn::Label(""); - - int y = 3; - int x = 5; - - mLvlLabel->setPosition(x, y); - x += mLvlLabel->getWidth() + 40; - mMoneyLabel->setPosition(x, y); - y += mLvlLabel->getHeight() + 5; // Next Row - x = 5; + mXpLabel = new gcn::Label(_("Exp:")); + mXpBar = new ProgressBar(1.0f, 80, 15, 143, 192, 211); - mHpLabel->setPosition(x, y); - x += mHpLabel->getWidth() + 5; - mHpBar->setPosition(x, y); - x += mHpBar->getWidth() + 5; - mHpValueLabel->setPosition(x, y); + mMpLabel = new gcn::Label(_("MP:")); + mMpBar = new ProgressBar(1.0f, 80, 15, 26, 102, 230); - y += mHpLabel->getHeight() + 5; // Next Row - x = 5; - - add(mLvlLabel); - add(mMoneyLabel); - add(mHpLabel); - add(mHpValueLabel); - add(mHpBar); + mJobLabel = new gcn::Label(_("Job:")); + mJobBar = new ProgressBar(1.0f, 80, 15, 220, 135, 203); // ---------------------- // Stats Part // ---------------------- // Static Labels - gcn::Label *mStatsTitleLabel = new gcn::Label("Stats"); - gcn::Label *mStatsTotalLabel = new gcn::Label("Total"); + gcn::Label *mStatsTitleLabel = new gcn::Label(_("Stats")); + gcn::Label *mStatsTotalLabel = new gcn::Label(_("Total")); + gcn::Label *mStatsCostLabel = new gcn::Label(_("Cost")); + mStatsTotalLabel->setAlignment(gcn::Graphics::CENTER); // Derived Stats -/* - mStatsAttackLabel = new gcn::Label("Attack:"); - mStatsDefenseLabel= new gcn::Label("Defense:"); - mStatsMagicAttackLabel = new gcn::Label("M.Attack:"); - mStatsMagicDefenseLabel = new gcn::Label("M.Defense:"); - mStatsAccuracyLabel = new gcn::Label("% Accuracy:"); - mStatsEvadeLabel = new gcn::Label("% Evade:"); - mStatsReflexLabel = new gcn::Label("% Reflex:"); - - mStatsAttackPoints = new gcn::Label(""); - mStatsDefensePoints = new gcn::Label(""); - mStatsMagicAttackPoints = new gcn::Label(""); - mStatsMagicDefensePoints = new gcn::Label(""); - mStatsAccuracyPoints = new gcn::Label("% Accuracy:"); - mStatsEvadePoints = new gcn::Label("% Evade:"); - mStatsReflexPoints = new gcn::Label("% Reflex:"); -*/ + mStatsAttackLabel = new gcn::Label(_("Attack:")); + mStatsDefenseLabel= new gcn::Label(_("Defense:")); + mStatsMagicAttackLabel = new gcn::Label(_("M.Attack:")); + mStatsMagicDefenseLabel = new gcn::Label(_("M.Defense:")); + // Gettext flag for next line: xgettext:no-c-format + mStatsAccuracyLabel = new gcn::Label(_("% Accuracy:")); + // Gettext flag for next line: xgettext:no-c-format + mStatsEvadeLabel = new gcn::Label(_("% Evade:")); + // Gettext flag for next line: xgettext:no-c-format + mStatsReflexLabel = new gcn::Label(_("% Reflex:")); + + mStatsAttackPoints = new gcn::Label; + mStatsDefensePoints = new gcn::Label; + mStatsMagicAttackPoints = new gcn::Label; + mStatsMagicDefensePoints = new gcn::Label; + mStatsAccuracyPoints = new gcn::Label; + mStatsEvadePoints = new gcn::Label; + mStatsReflexPoints = new gcn::Label; + // New labels - for (int i = 0; i < 6; i++) { - mStatsLabel[i] = new gcn::Label(); - mStatsDisplayLabel[i] = new gcn::Label(); + for (int i = 0; i < 6; i++) + { + mStatsLabel[i] = new gcn::Label("0"); + mStatsLabel[i]->setAlignment(gcn::Graphics::CENTER); + mStatsDisplayLabel[i] = new gcn::Label; + mPointsLabel[i] = new gcn::Label("0"); + mPointsLabel[i]->setAlignment(gcn::Graphics::CENTER); } - mCharacterPointsLabel = new gcn::Label(); - mCorrectionPointsLabel = new gcn::Label(); + mRemainingStatsPointsLabel = new gcn::Label; // Set button events Id - mStatsPlus[0] = new Button("+", "STR+", this); - mStatsPlus[1] = new Button("+", "AGI+", this); - mStatsPlus[2] = new Button("+", "DEX+", this); - mStatsPlus[3] = new Button("+", "VIT+", this); - mStatsPlus[4] = new Button("+", "INT+", this); - mStatsPlus[5] = new Button("+", "WIL+", this); - - mStatsMinus[0] = new Button("-", "STR-", this); - mStatsMinus[1] = new Button("-", "AGI-", this); - mStatsMinus[2] = new Button("-", "DEX-", this); - mStatsMinus[3] = new Button("-", "VIT-", this); - mStatsMinus[4] = new Button("-", "INT-", this); - mStatsMinus[5] = new Button("-", "WIL-", this); - - - - // Set position - mStatsTitleLabel->setPosition(mHpLabel->getX(), mHpLabel->getY() + 23 ); - mStatsTotalLabel->setPosition(110, mStatsTitleLabel->getY() + 15); - int totalLabelY = mStatsTotalLabel->getY(); + mStatsButton[0] = new Button("+", "STR", this); + mStatsButton[1] = new Button("+", "AGI", this); + mStatsButton[2] = new Button("+", "VIT", this); + mStatsButton[3] = new Button("+", "INT", this); + mStatsButton[4] = new Button("+", "DEX", this); + mStatsButton[5] = new Button("+", "LUK", this); + // Assemble + ContainerPlacer place; + place = getPlacer(0, 0); + + place(0, 0, mLvlLabel, 3); + place(5, 0, mJobLvlLabel, 3); + place(8, 0, mGpLabel, 3); + place(1, 1, mHpLabel).setPadding(3); + place(2, 1, mHpBar, 3); + place(6, 1, mXpLabel).setPadding(3); + place(7, 1, mXpBar, 3); + place(1, 2, mMpLabel).setPadding(3); + place(2, 2, mMpBar, 3); + place(6, 2, mJobLabel).setPadding(3); + place(7, 2, mJobBar, 3); + place.getCell().matchColWidth(0, 1); + place = getPlacer(0, 3); + place(0, 0, mStatsTitleLabel, 5); + place(5, 1, mStatsTotalLabel, 5); + place(12, 1, mStatsCostLabel, 5); for (int i = 0; i < 6; i++) { - mStatsLabel[i]->setPosition(5, - mStatsTotalLabel->getY() + (i * 23) + 15); - mStatsMinus[i]->setPosition(85, totalLabelY + (i * 23) + 15); - mStatsDisplayLabel[i]->setPosition(125, - totalLabelY + (i * 23) + 15); - mStatsPlus[i]->setPosition(185, totalLabelY + (i * 23) + 15); + place(0, 2 + i, mStatsLabel[i], 7).setPadding(5); + place(7, 2 + i, mStatsDisplayLabel[i]).setPadding(5); + place(10, 2 + i, mStatsButton[i]); + place(12, 2 + i, mPointsLabel[i]).setPadding(5); } + place(14, 2, mStatsAttackLabel, 7).setPadding(5); + place(14, 3, mStatsDefenseLabel, 7).setPadding(5); + place(14, 4, mStatsMagicAttackLabel, 7).setPadding(5); + place(14, 5, mStatsMagicDefenseLabel, 7).setPadding(5); + place(14, 6, mStatsAccuracyLabel, 7).setPadding(5); + place(14, 7, mStatsEvadeLabel, 7).setPadding(5); + place(14, 8, mStatsReflexLabel, 7).setPadding(5); + place(21, 2, mStatsAttackPoints, 3).setPadding(5); + place(21, 3, mStatsDefensePoints, 3).setPadding(5); + place(21, 4, mStatsMagicAttackPoints, 3).setPadding(5); + place(21, 5, mStatsMagicDefensePoints, 3).setPadding(5); + place(21, 6, mStatsAccuracyPoints, 3).setPadding(5); + place(21, 7, mStatsEvadePoints, 3).setPadding(5); + place(21, 8, mStatsReflexPoints, 3).setPadding(5); + place(0, 8, mRemainingStatsPointsLabel, 3).setPadding(5); + + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); - mCharacterPointsLabel->setPosition(5, mStatsDisplayLabel[5]->getY() + 25); - mCorrectionPointsLabel->setPosition(5, mStatsDisplayLabel[5]->getY() + 35); -/* - mStatsAttackLabel->setPosition(220, mStatsLabel[0]->getY()); - mStatsDefenseLabel->setPosition(220, mStatsLabel[1]->getY()); - mStatsMagicAttackLabel->setPosition(220, mStatsLabel[2]->getY()); - mStatsMagicDefenseLabel->setPosition(220, mStatsLabel[3]->getY()); - mStatsAccuracyLabel->setPosition(220, mStatsLabel[4]->getY()); - mStatsEvadeLabel->setPosition(220, mStatsLabel[5]->getY()); - mStatsReflexLabel->setPosition(220, mStatsLabel[6]->getY()); - - mStatsAttackPoints->setPosition(310, mStatsLabel[0]->getY()); - mStatsDefensePoints->setPosition(310, mStatsLabel[1]->getY()); - mStatsMagicAttackPoints->setPosition(310, mStatsLabel[2]->getY()); - mStatsMagicDefensePoints->setPosition(310, mStatsLabel[3]->getY()); - mStatsAccuracyPoints->setPosition(310, mStatsLabel[4]->getY()); - mStatsEvadePoints->setPosition(310, mStatsLabel[5]->getY()); - mStatsReflexPoints->setPosition(310, mStatsLabel[6]->getY()); -*/ - // Assemble - add(mStatsTitleLabel); - add(mStatsTotalLabel); - for(int i = 0; i < 6; i++) - { - add(mStatsLabel[i]); - add(mStatsDisplayLabel[i]); - add(mStatsPlus[i]); - add(mStatsMinus[i]); - }/* - add(mStatsAttackLabel); - add(mStatsDefenseLabel); - add(mStatsMagicAttackLabel); - add(mStatsMagicDefenseLabel); - add(mStatsAccuracyLabel); - add(mStatsEvadeLabel); - add(mStatsReflexLabel); - - add(mStatsAttackPoints); - add(mStatsDefensePoints); - add(mStatsMagicAttackPoints); - add(mStatsMagicDefensePoints); - add(mStatsAccuracyPoints); - add(mStatsEvadePoints); - add(mStatsReflexPoints);*/ - - add(mCharacterPointsLabel); - add(mCorrectionPointsLabel); + loadWindowState(); } void StatusWindow::update() { // Status Part // ----------- - mLvlLabel->setCaption( "Level: " + - toString(mPlayer->getLevel()) + - " (" + - toString(mPlayer->getLevelProgress()) + - "%)"); + mLvlLabel->setCaption(strprintf(_("Level: %d"), mPlayer->getLevel())); mLvlLabel->adjustSize(); - mMoneyLabel->setCaption("Money: " + toString(mPlayer->getMoney()) + " GP"); - mMoneyLabel->adjustSize(); + mJobLvlLabel->setCaption(strprintf(_("Job: %d"), mPlayer->mJobLevel)); + mJobLvlLabel->adjustSize(); - int hp = mPlayer->getHP(); - int maxHp = mPlayer->getMaxHP(); + if (mCurrency != mPlayer->getMoney()) { + mCurrency = mPlayer->getMoney(); + mGpLabel->setCaption(strprintf(_("Money: %s"), + Units::formatCurrency(mCurrency).c_str())); + mGpLabel->adjustSize(); + } + + mHpBar->setText(toString(mPlayer->getHp()) + + "/" + toString(mPlayer->getMaxHp())); + + mMpBar->setText(toString(mPlayer->mMp) + + "/" + toString(mPlayer->mMaxMp)); - mHpValueLabel->setCaption(toString(hp) + - " / " + toString(maxHp)); - mHpValueLabel->adjustSize(); + mXpBar->setText(toString(mPlayer->getXp()) + + "/" + toString(mPlayer->mXpForNextLevel)); + + mJobBar->setText(toString(mPlayer->mJobXp) + + "/" + toString(mPlayer->mJobXpForNextLevel)); // HP Bar coloration - if (hp < int(maxHp / 3)) + if (mPlayer->getHp() < int(mPlayer->getMaxHp() / 3)) { mHpBar->setColor(223, 32, 32); // Red } - else if (hp < int((maxHp / 3) * 2)) + else if (mPlayer->getHp() < int((mPlayer->getMaxHp() / 3) * 2)) { mHpBar->setColor(230, 171, 34); // Orange } @@ -229,43 +207,43 @@ void StatusWindow::update() mHpBar->setColor(0, 171, 34); // Green } - mHpBar->setProgress((float) hp / maxHp); + mHpBar->setProgress((float) mPlayer->getHp() / (float) mPlayer->getMaxHp()); + mMpBar->setProgress((float) mPlayer->mMp / (float) mPlayer->mMaxMp); + + mXpBar->setProgress( + (float) mPlayer->getXp() / (float) mPlayer->mXpForNextLevel); + mJobBar->setProgress( + (float) mPlayer->mJobXp / (float) mPlayer->mJobXpForNextLevel); // Stats Part // ---------- - const std::string attrNames[6] = { - "Strength", - "Agility", - "Dexterity", - "Vitality", - "Intelligence", - "Willpower" + static const char *attrNames[6] = { + N_("Strength"), + N_("Agility"), + N_("Vitality"), + N_("Intelligence"), + N_("Dexterity"), + N_("Luck") }; - int characterPoints = mPlayer->getCharacterPoints(); - int correctionPoints = mPlayer->getCorrectionPoints(); + int statusPoints = mPlayer->mStatsPointsToAttribute; + // Update labels for (int i = 0; i < 6; i++) { - mStatsLabel[i]->setCaption(attrNames[i]); - mStatsDisplayLabel[i]->setCaption( - strprintf("%d / %d", - mPlayer->getAttributeEffective(CHAR_ATTR_BEGIN + i), - mPlayer->getAttributeBase(CHAR_ATTR_BEGIN + i))); + mStatsLabel[i]->setCaption(gettext(attrNames[i])); + mStatsDisplayLabel[i]->setCaption(toString((int) mPlayer->mAttr[i])); + mPointsLabel[i]->setCaption(toString((int) mPlayer->mAttrUp[i])); mStatsLabel[i]->adjustSize(); mStatsDisplayLabel[i]->adjustSize(); + mPointsLabel[i]->adjustSize(); - mStatsPlus[i]->setEnabled(characterPoints); - mStatsMinus[i]->setEnabled(correctionPoints); + mStatsButton[i]->setEnabled(mPlayer->mAttrUp[i] <= statusPoints); } - mCharacterPointsLabel->setCaption("Character Points: " + - toString(characterPoints)); - mCharacterPointsLabel->adjustSize(); + mRemainingStatsPointsLabel->setCaption( + strprintf(_("Remaining Status Points: %d"), statusPoints)); + mRemainingStatsPointsLabel->adjustSize(); - mCorrectionPointsLabel->setCaption("Correction Points: " + - toString(correctionPoints)); - mCorrectionPointsLabel->adjustSize(); -/* // Derived Stats Points // Attack TODO: Count equipped Weapons and items attack bonuses @@ -299,11 +277,6 @@ void StatusWindow::update() // Reflex % mStatsReflexPoints->setCaption(toString(mPlayer->DEX / 4)); // + counter mStatsReflexPoints->adjustSize(); -*/ - // Update Second column widgets position - mMoneyLabel->setPosition(mLvlLabel->getX() + mLvlLabel->getWidth() + 20, - mLvlLabel->getY()); - } void StatusWindow::draw(gcn::Graphics *g) @@ -315,56 +288,33 @@ void StatusWindow::draw(gcn::Graphics *g) void StatusWindow::action(const gcn::ActionEvent &event) { - const std::string &eventId = event.getId(); - // Stats Part - if (eventId == "STR+") - { - mPlayer->raiseAttribute(LocalPlayer::STR); - } - else if (eventId == "AGI+") - { - mPlayer->raiseAttribute(LocalPlayer::AGI); - } - else if (eventId == "DEX+") + if (event.getId().length() == 3) { - mPlayer->raiseAttribute(LocalPlayer::DEX); - } - else if (eventId == "VIT+") - { - mPlayer->raiseAttribute(LocalPlayer::VIT); - } - else if (eventId == "INT+") - { - mPlayer->raiseAttribute(LocalPlayer::INT); - } - else if (eventId == "WIL+") - { - mPlayer->raiseAttribute(LocalPlayer::WIL); - } - - else if (eventId == "STR-") - { - mPlayer->lowerAttribute(LocalPlayer::STR); - } - else if (eventId == "AGI-") - { - mPlayer->lowerAttribute(LocalPlayer::AGI); - } - else if (eventId == "DEX-") - { - mPlayer->lowerAttribute(LocalPlayer::DEX); - } - else if (eventId == "VIT-") - { - mPlayer->lowerAttribute(LocalPlayer::VIT); - } - else if (eventId == "INT-") - { - mPlayer->lowerAttribute(LocalPlayer::INT); - } - else if (eventId == "WIL-") - { - mPlayer->lowerAttribute(LocalPlayer::WIL); + if (event.getId() == "STR") + { + player_node->raiseAttribute(LocalPlayer::STR); + } + if (event.getId() == "AGI") + { + player_node->raiseAttribute(LocalPlayer::AGI); + } + if (event.getId() == "VIT") + { + player_node->raiseAttribute(LocalPlayer::VIT); + } + if (event.getId() == "INT") + { + player_node->raiseAttribute(LocalPlayer::INT); + } + if (event.getId() == "DEX") + { + player_node->raiseAttribute(LocalPlayer::DEX); + } + if (event.getId() == "LUK") + { + player_node->raiseAttribute(LocalPlayer::LUK); + } } } + diff --git a/src/gui/status.h b/src/gui/status.h index 262b89f6..9e4de3fd 100644 --- a/src/gui/status.h +++ b/src/gui/status.h @@ -1,39 +1,34 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_STATUS_H -#define _TMW_STATUS_H - -#include <iosfwd> +#ifndef STATUS_H +#define STATUS_H #include <guichan/actionlistener.hpp> #include "window.h" -#include "../guichanfwd.h" - class LocalPlayer; class ProgressBar; - /** * The player status dialog. * @@ -68,13 +63,16 @@ class StatusWindow : public Window, public gcn::ActionListener /** * Status Part */ - gcn::Label *mLvlLabel, *mMoneyLabel, *mHpLabel, *mHpValueLabel; - ProgressBar *mHpBar; + gcn::Label *mLvlLabel, *mJobLvlLabel; + gcn::Label *mGpLabel; + int mCurrency; + gcn::Label *mHpLabel, *mMpLabel, *mXpLabel, *mJobLabel; + ProgressBar *mHpBar, *mMpBar; + ProgressBar *mXpBar, *mJobBar; /** * Derived Statistics captions */ -/* gcn::Label *mStatsAttackLabel, *mStatsDefenseLabel; gcn::Label *mStatsMagicAttackLabel, *mStatsMagicDefenseLabel; gcn::Label *mStatsAccuracyLabel, *mStatsEvadeLabel; @@ -84,20 +82,19 @@ class StatusWindow : public Window, public gcn::ActionListener gcn::Label *mStatsMagicAttackPoints, *mStatsMagicDefensePoints; gcn::Label *mStatsAccuracyPoints, *mStatsEvadePoints; gcn::Label *mStatsReflexPoints; -*/ + /** * Stats captions. */ gcn::Label *mStatsLabel[6]; + gcn::Label *mPointsLabel[6]; gcn::Label *mStatsDisplayLabel[6]; - gcn::Label *mCharacterPointsLabel; - gcn::Label *mCorrectionPointsLabel; + gcn::Label *mRemainingStatsPointsLabel; /** * Stats buttons. */ - gcn::Button *mStatsPlus[6]; - gcn::Button *mStatsMinus[6]; + gcn::Button *mStatsButton[6]; }; extern StatusWindow *statusWindow; diff --git a/src/gui/statuswindow.cpp b/src/gui/statuswindow.cpp new file mode 100644 index 00000000..bcac0a90 --- /dev/null +++ b/src/gui/statuswindow.cpp @@ -0,0 +1,370 @@ +/* + * 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 "statuswindow.h" + +#include <guichan/widgets/label.hpp> + +#include "button.h" +#include "progressbar.h" +#include "windowcontainer.h" + +#include "../localplayer.h" + +#include "../utils/strprintf.h" +#include "../utils/stringutils.h" + +StatusWindow::StatusWindow(LocalPlayer *player): + Window(player->getName()), + mPlayer(player) +{ + setWindowName("Status"); + setResizable(true); + setCloseButton(true); + setDefaultSize((windowContainer->getWidth() - 365) / 2, + (windowContainer->getHeight() - 255) / 2, 365, 275); + loadWindowState(); + + // ---------------------- + // Status Part + // ---------------------- + + mLvlLabel = new gcn::Label("Level:"); + mMoneyLabel = new gcn::Label("Money:"); + + mHpLabel = new gcn::Label("HP:"); + mHpBar = new ProgressBar(1.0f, 80, 15, 0, 171, 34); + mHpValueLabel = new gcn::Label(""); + + int y = 3; + int x = 5; + + mLvlLabel->setPosition(x, y); + x += mLvlLabel->getWidth() + 40; + mMoneyLabel->setPosition(x, y); + + y += mLvlLabel->getHeight() + 5; // Next Row + x = 5; + + mHpLabel->setPosition(x, y); + x += mHpLabel->getWidth() + 5; + mHpBar->setPosition(x, y); + x += mHpBar->getWidth() + 5; + mHpValueLabel->setPosition(x, y); + + y += mHpLabel->getHeight() + 5; // Next Row + x = 5; + + add(mLvlLabel); + add(mMoneyLabel); + add(mHpLabel); + add(mHpValueLabel); + add(mHpBar); + + // ---------------------- + // Stats Part + // ---------------------- + + // Static Labels + gcn::Label *mStatsTitleLabel = new gcn::Label("Stats"); + gcn::Label *mStatsTotalLabel = new gcn::Label("Total"); + + // Derived Stats +/* + mStatsAttackLabel = new gcn::Label("Attack:"); + mStatsDefenseLabel= new gcn::Label("Defense:"); + mStatsMagicAttackLabel = new gcn::Label("M.Attack:"); + mStatsMagicDefenseLabel = new gcn::Label("M.Defense:"); + mStatsAccuracyLabel = new gcn::Label("% Accuracy:"); + mStatsEvadeLabel = new gcn::Label("% Evade:"); + mStatsReflexLabel = new gcn::Label("% Reflex:"); + + mStatsAttackPoints = new gcn::Label(""); + mStatsDefensePoints = new gcn::Label(""); + mStatsMagicAttackPoints = new gcn::Label(""); + mStatsMagicDefensePoints = new gcn::Label(""); + mStatsAccuracyPoints = new gcn::Label("% Accuracy:"); + mStatsEvadePoints = new gcn::Label("% Evade:"); + mStatsReflexPoints = new gcn::Label("% Reflex:"); +*/ + // New labels + for (int i = 0; i < 6; i++) { + mStatsLabel[i] = new gcn::Label(); + mStatsDisplayLabel[i] = new gcn::Label(); + } + mCharacterPointsLabel = new gcn::Label(); + mCorrectionPointsLabel = new gcn::Label(); + + // Set button events Id + mStatsPlus[0] = new Button("+", "STR+", this); + mStatsPlus[1] = new Button("+", "AGI+", this); + mStatsPlus[2] = new Button("+", "DEX+", this); + mStatsPlus[3] = new Button("+", "VIT+", this); + mStatsPlus[4] = new Button("+", "INT+", this); + mStatsPlus[5] = new Button("+", "WIL+", this); + + mStatsMinus[0] = new Button("-", "STR-", this); + mStatsMinus[1] = new Button("-", "AGI-", this); + mStatsMinus[2] = new Button("-", "DEX-", this); + mStatsMinus[3] = new Button("-", "VIT-", this); + mStatsMinus[4] = new Button("-", "INT-", this); + mStatsMinus[5] = new Button("-", "WIL-", this); + + + + // Set position + mStatsTitleLabel->setPosition(mHpLabel->getX(), mHpLabel->getY() + 23 ); + mStatsTotalLabel->setPosition(110, mStatsTitleLabel->getY() + 15); + int totalLabelY = mStatsTotalLabel->getY(); + + for (int i = 0; i < 6; i++) + { + mStatsLabel[i]->setPosition(5, + mStatsTotalLabel->getY() + (i * 23) + 15); + mStatsMinus[i]->setPosition(85, totalLabelY + (i * 23) + 15); + mStatsDisplayLabel[i]->setPosition(125, + totalLabelY + (i * 23) + 15); + mStatsPlus[i]->setPosition(185, totalLabelY + (i * 23) + 15); + } + + mCharacterPointsLabel->setPosition(5, mStatsDisplayLabel[5]->getY() + 25); + mCorrectionPointsLabel->setPosition(5, mStatsDisplayLabel[5]->getY() + 35); +/* + mStatsAttackLabel->setPosition(220, mStatsLabel[0]->getY()); + mStatsDefenseLabel->setPosition(220, mStatsLabel[1]->getY()); + mStatsMagicAttackLabel->setPosition(220, mStatsLabel[2]->getY()); + mStatsMagicDefenseLabel->setPosition(220, mStatsLabel[3]->getY()); + mStatsAccuracyLabel->setPosition(220, mStatsLabel[4]->getY()); + mStatsEvadeLabel->setPosition(220, mStatsLabel[5]->getY()); + mStatsReflexLabel->setPosition(220, mStatsLabel[6]->getY()); + + mStatsAttackPoints->setPosition(310, mStatsLabel[0]->getY()); + mStatsDefensePoints->setPosition(310, mStatsLabel[1]->getY()); + mStatsMagicAttackPoints->setPosition(310, mStatsLabel[2]->getY()); + mStatsMagicDefensePoints->setPosition(310, mStatsLabel[3]->getY()); + mStatsAccuracyPoints->setPosition(310, mStatsLabel[4]->getY()); + mStatsEvadePoints->setPosition(310, mStatsLabel[5]->getY()); + mStatsReflexPoints->setPosition(310, mStatsLabel[6]->getY()); +*/ + // Assemble + add(mStatsTitleLabel); + add(mStatsTotalLabel); + for(int i = 0; i < 6; i++) + { + add(mStatsLabel[i]); + add(mStatsDisplayLabel[i]); + add(mStatsPlus[i]); + add(mStatsMinus[i]); + }/* + add(mStatsAttackLabel); + add(mStatsDefenseLabel); + add(mStatsMagicAttackLabel); + add(mStatsMagicDefenseLabel); + add(mStatsAccuracyLabel); + add(mStatsEvadeLabel); + add(mStatsReflexLabel); + + add(mStatsAttackPoints); + add(mStatsDefensePoints); + add(mStatsMagicAttackPoints); + add(mStatsMagicDefensePoints); + add(mStatsAccuracyPoints); + add(mStatsEvadePoints); + add(mStatsReflexPoints);*/ + + add(mCharacterPointsLabel); + add(mCorrectionPointsLabel); +} + +void StatusWindow::update() +{ + // Status Part + // ----------- + mLvlLabel->setCaption( "Level: " + + toString(mPlayer->getLevel()) + + " (" + + toString(mPlayer->getLevelProgress()) + + "%)"); + mLvlLabel->adjustSize(); + + mMoneyLabel->setCaption("Money: " + toString(mPlayer->getMoney()) + " GP"); + mMoneyLabel->adjustSize(); + + int hp = mPlayer->getHp(); + int maxHp = mPlayer->getMaxHp(); + + mHpValueLabel->setCaption(toString(hp) + + " / " + toString(maxHp)); + mHpValueLabel->adjustSize(); + + // HP Bar coloration + if (hp < int(maxHp / 3)) + { + mHpBar->setColor(223, 32, 32); // Red + } + else if (hp < int((maxHp / 3) * 2)) + { + mHpBar->setColor(230, 171, 34); // Orange + } + else + { + mHpBar->setColor(0, 171, 34); // Green + } + + mHpBar->setProgress((float) hp / maxHp); + + // Stats Part + // ---------- + const std::string attrNames[6] = { + "Strength", + "Agility", + "Dexterity", + "Vitality", + "Intelligence", + "Willpower" + }; + int characterPoints = mPlayer->getCharacterPoints(); + int correctionPoints = mPlayer->getCorrectionPoints(); + // Update labels + for (int i = 0; i < 6; i++) + { + mStatsLabel[i]->setCaption(attrNames[i]); + mStatsDisplayLabel[i]->setCaption( + strprintf("%d / %d", + mPlayer->getAttributeEffective(CHAR_ATTR_BEGIN + i), + mPlayer->getAttributeBase(CHAR_ATTR_BEGIN + i))); + + mStatsLabel[i]->adjustSize(); + mStatsDisplayLabel[i]->adjustSize(); + + mStatsPlus[i]->setEnabled(characterPoints); + mStatsMinus[i]->setEnabled(correctionPoints); + } + mCharacterPointsLabel->setCaption("Character Points: " + + toString(characterPoints)); + mCharacterPointsLabel->adjustSize(); + + mCorrectionPointsLabel->setCaption("Correction Points: " + + toString(correctionPoints)); + mCorrectionPointsLabel->adjustSize(); +/* + // Derived Stats Points + + // Attack TODO: Count equipped Weapons and items attack bonuses + mStatsAttackPoints->setCaption( + toString(mPlayer->ATK + mPlayer->ATK_BONUS)); + mStatsAttackPoints->adjustSize(); + + // Defense TODO: Count equipped Armors and items defense bonuses + mStatsDefensePoints->setCaption( + toString(mPlayer->DEF + mPlayer->DEF_BONUS)); + mStatsDefensePoints->adjustSize(); + + // Magic Attack TODO: Count equipped items M.Attack bonuses + mStatsMagicAttackPoints->setCaption( + toString(mPlayer->MATK + mPlayer->MATK_BONUS)); + mStatsMagicAttackPoints->adjustSize(); + + // Magic Defense TODO: Count equipped items M.Defense bonuses + mStatsMagicDefensePoints->setCaption( + toString(mPlayer->MDEF + mPlayer->MDEF_BONUS)); + mStatsMagicDefensePoints->adjustSize(); + + // Accuracy % + mStatsAccuracyPoints->setCaption(toString(mPlayer->HIT)); + mStatsAccuracyPoints->adjustSize(); + + // Evasion % + mStatsEvadePoints->setCaption(toString(mPlayer->FLEE)); + mStatsEvadePoints->adjustSize(); + + // Reflex % + mStatsReflexPoints->setCaption(toString(mPlayer->DEX / 4)); // + counter + mStatsReflexPoints->adjustSize(); +*/ + // Update Second column widgets position + mMoneyLabel->setPosition(mLvlLabel->getX() + mLvlLabel->getWidth() + 20, + mLvlLabel->getY()); + +} + +void StatusWindow::draw(gcn::Graphics *g) +{ + update(); + + Window::draw(g); +} + +void StatusWindow::action(const gcn::ActionEvent &event) +{ + const std::string &eventId = event.getId(); + + // Stats Part + if (eventId == "STR+") + { + mPlayer->raiseAttribute(LocalPlayer::STR); + } + else if (eventId == "AGI+") + { + mPlayer->raiseAttribute(LocalPlayer::AGI); + } + else if (eventId == "DEX+") + { + mPlayer->raiseAttribute(LocalPlayer::DEX); + } + else if (eventId == "VIT+") + { + mPlayer->raiseAttribute(LocalPlayer::VIT); + } + else if (eventId == "INT+") + { + mPlayer->raiseAttribute(LocalPlayer::INT); + } + else if (eventId == "WIL+") + { + mPlayer->raiseAttribute(LocalPlayer::WIL); + } + + else if (eventId == "STR-") + { + mPlayer->lowerAttribute(LocalPlayer::STR); + } + else if (eventId == "AGI-") + { + mPlayer->lowerAttribute(LocalPlayer::AGI); + } + else if (eventId == "DEX-") + { + mPlayer->lowerAttribute(LocalPlayer::DEX); + } + else if (eventId == "VIT-") + { + mPlayer->lowerAttribute(LocalPlayer::VIT); + } + else if (eventId == "INT-") + { + mPlayer->lowerAttribute(LocalPlayer::INT); + } + else if (eventId == "WIL-") + { + mPlayer->lowerAttribute(LocalPlayer::WIL); + } +} diff --git a/src/gui/statuswindow.h b/src/gui/statuswindow.h new file mode 100644 index 00000000..262b89f6 --- /dev/null +++ b/src/gui/statuswindow.h @@ -0,0 +1,105 @@ +/* + * 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_STATUS_H +#define _TMW_STATUS_H + +#include <iosfwd> + +#include <guichan/actionlistener.hpp> + +#include "window.h" + +#include "../guichanfwd.h" + +class LocalPlayer; +class ProgressBar; + + +/** + * The player status dialog. + * + * \ingroup Interface + */ +class StatusWindow : public Window, public gcn::ActionListener +{ + public: + /** + * Constructor. + */ + StatusWindow(LocalPlayer *player); + + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event); + + /** + * Draw this window + */ + void draw(gcn::Graphics *graphics); + + /** + * Updates this dialog with values from PLAYER_INFO *char_info + */ + void update(); + + private: + LocalPlayer *mPlayer; + + /** + * Status Part + */ + gcn::Label *mLvlLabel, *mMoneyLabel, *mHpLabel, *mHpValueLabel; + ProgressBar *mHpBar; + + /** + * Derived Statistics captions + */ +/* + gcn::Label *mStatsAttackLabel, *mStatsDefenseLabel; + gcn::Label *mStatsMagicAttackLabel, *mStatsMagicDefenseLabel; + gcn::Label *mStatsAccuracyLabel, *mStatsEvadeLabel; + gcn::Label *mStatsReflexLabel; + + gcn::Label *mStatsAttackPoints, *mStatsDefensePoints; + gcn::Label *mStatsMagicAttackPoints, *mStatsMagicDefensePoints; + gcn::Label *mStatsAccuracyPoints, *mStatsEvadePoints; + gcn::Label *mStatsReflexPoints; +*/ + /** + * Stats captions. + */ + gcn::Label *mStatsLabel[6]; + gcn::Label *mStatsDisplayLabel[6]; + gcn::Label *mCharacterPointsLabel; + gcn::Label *mCorrectionPointsLabel; + + /** + * Stats buttons. + */ + gcn::Button *mStatsPlus[6]; + gcn::Button *mStatsMinus[6]; +}; + +extern StatusWindow *statusWindow; + +#endif diff --git a/src/gui/table.cpp b/src/gui/table.cpp new file mode 100644 index 00000000..1fd088ce --- /dev/null +++ b/src/gui/table.cpp @@ -0,0 +1,561 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/actionlistener.hpp> +#include <guichan/graphics.hpp> +#include <guichan/key.hpp> + +#include "color.h" +#include "table.h" + +#include "../configuration.h" + +#include "../utils/dtor.h" + +float GuiTable::mAlpha = config.getValue("guialpha", 0.8); + +class GuiTableActionListener : public gcn::ActionListener +{ +public: + GuiTableActionListener(GuiTable *_table, gcn::Widget *_widget, int _row, int _column); + + virtual ~GuiTableActionListener(); + + virtual void action(const gcn::ActionEvent& actionEvent); + +protected: + GuiTable *mTable; + int mRow; + int mColumn; + gcn::Widget *mWidget; +}; + + +GuiTableActionListener::GuiTableActionListener(GuiTable *table, gcn::Widget *widget, int row, int column) : + mTable(table), + mRow(row), + mColumn(column), + mWidget(widget) +{ + if (widget) + { + widget->addActionListener(this); + widget->_setParent(table); + } +} + +GuiTableActionListener::~GuiTableActionListener() +{ + if (mWidget) + { + mWidget->removeActionListener(this); + mWidget->_setParent(NULL); + } +} + +void GuiTableActionListener::action(const gcn::ActionEvent& actionEvent) +{ + mTable->setSelected(mRow, mColumn); + mTable->distributeActionEvent(); +} + + +GuiTable::GuiTable(TableModel *initial_model, gcn::Color background, + bool opacity) : + mLinewiseMode(false), + mWrappingEnabled(false), + mOpaque(opacity), + mBackgroundColor(background), + mModel(NULL), + mSelectedRow(0), + mSelectedColumn(0), + mTopWidget(NULL) +{ + setModel(initial_model); + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); +} + +GuiTable::~GuiTable() +{ + delete mModel; +} + +TableModel *GuiTable::getModel() const +{ + return mModel; +} + +void GuiTable::setModel(TableModel *new_model) +{ + if (mModel) + { + uninstallActionListeners(); + mModel->removeListener(this); + } + + mModel = new_model; + installActionListeners(); + + if (new_model) + { + new_model->installListener(this); + recomputeDimensions(); + } +} + +void GuiTable::recomputeDimensions() +{ + int rows_nr = mModel->getRows(); + int columns_nr = mModel->getColumns(); + int width = 0; + int height = 0; + + if (mSelectedRow >= rows_nr) + mSelectedRow = rows_nr - 1; + + if (mSelectedColumn >= columns_nr) + mSelectedColumn = columns_nr - 1; + + for (int i = 0; i < columns_nr; i++) + width += getColumnWidth(i); + + height = getRowHeight() * rows_nr; + + setWidth(width); + setHeight(height); +} + +void GuiTable::setSelected(int row, int column) +{ + mSelectedColumn = column; + mSelectedRow = row; +} + +int GuiTable::getSelectedRow() +{ + return mSelectedRow; +} + +int GuiTable::getSelectedColumn() +{ + return mSelectedColumn; +} + +void GuiTable::setLinewiseSelection(bool linewise) +{ + mLinewiseMode = linewise; +} + +int GuiTable::getRowHeight() +{ + if (mModel) + return mModel->getRowHeight() + 1; // border + else + return 0; +} + +int GuiTable::getColumnWidth(int i) +{ + if (mModel) + return mModel->getColumnWidth(i) + 1; // border + else + return 0; +} + +void GuiTable::setSelectedRow(int selected) +{ + if (!mModel) + { + mSelectedRow = -1; + } + else + { + if (selected < 0 && !mWrappingEnabled) + { + mSelectedRow = -1; + } + else if (selected >= mModel->getRows() && mWrappingEnabled) + { + mSelectedRow = 0; + } + else if ((selected >= mModel->getRows() && !mWrappingEnabled) || + (selected < 0 && mWrappingEnabled)) + { + mSelectedRow = mModel->getRows() - 1; + } + else + { + mSelectedRow = selected; + } + } +} + +void GuiTable::setSelectedColumn(int selected) +{ + if (!mModel) + { + mSelectedColumn = -1; + } + else + { + if ((selected >= mModel->getColumns() && mWrappingEnabled) || + (selected < 0 && !mWrappingEnabled)) + { + mSelectedColumn = 0; + } + else if ((selected >= mModel->getColumns() && !mWrappingEnabled) || + (selected < 0 && mWrappingEnabled)) + { + mSelectedColumn = mModel->getColumns() - 1; + } + else + { + mSelectedColumn = selected; + } + } +} + +void GuiTable::uninstallActionListeners(void) +{ + delete_all(mActionListeners); + mActionListeners.clear(); +} + +void GuiTable::installActionListeners() +{ + if (!mModel) + return; + + int rows = mModel->getRows(); + int columns = mModel->getColumns(); + + for (int row = 0; row < rows; ++row) + for (int column = 0; column < columns; ++column) + { + gcn::Widget *widget = mModel->getElementAt(row, column); + mActionListeners.push_back(new GuiTableActionListener(this, widget, + row, column)); + } + + _setFocusHandler(_getFocusHandler()); // propagate focus handler to widgets +} + +// -- widget ops +void GuiTable::draw(gcn::Graphics* graphics) +{ + if (!mModel) + return; + + if (config.getValue("guialpha", 0.8) != mAlpha) + mAlpha = config.getValue("guialpha", 0.8); + + if (mOpaque) + { + const int red = getBackgroundColor().r; + const int green = getBackgroundColor().g; + const int blue = getBackgroundColor().b; + const int alpha = (int)(mAlpha * 255.0f); + graphics->setColor(gcn::Color(red, green, blue, alpha)); + graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight())); + } + + // First, determine how many rows we need to draw, and where we should start. + int first_row = -(getY() / getRowHeight()); + + if (first_row < 0) + first_row = 0; + + int rows_nr = 1 + (getHeight() / getRowHeight()); // May overestimate by one. + + int max_rows_nr = mModel->getRows() - first_row; // clip if neccessary: + if (max_rows_nr < rows_nr) + rows_nr = max_rows_nr; + + // Now determine the first and last column + // Take the easy way out; these are usually bounded and all visible. + int first_column = 0; + int last_column = mModel->getColumns() - 1; + + // Set up everything for drawing + int height = getRowHeight(); + int y_offset = first_row * height; + + for (int r = first_row; r < first_row + rows_nr; ++r) + { + int x_offset = 0; + + for (int c = first_column; c <= last_column; ++c) + { + gcn::Widget *widget = mModel->getElementAt(r, c); + int width = getColumnWidth(c); + if (widget) + { + gcn::Rectangle bounds(x_offset, y_offset, width, height); + + if (widget == mTopWidget) + { + bounds.height = widget->getHeight(); + bounds.width = widget->getWidth(); + } + + widget->setDimension(bounds); + + if (!mLinewiseMode && c == mSelectedColumn && r == mSelectedRow) + { + bool valid; + const int red = + (textColor->getColor('H', valid) >> 16) & 0xFF; + const int green = + (textColor->getColor('H', valid) >> 8) & 0xFF; + const int blue = textColor->getColor('H', valid) & 0xFF; + const int alpha = (int)(mAlpha * 127.0f); + + graphics->setColor(gcn::Color(red, green, blue, alpha)); + graphics->fillRectangle(bounds); + } + + graphics->pushClipArea(bounds); + widget->draw(graphics); + graphics->popClipArea(); + } + + x_offset += width; + } + + if (mLinewiseMode && r == mSelectedRow) + { + bool valid; + const int red = + (textColor->getColor('H', valid) >> 16) & 0xFF; + const int green = + (textColor->getColor('H', valid) >> 8) & 0xFF; + const int blue = textColor->getColor('H', valid) & 0xFF; + const int alpha = (int)(mAlpha * 127.0f); + + graphics->setColor(gcn::Color(red, green, blue, alpha)); + graphics->fillRectangle(gcn::Rectangle(0, y_offset, + x_offset, height)); + } + + y_offset += height; + } + + if (mTopWidget) + { + gcn::Rectangle bounds = mTopWidget->getDimension(); + graphics->pushClipArea(bounds); + mTopWidget->draw(graphics); + graphics->popClipArea(); + } +} + +void GuiTable::moveToTop(gcn::Widget *widget) +{ + gcn::Widget::moveToTop(widget); + mTopWidget = widget; +} + +void GuiTable::moveToBottom(gcn::Widget *widget) +{ + gcn::Widget::moveToBottom(widget); + if (widget == mTopWidget) + mTopWidget = NULL; +} + +gcn::Rectangle GuiTable::getChildrenArea() +{ + return gcn::Rectangle(0, 0, getWidth(), getHeight()); +} + +// -- KeyListener notifications +void GuiTable::keyPressed(gcn::KeyEvent& keyEvent) +{ + gcn::Key key = keyEvent.getKey(); + + if (key.getValue() == gcn::Key::ENTER || key.getValue() == gcn::Key::SPACE) + { + distributeActionEvent(); + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::UP) + { + setSelectedRow(mSelectedRow - 1); + + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::DOWN) + { + setSelectedRow(mSelectedRow + 1); + + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::LEFT) + { + setSelectedColumn(mSelectedColumn - 1); + + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::RIGHT) + { + setSelectedColumn(mSelectedColumn + 1); + + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::HOME) + { + setSelectedRow(0); + setSelectedColumn(0); + keyEvent.consume(); + } + else if (key.getValue() == gcn::Key::END) + { + setSelectedRow(mModel->getRows() - 1); + setSelectedColumn(mModel->getColumns() - 1); + keyEvent.consume(); + } +} + +// -- MouseListener notifications +void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent) +{ + if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) + { + int row = getRowForY(mouseEvent.getY()); + int column = getColumnForX(mouseEvent.getX()); + + if (row > -1 && column > -1 && + row < mModel->getRows() && column < mModel->getColumns()) + { + mSelectedColumn = column; + mSelectedRow = row; + } + + distributeActionEvent(); + } +} + +void GuiTable::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent) +{ + if (isFocused()) + { + if (getSelectedRow() >= 0 ) + { + setSelectedRow(getSelectedRow() - 1); + } + + mouseEvent.consume(); + } +} + +void GuiTable::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) +{ + if (isFocused()) + { + setSelectedRow(getSelectedRow() + 1); + + mouseEvent.consume(); + } +} + +void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent) +{ +} + +// -- TableModelListener notifications +void GuiTable::modelUpdated(bool completed) +{ + if (completed) + { + recomputeDimensions(); + installActionListeners(); + } + else + { // before the update? + mTopWidget = NULL; // No longer valid in general + uninstallActionListeners(); + } +} + +gcn::Widget *GuiTable::getWidgetAt(int x, int y) +{ + int row = getRowForY(y); + int column = getColumnForX(x); + + if (mTopWidget && mTopWidget->getDimension().isPointInRect(x, y)) + return mTopWidget; + + if (row > -1 && column > -1) + { + gcn::Widget *w = mModel->getElementAt(row, column); + if (w && w->isFocusable()) + return w; + else + return NULL; // Grab the event locally + } + else + return NULL; +} + +int GuiTable::getRowForY(int y) +{ + int row = y / getRowHeight(); + + if (row < 0 || row >= mModel->getRows()) + return -1; + else + return row; +} + +int GuiTable::getColumnForX(int x) +{ + int column; + int delta = 0; + + for (column = 0; column < mModel->getColumns(); column++) + { + delta += getColumnWidth(column); + if (x <= delta) + break; + } + + if (column < 0 || column >= mModel->getColumns()) + return -1; + else + return column; +} + +void GuiTable::_setFocusHandler(gcn::FocusHandler* focusHandler) +{ + gcn::Widget::_setFocusHandler(focusHandler); + + if (mModel) { + for (int r = 0; r < mModel->getRows(); ++r) { + for (int c = 0; c < mModel->getColumns(); ++c) { + gcn::Widget *w = mModel->getElementAt(r, c); + if (w) + w->_setFocusHandler(focusHandler); + } + } + } +} diff --git a/src/gui/table.h b/src/gui/table.h new file mode 100644 index 00000000..d73cf340 --- /dev/null +++ b/src/gui/table.h @@ -0,0 +1,187 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TABLE_H +#define TABLE_H + +#include <vector> + +#include <guichan/keylistener.hpp> +#include <guichan/mouselistener.hpp> +#include <guichan/widget.hpp> + +#include "table_model.h" + +class GuiTableActionListener; + +/** + * A table, with rows and columns made out of sub-widgets. Largely inspired by + * (and can be thought of as a generalisation of) the guichan listbox + * implementation. + * + * Normally you want this within a ScrollArea. + * + * \ingroup GUI + */ +class GuiTable : public gcn::Widget, + public gcn::MouseListener, + public gcn::KeyListener, + public TableModelListener +{ + // so that the action listener can call distributeActionEvent + friend class GuiTableActionListener; + +public: + GuiTable(TableModel * initial_model = NULL, gcn::Color background = 0xffffff, + bool opacity = true); + + virtual ~GuiTable(); + + /** + * Retrieves the active table model + */ + TableModel *getModel() const; + + /** + * Sets the table model + * + * Note that actions issued by widgets returned from the model will update + * the table selection, but only AFTER any event handlers installed within + * the widget have been triggered. To be notified after such an update, add + * an action listener to the table instead. + */ + void setModel(TableModel *m); + + const TableModel* getModel() {return mModel;} + + void setSelected(int row, int column); + + int getSelectedRow(); + + int getSelectedColumn(); + + void setSelectedRow(int selected); + + void setSelectedColumn(int selected); + + bool isWrappingEnabled() const {return mWrappingEnabled;} + + void setWrappingEnabled(bool wrappingEnabled) + {mWrappingEnabled = wrappingEnabled;} + + gcn::Rectangle getChildrenArea(void); + + /** + * Toggle whether to use linewise selection mode, in which the table selects + * an entire line at a time, rather than a single cell. + * + * Note that column information is tracked even in linewise selection mode; + * this mode therefore only affects visualisation. + * + * Disabled by default. + * + * \param linewise: Whether to enable linewise selection mode + */ + void setLinewiseSelection(bool linewise); + + // Inherited from Widget + virtual void draw(gcn::Graphics* graphics); + + virtual gcn::Widget *getWidgetAt(int x, int y); + + virtual void moveToTop(gcn::Widget *child); + + virtual void moveToBottom(gcn::Widget *child); + + virtual void _setFocusHandler(gcn::FocusHandler* focusHandler); + + // Inherited from KeyListener + virtual void keyPressed(gcn::KeyEvent& keyEvent); + + /** + * Sets the table to be opaque, that is sets the table + * to display its background. + * + * @param opaque True if the table should be opaque, false otherwise. + */ + virtual void setOpaque(bool opaque) {mOpaque = opaque;} + + /** + * Checks if the table is opaque, that is if the table area displays its + * background. + * + * @return True if the table is opaque, false otherwise. + */ + virtual bool isOpaque() const {return mOpaque;} + + // Inherited from MouseListener + virtual void mousePressed(gcn::MouseEvent& mouseEvent); + + virtual void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent); + + virtual void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent); + + virtual void mouseDragged(gcn::MouseEvent& mouseEvent); + + // Constraints inherited from TableModelListener + virtual void modelUpdated(bool); + +protected: + /** Frees all action listeners on inner widgets. */ + virtual void uninstallActionListeners(); + /** Installs all action listeners on inner widgets. */ + virtual void installActionListeners(); + + virtual int getRowHeight(); + virtual int getColumnWidth(int i); + +private: + int getRowForY(int y); // -1 on error + int getColumnForX(int x); // -1 on error + void recomputeDimensions(); + bool mLinewiseMode; + bool mWrappingEnabled; + bool mOpaque; + + static float mAlpha; + + /** + * Holds the background color of the table. + */ + gcn::Color mBackgroundColor; + + TableModel *mModel; + + int mSelectedRow; + int mSelectedColumn; + + /** Number of frames to skip upwards when drawing the selected widget. */ + int mPopFramesNr; + + /** If someone moves a fresh widget to the top, we must display it. */ + gcn::Widget *mTopWidget; + + /** Vector for compactness; used as a list in practice. */ + std::vector<GuiTableActionListener *> mActionListeners; +}; + + +#endif /* !defined(TABLE_H) */ diff --git a/src/gui/table_model.cpp b/src/gui/table_model.cpp new file mode 100644 index 00000000..4fa13bae --- /dev/null +++ b/src/gui/table_model.cpp @@ -0,0 +1,161 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/widget.hpp> + +#include "table_model.h" + +#include "../utils/dtor.h" + +void TableModel::installListener(TableModelListener *listener) +{ + listeners.insert(listener); +} + +void TableModel::removeListener(TableModelListener *listener) +{ + listeners.erase(listener); +} + +void TableModel::signalBeforeUpdate() +{ + for (std::set<TableModelListener *>::const_iterator it = listeners.begin(); it != listeners.end(); it++) + (*it)->modelUpdated(false); +} + +void TableModel::signalAfterUpdate() +{ + for (std::set<TableModelListener *>::const_iterator it = listeners.begin(); it != listeners.end(); it++) + (*it)->modelUpdated(true); +} + + +#define WIDGET_AT(row, column) (((row) * mColumns) + (column)) +#define DYN_SIZE(h) ((h) >= 0) // determines whether this size is tagged for auto-detection + +StaticTableModel::StaticTableModel(int row, int column) : + mRows(row), + mColumns(column), + mHeight(1) +{ + mTableModel.resize(row * column, NULL); + mWidths.resize(column, 1); +} + +StaticTableModel::~StaticTableModel() +{ + delete_all(mTableModel); +} + +void StaticTableModel::resize() +{ + mRows = getRows(); + mColumns = getColumns(); + mTableModel.resize(mRows * mColumns, NULL); +} + +void StaticTableModel::set(int row, int column, gcn::Widget *widget) +{ + if (row >= mRows || row < 0 + || column >= mColumns || column < 0) + // raise exn? + return; + + if (DYN_SIZE(mHeight) + && widget->getHeight() > mHeight) + mHeight = widget->getHeight(); + + if (DYN_SIZE(mWidths[column]) + && widget->getWidth() > mWidths[column]) + mWidths[column] = widget->getWidth(); + + signalBeforeUpdate(); + + if (mTableModel[WIDGET_AT(row, column)]) + delete mTableModel[WIDGET_AT(row, column)]; + + mTableModel[WIDGET_AT(row, column)] = widget; + + signalAfterUpdate(); +} + +gcn::Widget *StaticTableModel::getElementAt(int row, int column) +{ + return mTableModel[WIDGET_AT(row, column)]; +} + +void StaticTableModel::fixColumnWidth(int column, int width) +{ + if (width < 0 + || column < 0 || column >= mColumns) + return; + + mWidths[column] = -width; // Negate to tag as fixed +} + +void StaticTableModel::fixRowHeight(int height) +{ + if (height < 0) + return; + + mHeight = -height; +} + +int StaticTableModel::getRowHeight() +{ + return abs(mHeight); +} + +int StaticTableModel::getColumnWidth(int column) +{ + if (column < 0 || column >= mColumns) + return 0; + + return abs(mWidths[column]); +} + +int StaticTableModel::getRows() +{ + return mRows; +} + +int StaticTableModel::getColumns() +{ + return mColumns; +} + +int StaticTableModel::getWidth(void) +{ + int width = 0; + + for (unsigned int i = 0; i < mWidths.size(); i++) + { + width += mWidths[i]; + } + + return width; +} + +int StaticTableModel::getHeight(void) +{ + return (mColumns * mHeight); +} + diff --git a/src/gui/table_model.h b/src/gui/table_model.h new file mode 100644 index 00000000..9ca36120 --- /dev/null +++ b/src/gui/table_model.h @@ -0,0 +1,144 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TABLE_MODEL_H +#define TABLE_MODEL_H + +#include <set> +#include <vector> + +class TableModelListener +{ +public: + /** + * Must be invoked by the TableModel whenever a global change is about to + * occur or has occurred (e.g., when a row or column is being removed or + * added). + * + * This method is triggered twice, once before and once after the update. + * + * \param completed whether we are signalling the end of the update + */ + virtual void modelUpdated(bool completed) = 0; +}; + +/** + * A model for a regular table of widgets. + */ +class TableModel +{ +public: + virtual ~TableModel() { } + + /** + * Determines the number of rows (lines) in the table + */ + virtual int getRows() = 0; + + /** + * Determines the number of columns in each row + */ + virtual int getColumns() = 0; + + /** + * Determines the height for each row + */ + virtual int getRowHeight() = 0; + + /** + * Determines the width of each individual column + */ + virtual int getColumnWidth(int index) = 0; + + /** + * Retrieves the widget stored at the specified location within the table. + */ + virtual gcn::Widget *getElementAt(int row, int column) = 0; + + virtual void installListener(TableModelListener *listener); + + virtual void removeListener(TableModelListener *listener); + +protected: + /** + * Tells all listeners that the table is about to see an update + */ + virtual void signalBeforeUpdate(); + + /** + * Tells all listeners that the table has seen an update + */ + virtual void signalAfterUpdate(); + +private: + std::set<TableModelListener *> listeners; +}; + + +class StaticTableModel : public TableModel +{ +public: + StaticTableModel(int width, int height); + virtual ~StaticTableModel(); + + /** + * Inserts a widget into the table model. + * The model is resized to accomodate the widget's width and height, + * unless column width / row height have been fixed. + */ + virtual void set(int row, int column, gcn::Widget *widget); + + /** + * Fixes the column width for a given column; this overrides dynamic width + * inference. + * + * Semantics are undefined for width 0. + */ + virtual void fixColumnWidth(int column, int width); + + /** + * Fixes the row height; this overrides dynamic height inference. + * + * Semantics are undefined for width 0. + */ + virtual void fixRowHeight(int height); + + /** + * Resizes the table model + */ + virtual void resize(); + + virtual int getRows(); + virtual int getColumns(); + virtual int getRowHeight(); + virtual int getWidth(); + virtual int getHeight(); + virtual int getColumnWidth(int index); + virtual gcn::Widget *getElementAt(int row, int column); + +protected: + int mRows, mColumns; + int mHeight; + std::vector<gcn::Widget *> mTableModel; + std::vector<int> mWidths; +}; + +#endif /* !defined(TABLE_MODEL_H) */ diff --git a/src/gui/textbox.cpp b/src/gui/textbox.cpp index 619265ec..2a86d549 100644 --- a/src/gui/textbox.cpp +++ b/src/gui/textbox.cpp @@ -1,39 +1,39 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "textbox.h" - #include <sstream> -#include <guichan/basiccontainer.hpp> #include <guichan/font.hpp> +#include "textbox.h" + TextBox::TextBox(): gcn::TextBox() { setOpaque(false); setFrameSize(0); + mMinWidth = getWidth(); } -void TextBox::setTextWrapped(const std::string &text) +void TextBox::setTextWrapped(const std::string &text, int minDimension) { // Make sure parent scroll area sets width of this widget if (getParent()) @@ -41,8 +41,13 @@ void TextBox::setTextWrapped(const std::string &text) getParent()->logic(); } + // Take the supplied minimum dimension as a starting point and try to beat it + mMinWidth = minDimension; + std::stringstream wrappedStream; std::string::size_type newlinePos, lastNewlinePos = 0; + int minWidth = 0; + int xpos; do { @@ -57,7 +62,18 @@ void TextBox::setTextWrapped(const std::string &text) std::string line = text.substr(lastNewlinePos, newlinePos - lastNewlinePos); std::string::size_type spacePos, lastSpacePos = 0; - int xpos = 0; + xpos = 0; + + spacePos = text.rfind(" ", text.size()); + + if (spacePos != std::string::npos) + { + const std::string word = text.substr(spacePos + 1); + const int length = getFont()->getWidth(word); + + if (length > mMinWidth) + mMinWidth = length; + } do { @@ -73,7 +89,7 @@ void TextBox::setTextWrapped(const std::string &text) int width = getFont()->getWidth(word); - if (xpos != 0 && xpos + width < getWidth()) + if (xpos != 0 && xpos + width + getFont()->getWidth(" ") <= mMinWidth) { xpos += width + getFont()->getWidth(" "); wrappedStream << " " << word; @@ -85,22 +101,46 @@ void TextBox::setTextWrapped(const std::string &text) } else { + if (xpos > minWidth) + minWidth = xpos; + + // The window wasn't big enough. Resize it and try again. + if (minWidth > mMinWidth) + { + mMinWidth = minWidth; + wrappedStream.clear(); + wrappedStream.str(""); + spacePos = 0; + lastNewlinePos = 0; + newlinePos = text.find("\n", lastNewlinePos); + if (newlinePos == std::string::npos) + newlinePos = text.size(); + line = text.substr(lastNewlinePos, newlinePos - + lastNewlinePos); + width = 0; + break; + } + else + { + wrappedStream << "\n" << word; + } xpos = width; - wrappedStream << "\n" << word; } - lastSpacePos = spacePos + 1; } while (spacePos != line.size()); if (text.find("\n", lastNewlinePos) != std::string::npos) - { wrappedStream << "\n"; - } lastNewlinePos = newlinePos + 1; } while (newlinePos != text.size()); + if (xpos > minWidth) + minWidth = xpos; + + mMinWidth = minWidth; + gcn::TextBox::setText(wrappedStream.str()); } diff --git a/src/gui/textbox.h b/src/gui/textbox.h index 2060e377..10a81fc0 100644 --- a/src/gui/textbox.h +++ b/src/gui/textbox.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_TEXTBOX_H__ -#define __TMW_TEXTBOX_H__ +#ifndef TEXTBOX_H +#define TEXTBOX_H #include <guichan/widgets/textbox.hpp> @@ -31,7 +31,8 @@ * * \ingroup GUI */ -class TextBox : public gcn::TextBox { +class TextBox : public gcn::TextBox +{ public: /** * Constructor. @@ -41,7 +42,15 @@ class TextBox : public gcn::TextBox { /** * Sets the text after wrapping it to the current width of the widget. */ - void setTextWrapped(const std::string &text); + void setTextWrapped(const std::string &text, int minDimension); + + /** + * Get the minimum text width for the text box. + */ + int getMinWidth() { return mMinWidth; } + + private: + int mMinWidth; }; #endif diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp index 49c0c91d..99a95a2e 100644 --- a/src/gui/textfield.cpp +++ b/src/gui/textfield.cpp @@ -1,32 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - #include <guichan/font.hpp> -#include "textfield.h" - #include "sdlinput.h" +#include "textfield.h" +#include "../configuration.h" #include "../graphics.h" #include "../resources/image.h" @@ -37,10 +35,13 @@ #undef DELETE //Win32 compatibility hack int TextField::instances = 0; +float TextField::mAlpha = config.getValue("guialpha", 0.8); ImageRect TextField::skin; TextField::TextField(const std::string& text): - gcn::TextField(text) + gcn::TextField(text), + mNumeric(false), + mListener(0) { setFrameSize(2); @@ -51,9 +52,6 @@ TextField::TextField(const std::string& text): Image *textbox = resman->getImage("graphics/gui/deepbox.png"); int gridx[4] = {0, 3, 28, 31}; int gridy[4] = {0, 3, 28, 31}; - //Image *textbox = resman->getImage("graphics/gui/textbox.png"); - //int gridx[4] = {0, 5, 26, 31}; - //int gridy[4] = {0, 5, 26, 31}; int a = 0, x, y; for (y = 0; y < 3; y++) { @@ -62,6 +60,7 @@ TextField::TextField(const std::string& text): gridx[x], gridy[y], gridx[x + 1] - gridx[x] + 1, gridy[y + 1] - gridy[y] + 1); + skin.grid[a]->setAlpha(config.getValue("guialpha", 0.8)); a++; } } @@ -93,6 +92,15 @@ void TextField::draw(gcn::Graphics *graphics) graphics->setColor(getForegroundColor()); graphics->setFont(getFont()); graphics->drawText(mText, 1 - mXScroll, 1); + + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + for (int a = 0; a < 9; a++) + { + skin.grid[a]->setAlpha(mAlpha); + } + } } void TextField::drawFrame(gcn::Graphics *graphics) @@ -105,6 +113,42 @@ void TextField::drawFrame(gcn::Graphics *graphics) static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin); } +void TextField::setNumeric(bool numeric) +{ + mNumeric = numeric; + if (!numeric) + { + return; + } + const char *text = mText.c_str(); + for (const char *textPtr = text; *textPtr; ++textPtr) + { + if (*textPtr < '0' || *textPtr > '9') + { + setText(mText.substr(0, textPtr - text)); + return; + } + } +} + +int TextField::getValue() const +{ + if (!mNumeric) + { + return 0; + } + int value = atoi(mText.c_str()); + if (value < mMinimum) + { + return mMinimum; + } + if (value > mMaximum) + { + return mMaximum; + } + return value; +} + void TextField::keyPressed(gcn::KeyEvent &keyEvent) { int val = keyEvent.getKey().getValue(); diff --git a/src/gui/textfield.h b/src/gui/textfield.h index b808fad2..73824615 100644 --- a/src/gui/textfield.h +++ b/src/gui/textfield.h @@ -1,30 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_TEXTFIELD_H__ -#define __TMW_TEXTFIELD_H__ +#ifndef TEXTFIELD_H +#define TEXTFIELD_H #include <guichan/widgets/textfield.hpp> class ImageRect; +class TextField; + +class TextFieldListener +{ + public: + virtual void listen(const TextField *value) = 0; +}; /** * A text field. @@ -54,13 +61,48 @@ class TextField : public gcn::TextField { void drawFrame(gcn::Graphics *graphics); /** + * Determine whether the field should be numeric or not + */ + void setNumeric(bool numeric); + + /** + * Set the range on the field if it is numeric + */ + void setRange(int min, int max) {mMinimum = min; mMaximum = max; } + + /** * Processes one keypress. */ void keyPressed(gcn::KeyEvent &keyEvent); + /** + * Set the minimum value for a range + */ + void setMinimum(int min) {mMinimum = min; } + + /** + * Set the maximum value for a range + */ + void setMaximum(int max) {mMaximum = max; } + + /** + * Return the value for a numeric field + */ + int getValue() const; + + /** + * Add a listener + */ + void addListener(TextFieldListener *listener) {mListener = listener; } + private: static int instances; + static float mAlpha; static ImageRect skin; + bool mNumeric; + int mMinimum; + int mMaximum; + TextFieldListener *mListener; }; #endif diff --git a/src/gui/trade.cpp b/src/gui/trade.cpp index 0592c485..98214a79 100644 --- a/src/gui/trade.cpp +++ b/src/gui/trade.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -24,8 +24,6 @@ #include <guichan/font.hpp> #include <guichan/widgets/label.hpp> -#include "trade.h" - #include "button.h" #include "chat.h" #include "inventorywindow.h" @@ -33,42 +31,68 @@ #include "itemcontainer.h" #include "scrollarea.h" #include "textfield.h" +#include "trade.h" #include "widgets/layout.h" #include "../inventory.h" #include "../item.h" #include "../localplayer.h" +#include "../units.h" +#ifdef TMWSERV_SUPPORT #include "../net/gameserver/player.h" - -#include "../resources/iteminfo.h" +#else +#include "../net/messageout.h" +#include "../net/ea/protocol.h" +#endif #include "../utils/gettext.h" +#include "../utils/stringutils.h" #include "../utils/strprintf.h" +#ifdef TMWSERV_SUPPORT TradeWindow::TradeWindow(): - Window("Trade: You"), - mMyInventory(new Inventory), - mPartnerInventory(new Inventory), - mStatus(PREPARING) +#else +TradeWindow::TradeWindow(Network *network): +#endif + Window(_("Trade: You")), +#ifdef EATHENA_SUPPORT + mNetwork(network), +#endif + mMyInventory(new Inventory(INVENTORY_SIZE)), + mPartnerInventory(new Inventory(INVENTORY_SIZE)) +#ifdef TMWSERV_SUPPORT + , mStatus(PREPARING) +#endif { setWindowName("Trade"); setResizable(true); setDefaultSize(115, 197, 332, 209); Button *mAddButton = new Button(_("Add"), "add", this); +#ifdef EATHENA_SUPPORT + mOkButton = new Button(_("Ok"), "ok", this); +#endif Button *mCancelButton = new Button(_("Cancel"), "cancel", this); mTradeButton = new Button(_("Propose trade"), "trade", this); mTradeButton->setWidth(8 + std::max( mTradeButton->getFont()->getWidth(_("Propose trade")), mTradeButton->getFont()->getWidth(_("Confirm trade")))); - mMyItemContainer = new ItemContainer(mMyInventory, 4, 3); +#ifdef TMWSERV_SUPPORT + mMyItemContainer = new ItemContainer(mMyInventory.get(), 4, 3, 0); +#else + mMyItemContainer = new ItemContainer(mMyInventory.get(), 4, 3, 2); +#endif mMyItemContainer->addSelectionListener(this); ScrollArea *mMyScroll = new ScrollArea(mMyItemContainer); - mPartnerItemContainer = new ItemContainer(mPartnerInventory, 4, 3); +#ifdef TMWSERV_SUPPORT + mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 4, 3, 0); +#else + mPartnerItemContainer = new ItemContainer(mPartnerInventory.get(), 4, 3, 2); +#endif mPartnerItemContainer->addSelectionListener(this); ScrollArea *mPartnerScroll = new ScrollArea(mPartnerItemContainer); @@ -78,10 +102,6 @@ TradeWindow::TradeWindow(): mMoneyField->setWidth(40); Button *mMoneyChange = new Button(_("Change"), "money", this); - mItemNameLabel = new gcn::Label(strprintf(_("Name: %s"), "")); - mItemDescriptionLabel = new gcn::Label( - strprintf(_("Description: %s"), "")); - place(1, 0, mMoneyLabel); place(0, 1, mMyScroll).setPadding(3); place(1, 1, mPartnerScroll).setPadding(3); @@ -91,11 +111,12 @@ TradeWindow::TradeWindow(): place(1, 0, mMoneyField); place(2, 0, mMoneyChange).setHAlign(LayoutCell::LEFT); place = getPlacer(0, 2); - place(0, 0, mItemNameLabel, 4); - place(0, 1, mItemDescriptionLabel, 4); - place(0, 2, mAddButton); - place(2, 2, mTradeButton); - place(3, 2, mCancelButton); + place(0, 0, mAddButton); +#ifdef EATHENA_SUPPORT + place(1, 0, mOkButton); +#endif + place(2, 0, mTradeButton); + place(3, 0, mCancelButton); Layout &layout = getLayout(); layout.extend(0, 2, 2, 1); layout.setRowHeight(1, Layout::AUTO_SET); @@ -108,69 +129,151 @@ TradeWindow::TradeWindow(): TradeWindow::~TradeWindow() { - delete mMyInventory; - delete mPartnerInventory; } void TradeWindow::setMoney(int amount) { - mMoneyLabel->setCaption(strprintf(_("You get %d GP."), amount)); + mMoneyLabel->setCaption(strprintf(_("You get %s."), + Units::formatCurrency(amount).c_str())); + mMoneyLabel->adjustSize(); +#ifdef TMWSERV_SUPPORT setStatus(PREPARING); +#endif } +#ifdef TMWSERV_SUPPORT void TradeWindow::addItem(int id, bool own, int quantity) { (own ? mMyInventory : mPartnerInventory)->addItem(id, quantity); setStatus(PREPARING); } +#endif + +#ifdef EATHENA_SUPPORT +void TradeWindow::addItem(int id, bool own, int quantity, bool equipment) +{ + if (own) + { + mMyInventory->addItem(id, quantity, equipment); + } + else + { + mPartnerInventory->addItem(id, quantity, equipment); + } +} + +void TradeWindow::changeQuantity(int index, bool own, int quantity) +{ + if (own) + mMyInventory->getItem(index)->setQuantity(quantity); + else + mPartnerInventory->getItem(index)->setQuantity(quantity); +} + +void TradeWindow::increaseQuantity(int index, bool own, int quantity) +{ + if (own) + mMyInventory->getItem(index)->increaseQuantity(quantity); + else + mPartnerInventory->getItem(index)->increaseQuantity(quantity); +} +#endif void TradeWindow::reset() { mMyInventory->clear(); mPartnerInventory->clear(); - mMoneyLabel->setCaption(strprintf(_("You get %d GP."), 0)); +#ifdef EATHENA_SUPPORT + mTradeButton->setEnabled(false); + mOkButton->setEnabled(true); + mOkOther = false; + mOkMe = false; +#endif + mMoneyLabel->setCaption(strprintf(_("You get %s."), "")); mMoneyField->setEnabled(true); mMoneyField->setText(""); +#ifdef TMWSERV_SUPPORT setStatus(PREPARING); +#endif } +#ifdef TMWSERV_SUPPORT + void TradeWindow::receivedOk() { setStatus(ACCEPTING); } +#else + +void TradeWindow::setTradeButton(bool enabled) +{ + mTradeButton->setEnabled(enabled); +} + +void TradeWindow::receivedOk(bool own) +{ + if (own) + { + mOkMe = true; + if (mOkOther) + { + mTradeButton->setEnabled(true); + mOkButton->setEnabled(false); + } + else + { + mTradeButton->setEnabled(false); + mOkButton->setEnabled(false); + } + } + else + { + mOkOther = true; + if (mOkMe) + { + mTradeButton->setEnabled(true); + mOkButton->setEnabled(false); + } + else + { + mTradeButton->setEnabled(false); + mOkButton->setEnabled(true); + } + } +} + +#endif + void TradeWindow::tradeItem(Item *item, int quantity) { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::tradeItem(item->getInvIndex(), quantity); addItem(item->getId(), true, quantity); item->increaseQuantity(-quantity); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST); + outMsg.writeInt16(item->getInvIndex()); + outMsg.writeInt32(quantity); +#endif } void TradeWindow::valueChanged(const gcn::SelectionEvent &event) { - Item *item; + const Item *item; /* If an item is selected in one container, make sure no item is selected * in the other container. */ if (event.getSource() == mMyItemContainer && - (item = mMyItemContainer->getItem())) - { + (item = mMyItemContainer->getSelectedItem())) mPartnerItemContainer->selectNone(); - } - else if ((item = mPartnerItemContainer->getItem())) - { + else if ((item = mPartnerItemContainer->getSelectedItem())) mMyItemContainer->selectNone(); - } - - // Update name and description - ItemInfo const *info = item ? &item->getInfo() : NULL; - mItemNameLabel->setCaption(strprintf(_("Name: %s"), - info ? info->getName().c_str() : "")); - mItemDescriptionLabel->setCaption(strprintf(_("Description: %s"), - info ? info->getDescription().c_str() : "")); } +#ifdef TMWSERV_SUPPORT void TradeWindow::setStatus(Status s) { if (s == mStatus) return; @@ -180,44 +283,86 @@ void TradeWindow::setStatus(Status s) (s == PREPARING ? _("Propose trade") : _("Confirm trade")); mTradeButton->setEnabled(s != PROPOSING); } +#endif void TradeWindow::action(const gcn::ActionEvent &event) { - Item *item = inventoryWindow->getItem(); + Item *item = inventoryWindow->getSelectedItem(); if (event.getId() == "add") { if (!item) return; + if (mMyInventory->getFreeSlot() < 1) + return; + if (mMyInventory->contains(item)) { chatWindow->chatLog("Failed adding item. You can not " "overlap one kind of item on the window.", BY_SERVER); return; } - if (item->getQuantity() == 1) { + if (item->getQuantity() == 1) + { tradeItem(item, 1); } - else { + else + { // Choose amount of items to trade new ItemAmountWindow(AMOUNT_TRADE_ADD, this, item); } +#ifdef TMWSERV_SUPPORT setStatus(PREPARING); +#endif } else if (event.getId() == "cancel") { setVisible(false); reset(); player_node->setTrading(false); +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::acceptTrade(false); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_CANCEL_REQUEST); +#endif + } +#ifdef EATHENA_SUPPORT + else if (event.getId() == "ok") + { + std::stringstream tempMoney(mMoneyField->getText()); + int tempInt; + if (tempMoney >> tempInt) + { + mMoneyField->setText(toString(tempInt)); + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_ITEM_ADD_REQUEST); + outMsg.writeInt16(0); + outMsg.writeInt32(tempInt); + } + else + { + mMoneyField->setText(""); + } + mMoneyField->setEnabled(false); + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_ADD_COMPLETE); } +#endif else if (event.getId() == "trade") { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::acceptTrade(true); setStatus(PROPOSING); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_OK); +#endif } +#ifdef TMWSERV_SUPPORT else if (event.getId() == "money") { int v = atoi(mMoneyField->getText().c_str()); @@ -225,4 +370,5 @@ void TradeWindow::action(const gcn::ActionEvent &event) mMoneyField->setText(strprintf("%d", v)); setStatus(PREPARING); } +#endif } diff --git a/src/gui/trade.h b/src/gui/trade.h index c51e0fdd..bde0481c 100644 --- a/src/gui/trade.h +++ b/src/gui/trade.h @@ -1,26 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_TRADE_H -#define _TMW_TRADE_H +#ifndef TRADE_H +#define TRADE_H + +#include <memory> #include <guichan/actionlistener.hpp> #include <guichan/selectionlistener.hpp> @@ -32,6 +34,9 @@ class Inventory; class Item; class ItemContainer; +#ifdef EATHENA_SUPPORT +class Network; +#endif class ScrollArea; /** @@ -45,7 +50,11 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener /** * Constructor. */ +#ifdef TMWSERV_SUPPORT TradeWindow(); +#else + TradeWindow(Network *network); +#endif /** * Destructor. @@ -67,16 +76,41 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener */ void reset(); +#ifdef EATHENA_SUPPORT + /** + * Add an item to the trade window. + */ + void addItem(int id, bool own, int quantity, bool equipment); + + /** + * Change quantity of an item. + */ + void changeQuantity(int index, bool own, int quantity); + + /** + * Increase quantity of an item. + */ + void increaseQuantity(int index, bool own, int quantity); + + /** + * Set trade Button disabled + */ + void setTradeButton(bool enabled); +#endif + /** * Player received ok message from server */ +#ifdef TMWSERV_SUPPORT void receivedOk(); +#else + void receivedOk(bool own); +#endif /** * Send trade packet. */ - void - tradeItem(Item *item, int quantity); + void tradeItem(Item *item, int quantity); /** * Updates the labels and makes sure only one item is selected in @@ -90,6 +124,7 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener void action(const gcn::ActionEvent &event); private: +#ifdef TMWSERV_SUPPORT enum Status { PREPARING, /**< Players are adding items. */ @@ -101,20 +136,31 @@ class TradeWindow : public Window, gcn::ActionListener, gcn::SelectionListener * Sets the current status of the trade. */ void setStatus(Status); +#endif + +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif - Inventory *mMyInventory; - Inventory *mPartnerInventory; + typedef const std::auto_ptr<Inventory> InventoryPtr; + InventoryPtr mMyInventory; + InventoryPtr mPartnerInventory; ItemContainer *mMyItemContainer; ItemContainer *mPartnerItemContainer; - gcn::Label *mItemNameLabel; - gcn::Label *mItemDescriptionLabel; gcn::Label *mMoneyLabel; gcn::Button *mTradeButton; +#ifdef EATHENA_SUPPORT + gcn::Button *mOkButton; +#endif gcn::TextField *mMoneyField; +#ifdef TMWSERV_SUPPORT Status mStatus; +#else + bool mOkOther, mOkMe; +#endif }; extern TradeWindow *tradeWindow; diff --git a/src/gui/truetypefont.cpp b/src/gui/truetypefont.cpp index 1132c3b5..7c72e2f5 100644 --- a/src/gui/truetypefont.cpp +++ b/src/gui/truetypefont.cpp @@ -1,30 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "truetypefont.h" - -#include <list> - #include <guichan/exception.hpp> +#include "truetypefont.h" + #include "../graphics.h" #include "../resources/image.h" @@ -45,8 +43,7 @@ class TextChunk bool operator==(const TextChunk &chunk) const { - return ( - chunk.text == text && chunk.color == color); + return (chunk.text == text && chunk.color == color); } void generate(TTF_Font *font) @@ -75,14 +72,11 @@ class TextChunk gcn::Color color; }; - -// Word surfaces cache -static std::list<TextChunk> cache; typedef std::list<TextChunk>::iterator CacheIterator; static int fontCounter; -TrueTypeFont::TrueTypeFont(const std::string& filename, int size) +TrueTypeFont::TrueTypeFont(const std::string &filename, int size) { if (fontCounter == 0 && TTF_Init() == -1) { @@ -93,7 +87,7 @@ TrueTypeFont::TrueTypeFont(const std::string& filename, int size) ++fontCounter; mFont = TTF_OpenFont(filename.c_str(), size); - if (mFont == NULL) + if (!mFont) { throw GCN_EXCEPTION("SDLTrueTypeFont::SDLTrueTypeFont: " + std::string(TTF_GetError())); @@ -112,13 +106,11 @@ TrueTypeFont::~TrueTypeFont() } void TrueTypeFont::drawString(gcn::Graphics *graphics, - const std::string &text, - int x, int y) + const std::string &text, + int x, int y) { if (text.empty()) - { return; - } Graphics *g = dynamic_cast<Graphics *>(graphics); @@ -139,12 +131,12 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, bool found = false; - for (CacheIterator i = cache.begin(); i != cache.end(); i++) + for (CacheIterator i = mCache.begin(); i != mCache.end(); ++i) { if (chunk == (*i)) { // Raise priority: move it to front - cache.splice(cache.begin(), cache, i); + mCache.splice(mCache.begin(), mCache, i); found = true; break; } @@ -153,19 +145,19 @@ void TrueTypeFont::drawString(gcn::Graphics *graphics, // Surface not found if (!found) { - if (cache.size() >= CACHE_SIZE) + if (mCache.size() >= CACHE_SIZE) { - cache.pop_back(); + mCache.pop_back(); } - cache.push_front(chunk); - cache.front().generate(mFont); + mCache.push_front(chunk); + mCache.front().generate(mFont); } - cache.front().img->setAlpha(alpha); - g->drawImage(cache.front().img, x, y); + mCache.front().img->setAlpha(alpha); + g->drawImage(mCache.front().img, x, y); } -int TrueTypeFont::getWidth(const std::string& text) const +int TrueTypeFont::getWidth(const std::string &text) const { int w, h; TTF_SizeUTF8(mFont, text.c_str(), &w, &h); diff --git a/src/gui/truetypefont.h b/src/gui/truetypefont.h index 3b39329e..71b45fd1 100644 --- a/src/gui/truetypefont.h +++ b/src/gui/truetypefont.h @@ -1,37 +1,39 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_TRUETYPEFONT_H -#define _TMW_TRUETYPEFONT_H +#ifndef TRUETYPEFONT_H +#define TRUETYPEFONT_H +#include <list> #include <string> #include <guichan/font.hpp> -#include <guichan/graphics.hpp> -#ifdef __APPLE__ -#include <SDL_ttf/SDL_ttf.h> -#else +#ifndef __APPLE__ #include <SDL/SDL_ttf.h> +#else +#include <SDL_ttf.h> #endif +class TextChunk; + /** * A wrapper around SDL_ttf for allowing the use of TrueType fonts. * @@ -46,7 +48,7 @@ class TrueTypeFont : public gcn::Font * @param filename Font filename. * @param size Font size. */ - TrueTypeFont(const std::string& filename, int size); + TrueTypeFont(const std::string &filename, int size); /** * Destructor. @@ -60,10 +62,15 @@ class TrueTypeFont : public gcn::Font /** * @see Font::drawString */ - void drawString(gcn::Graphics* graphics, const std::string& text, int x, int y); + void drawString(gcn::Graphics *graphics, + const std::string &text, + int x, int y); private: TTF_Font *mFont; + + // Word surfaces cache + std::list<TextChunk> mCache; }; #endif diff --git a/src/gui/unregisterdialog.h b/src/gui/unregisterdialog.h index 4056d251..1e3cc88f 100644 --- a/src/gui/unregisterdialog.h +++ b/src/gui/unregisterdialog.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_UNREGISTERDIALOG_H -#define _TMW_UNREGISTERDIALOG_H +#ifndef UNREGISTERDIALOG_H +#define UNREGISTERDIALOG_H #include <iosfwd> #include <guichan/actionlistener.hpp> diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index 997a9b82..ca41dbda 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -1,26 +1,24 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "updatewindow.h" - #include <iostream> #include <SDL.h> #include <SDL_thread.h> @@ -28,22 +26,26 @@ #include <guichan/widgets/label.hpp> +// Curl should be included after Guichan to avoid Windows redefinitions +#include <curl/curl.h> + #include "browserbox.h" #include "button.h" #include "progressbar.h" #include "scrollarea.h" +#include "updatewindow.h" -// Curl should be included after Guichan to avoid Windows redefinitions -#include <curl/curl.h> +#include "widgets/layout.h" #include "../configuration.h" #include "../log.h" #include "../main.h" -#include "../utils/tostring.h" - #include "../resources/resourcemanager.h" +#include "../utils/gettext.h" +#include "../utils/stringutils.h" + /** * Calculates the Alder-32 checksum for the given file. */ @@ -67,8 +69,7 @@ static unsigned long fadler32(FILE *file) /** * Load the given file into a vector of strings. */ -std::vector<std::string> -loadTextFile(const std::string &fileName) +std::vector<std::string> loadTextFile(const std::string &fileName) { std::vector<std::string> lines; std::ifstream fin(fileName.c_str()); @@ -89,7 +90,7 @@ loadTextFile(const std::string &fileName) UpdaterWindow::UpdaterWindow(const std::string &updateHost, const std::string &updatesDir): - Window("Updating..."), + Window(_("Updating...")), mThread(NULL), mDownloadStatus(UPDATE_NEWS), mUpdateHost(updateHost), @@ -106,34 +107,29 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost, { mCurlError[0] = 0; - const int h = 240; - const int w = 320; - setContentSize(w, h); - - mBrowserBox = new BrowserBox(); + mBrowserBox = new BrowserBox; mScrollArea = new ScrollArea(mBrowserBox); - mLabel = new gcn::Label("Connecting..."); - mProgressBar = new ProgressBar(0.0, w - 10, 20, 37, 70, 200); - mCancelButton = new Button("Cancel", "cancel", this); - mPlayButton = new Button("Play", "play", this); + mLabel = new gcn::Label(_("Connecting...")); + mProgressBar = new ProgressBar(0.0, 310, 20, 168, 116, 31); + mCancelButton = new Button(_("Cancel"), "cancel", this); + mPlayButton = new Button(_("Play"), "play", this); mBrowserBox->setOpaque(false); mPlayButton->setEnabled(false); - mCancelButton->setPosition(5, h - 5 - mCancelButton->getHeight()); - mPlayButton->setPosition( - mCancelButton->getX() + mCancelButton->getWidth() + 5, - h - 5 - mPlayButton->getHeight()); - mProgressBar->setPosition(5, mCancelButton->getY() - 20 - 5); - mLabel->setPosition(5, mProgressBar->getY() - mLabel->getHeight() - 5); + ContainerPlacer place; + place = getPlacer(0, 0); + + place(0, 0, mScrollArea, 5, 3).setPadding(3); + place(0, 3, mLabel, 5); + place(0, 4, mProgressBar, 5); + place(3, 5, mCancelButton); + place(4, 5, mPlayButton); - mScrollArea->setDimension(gcn::Rectangle(5, 5, 310, mLabel->getY() - 12)); + reflowLayout(320, 240); - add(mScrollArea); - add(mLabel); - add(mProgressBar); - add(mCancelButton); - add(mPlayButton); + Layout &layout = getLayout(); + layout.setRowHeight(0, Layout::AUTO_SET); setLocationRelativeTo(getParent()); setVisible(true); @@ -209,7 +205,7 @@ void UpdaterWindow::loadNews() // Tokenize and add each line separately char *line = strtok(mMemoryBuffer, "\n"); - while (line != NULL) + while (line) { mBrowserBox->addRow(line); line = strtok(NULL, "\n"); @@ -228,8 +224,9 @@ int UpdaterWindow::updateProgress(void *ptr, float progress = dn / dt; UpdaterWindow *uw = reinterpret_cast<UpdaterWindow *>(ptr); - if (progress < 0) progress = 0.0f; - if (progress > 1) progress = 1.0f; + if (progress != progress) progress = 0.0f; // check for NaN + if (progress < 0.0f) progress = 0.0f; // no idea how this could ever happen, but why not check for it anyway. + if (progress > 1.0f) progress = 1.0f; uw->setLabel( uw->mCurrentFile + " (" + toString((int) (progress * 100)) + "%)"); @@ -244,8 +241,7 @@ int UpdaterWindow::updateProgress(void *ptr, return 0; } -size_t -UpdaterWindow::memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream) +size_t UpdaterWindow::memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream) { UpdaterWindow *uw = reinterpret_cast<UpdaterWindow *>(stream); size_t totalMem = size * nmemb; @@ -328,8 +324,8 @@ int UpdaterWindow::downloadThread(void *ptr) { case CURLE_COULDNT_CONNECT: default: - std::cerr << "curl error " << res << ": " - << uw->mCurlError << " host: " << url.c_str() + std::cerr << _("curl error ") << res << ": " + << uw->mCurlError << _(" host: ") << url.c_str() << std::endl; break; } @@ -412,7 +408,7 @@ void UpdaterWindow::download() mDownloadComplete = false; mThread = SDL_CreateThread(UpdaterWindow::downloadThread, this); - if (mThread == NULL) + if (!mThread) { logger->log("Unable to create mThread"); mDownloadStatus = UPDATE_ERROR; @@ -452,9 +448,9 @@ void UpdaterWindow::logic() mThread = NULL; } mBrowserBox->addRow(""); - mBrowserBox->addRow("##1 The update process is incomplete."); - mBrowserBox->addRow("##1 It is strongly recommended that"); - mBrowserBox->addRow("##1 you try again later"); + mBrowserBox->addRow(_("##1 The update process is incomplete.")); + mBrowserBox->addRow(_("##1 It is strongly recommended that")); + mBrowserBox->addRow(_("##1 you try again later")); mBrowserBox->addRow(mCurlError); mScrollArea->setVerticalScrollAmount( mScrollArea->getVerticalMaxScroll()); @@ -521,7 +517,7 @@ void UpdaterWindow::logic() break; case UPDATE_COMPLETE: enable(); - setLabel("Completed"); + setLabel(_("Completed")); break; case UPDATE_IDLE: break; diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h index a7dfe2cb..ace398b4 100644 --- a/src/gui/updatewindow.h +++ b/src/gui/updatewindow.h @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -23,12 +23,13 @@ #define _UPDATERWINDOW_H #include <guichan/actionlistener.hpp> + #include <string> #include <vector> #include "window.h" -#include "../guichanfwd.h" +#include "../utils/mutex.h" #include "../utils/mutex.h" diff --git a/src/gui/vbox.cpp b/src/gui/vbox.cpp deleted file mode 100644 index 2ec1112d..00000000 --- a/src/gui/vbox.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 "vbox.h" - -void VBox::draw(gcn::Graphics *graphics) -{ - if (mWidgets.empty()) - { - return; - } - - int childWidth = getWidth(); - int childHeight = getHeight() / mWidgets.size(); - int i = 0; - - for (WidgetIterator w = mWidgets.begin(); w != mWidgets.end(); w++) - { - (*w)->setPosition(0, childHeight * i - padding); - (*w)->setSize(childWidth, childHeight); - i++; - } - - gcn::Container::draw(graphics); -} diff --git a/src/gui/viewport.cpp b/src/gui/viewport.cpp index a746fb03..cbd1f3f7 100644 --- a/src/gui/viewport.cpp +++ b/src/gui/viewport.cpp @@ -1,62 +1,61 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "viewport.h" - -#include <guichan/sdl/sdlinput.hpp> - -#include "gui.h" +#include "ministatus.h" #include "popupmenu.h" +#include "viewport.h" -#include "../simpleanimation.h" #include "../beingmanager.h" #include "../configuration.h" #include "../flooritemmanager.h" +#include "../game.h" #include "../graphics.h" +#include "../keyboardconfig.h" #include "../localplayer.h" #include "../map.h" #include "../monster.h" #include "../npc.h" +#include "../textmanager.h" -#include "../resources/animation.h" #include "../resources/monsterinfo.h" #include "../resources/resourcemanager.h" -#include "../resources/image.h" -#include "../resources/imageset.h" - -#include "../utils/tostring.h" -#include <cassert> +#include "../utils/stringutils.h" extern volatile int tick_time; -extern int get_elapsed_time(int start_time); Viewport::Viewport(): mMap(0), - mViewX(0.0f), - mViewY(0.0f), + mPixelViewX(0.0f), + mPixelViewY(0.0f), + mTileViewX(0), + mTileViewY(0), mShowDebugPath(false), mVisibleNames(false), mPlayerFollowMouse(false), +#ifdef TMWSERV_SUPPORT mLocalWalkTime(-1) +#else + mWalkTime(0) +#endif { setOpaque(false); addMouseListener(this); @@ -71,52 +70,7 @@ Viewport::Viewport(): config.addListener("ScrollRadius", this); config.addListener("visiblenames", 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(const std::string &filename, - int width, int height, - bool outRange, Being::TargetCursorSize size) -{ - assert(size >= Being::TC_SMALL); - assert(size < Being::NUM_TC); - - 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; - } + mPopupMenu = new PopupMenu; } Viewport::~Viewport() @@ -124,14 +78,6 @@ Viewport::~Viewport() delete mPopupMenu; config.removeListener("visiblenames", this); - - for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) - { - delete mTargetCursorInRange[i]; - delete mTargetCursorOutRange[i]; - mInRangeImages[i]->decRef(); - mOutRangeImages[i]->decRef(); - } } void Viewport::setMap(Map *map) @@ -139,6 +85,8 @@ void Viewport::setMap(Map *map) mMap = map; } +extern MiniStatusWindow *miniStatusWindow; + void Viewport::draw(gcn::Graphics *gcnGraphics) { static int lastTick = tick_time; @@ -148,6 +96,10 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) Graphics *graphics = static_cast<Graphics*>(gcnGraphics); + // Ensure the client doesn't freak out if a feature localplayer uses + // is dependent on a map. + player_node->mMapInitialized = true; + // Avoid freaking out when tick_time overflows if (tick_time < lastTick) { @@ -155,12 +107,22 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) } // Calculate viewpoint +#ifdef TMWSERV_SUPPORT int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 2; int midTileY = (graphics->getHeight() + mScrollCenterOffsetX) / 2; const Vector &playerPos = player_node->getPosition(); const int player_x = (int) playerPos.x - midTileX; const int player_y = (int) playerPos.y - midTileY; +#else + int midTileX = (graphics->getWidth() + mScrollCenterOffsetX) / 32 / 2; + int midTileY = (graphics->getHeight() + mScrollCenterOffsetY) / 32 / 2; + + int player_x = (player_node->mX - midTileX) * 32 + + player_node->getXOffset(); + int player_y = (player_node->mY - midTileY) * 32 + + player_node->getYOffset(); +#endif if (mScrollLaziness < 1) mScrollLaziness = 1; // Avoids division by zero @@ -168,34 +130,34 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) // Apply lazy scrolling while (lastTick < tick_time) { - if (player_x > mViewX + mScrollRadius) + if (player_x > mPixelViewX + mScrollRadius) { - mViewX += (player_x - mViewX - mScrollRadius) / mScrollLaziness; + mPixelViewX += (player_x - mPixelViewX - mScrollRadius) / mScrollLaziness; } - if (player_x < mViewX - mScrollRadius) + if (player_x < mPixelViewX - mScrollRadius) { - mViewX += (player_x - mViewX + mScrollRadius) / mScrollLaziness; + mPixelViewX += (player_x - mPixelViewX + mScrollRadius) / mScrollLaziness; } - if (player_y > mViewY + mScrollRadius) + if (player_y > mPixelViewY + mScrollRadius) { - mViewY += (player_y - mViewY - mScrollRadius) / mScrollLaziness; + mPixelViewY += (player_y - mPixelViewY - mScrollRadius) / mScrollLaziness; } - if (player_y < mViewY - mScrollRadius) + if (player_y < mPixelViewY - mScrollRadius) { - mViewY += (player_y - mViewY + mScrollRadius) / mScrollLaziness; + mPixelViewY += (player_y - mPixelViewY + mScrollRadius) / mScrollLaziness; } lastTick++; } // Auto center when player is off screen - if ( player_x - mViewX > graphics->getWidth() / 2 - || mViewX - player_x > graphics->getWidth() / 2 - || mViewY - player_y > graphics->getHeight() / 2 - || player_y - mViewY > graphics->getHeight() / 2 + if ( player_x - mPixelViewX > graphics->getWidth() / 2 + || mPixelViewX - player_x > graphics->getWidth() / 2 + || mPixelViewY - player_y > graphics->getHeight() / 2 + || player_y - mPixelViewY > graphics->getHeight() / 2 ) { - mViewX = player_x; - mViewY = player_y; + mPixelViewX = player_x; + mPixelViewY = player_y; }; // Don't move camera so that the end of the map is on screen @@ -205,49 +167,62 @@ void Viewport::draw(gcn::Graphics *gcnGraphics) mMap->getHeight() * mMap->getTileHeight() - graphics->getHeight(); if (mMap) { - if (mViewX < 0) { - mViewX = 0; + if (mPixelViewX < 0) { + mPixelViewX = 0; } - if (mViewY < 0) { - mViewY = 0; + if (mPixelViewY < 0) { + mPixelViewY = 0; } - if (mViewX > viewXmax) { - mViewX = viewXmax; + if (mPixelViewX > viewXmax) { + mPixelViewX = viewXmax; } - if (mViewY > viewYmax) { - mViewY = viewYmax; + if (mPixelViewY > viewYmax) { + mPixelViewY = viewYmax; } } + mTileViewX = (int) (mPixelViewX + 16) / 32; + mTileViewY = (int) (mPixelViewY + 16) / 32; + // Draw tiles and sprites if (mMap) { - mMap->draw(graphics, (int) mViewX, (int) mViewY); - drawTargetCursor(graphics); // TODO: Draw the cursor with the sprite - drawTargetName(graphics); + mMap->draw(graphics, (int) mPixelViewX, (int) mPixelViewY); + if (mShowDebugPath) { - mMap->drawCollision(graphics, (int) mViewX, (int) mViewY); + mMap->drawCollision(graphics, + (int) mPixelViewX, + (int) mPixelViewY); #if 0 drawDebugPath(graphics); #endif } } + if (player_node->mUpdateName) + { + player_node->mUpdateName = false; + player_node->setName(player_node->getName()); + } + + + // Draw text + if (textManager) + { + textManager->draw(graphics, (int) mPixelViewX, (int) mPixelViewY); + } + // Draw player names, speech, and emotion sprite as needed Beings &beings = beingManager->getAll(); for (BeingIterator i = beings.begin(); i != beings.end(); i++) { - (*i)->drawSpeech(graphics, -(int) mViewX, -(int) mViewY); - if (mVisibleNames) - (*i)->drawName(graphics, -(int) mViewX, -(int) mViewY); - else if ((*i) == mSelectedBeing) - (*i)->drawName(graphics, -(int) mViewX, -(int) mViewY); - (*i)->drawEmotion(graphics, -(int) mViewX, -(int) mViewY); - - if (mShowDebugPath && !(*i)->getPath().empty()) - drawPath(graphics, (*i)->getPath()); + (*i)->drawSpeech(-(int) mPixelViewX, -(int) mPixelViewY); + (*i)->drawEmotion(graphics, -(int) mPixelViewX, -(int) mPixelViewY); } + if (miniStatusWindow) + miniStatusWindow->drawIcons(graphics); + // Draw contained widgets WindowContainer::draw(gcnGraphics); } @@ -263,67 +238,19 @@ void Viewport::logic() Uint8 button = SDL_GetMouseState(&mouseX, &mouseY); if (mPlayerFollowMouse && button & SDL_BUTTON(1) && +#ifdef TMWSERV_SUPPORT get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay) { mLocalWalkTime = tick_time; - player_node->setDestination(mouseX + (int) mViewX, - mouseY + (int) mViewY); - } - - for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) + player_node->setDestination(mouseX + (int) mPixelViewX, + mouseY + (int) mPixelViewY); +#else + mWalkTime != player_node->mWalkTime) { - 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 - const Vector &dist = - target->getPosition() - player_node->getPosition(); - const int rangeX = abs((int) dist.x); - const int rangeY = abs((int) dist.y); - const 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() - - targetCursor->getWidth() / 2 - (int) mViewX; - int posY = target->getPixelY() - 16 - - targetCursor->getHeight() / 2 - (int) mViewY; - - graphics->drawImage(targetCursor, posX, posY); - } -} - -void Viewport::drawTargetName(Graphics *graphics) -{ - // Draw target marker if needed - Being *target = player_node->getTarget(); - if (target && target->getType() == Being::MONSTER) - { - graphics->setFont(speechFont); - graphics->setColor(gcn::Color(255, 32, 32)); - - const MonsterInfo &mi = static_cast<Monster*>(target)->getInfo(); - int posX = target->getPixelX() - (int) mViewX; - int posY = target->getPixelY() + 16 - target->getHeight() - (int) mViewY; - - graphics->drawText(mi.getName(), posX, posY, gcn::Graphics::CENTER); + player_node->setDestination(mouseX / 32 + mTileViewX, + mouseY / 32 + mTileViewY); + mWalkTime = player_node->mWalkTime; +#endif } } @@ -333,8 +260,8 @@ void Viewport::drawDebugPath(Graphics *graphics) int mouseX, mouseY; SDL_GetMouseState(&mouseX, &mouseY); - const int mouseTileX = (mouseX + (int) mViewX) / 32; - const int mouseTileY = (mouseY + (int) mViewY) / 32; + const int mouseTileX = (mouseX + (int) mPixelViewX) / 32; + const int mouseTileY = (mouseY + (int) mPixelViewY) / 32; const Vector &playerPos = player_node->getPosition(); Path debugPath = mMap->findPath( @@ -350,8 +277,8 @@ void Viewport::drawPath(Graphics *graphics, const Path &path) graphics->setColor(gcn::Color(255, 0, 0)); for (Path::const_iterator i = path.begin(); i != path.end(); ++i) { - int squareX = i->x * 32 - (int) mViewX + 12; - int squareY = i->y * 32 - (int) mViewY + 12; + 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( @@ -366,10 +293,14 @@ void Viewport::mousePressed(gcn::MouseEvent &event) if (!mMap || !player_node || player_node->mAction == Being::DEAD) return; + // Check if we are busy + if (current_npc) + return; + mPlayerFollowMouse = false; - const int pixelx = event.getX() + (int) mViewX; - const int pixely = event.getY() + (int) mViewY; + const int pixelx = event.getX() + (int) mPixelViewX; + const int pixely = event.getY() + (int) mPixelViewY; const int tilex = pixelx / mMap->getTileWidth(); const int tiley = pixely / mMap->getTileHeight(); @@ -380,12 +311,13 @@ void Viewport::mousePressed(gcn::MouseEvent &event) FloorItem *floorItem; if ((being = beingManager->findBeingByPixel(pixelx, pixely)) && - being != player_node) + being != player_node) { - mPopupMenu->showPopup(event.getX(), event.getY(), being); - return; + mPopupMenu->showPopup(event.getX(), event.getY(), being); + return; } - else if((floorItem = floorItemManager->findByCoordinates(tilex, tiley))) + else if ((floorItem = floorItemManager->findByCoordinates(tilex, + tiley))) { mPopupMenu->showPopup(event.getX(), event.getY(), floorItem); return; @@ -403,24 +335,63 @@ void Viewport::mousePressed(gcn::MouseEvent &event) if (event.getButton() == gcn::MouseEvent::LEFT) { FloorItem *item; +#ifdef EATHENA_SUPPORT + Being *being; + // Interact with some being +// if ((being = beingManager->findBeing(tilex, tiley))) + if ((being = beingManager->findBeingByPixel(pixelx, pixely))) + { + switch (being->getType()) + { + case Being::NPC: + dynamic_cast<NPC*>(being)->talk(); + break; + + case Being::MONSTER: + case Being::PLAYER: + if (being->mAction == Being::DEAD) + break; + + if (player_node->withinAttackRange(being) || keyboard.isKeyActive(keyboard.KEY_ATTACK)) + { + player_node->setGotoTarget(being); + player_node->attack(being, !keyboard.isKeyActive(keyboard.KEY_TARGET)); + } + else + { + player_node->setDestination(tilex, tiley); + } + break; + + default: + break; + } + } // Pick up some item + else +#endif if ((item = floorItemManager->findByCoordinates(tilex, tiley))) { - player_node->pickUp(item); + player_node->pickUp(item); } // Just walk around else { +#ifdef TMWSERV_SUPPORT // FIXME: REALLY UGLY! Uint8 *keys = SDL_GetKeyState(NULL); if (!(keys[SDLK_LSHIFT] || keys[SDLK_RSHIFT]) && get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay) { mLocalWalkTime = tick_time; - player_node->setDestination(event.getX() + (int) mViewX, - event.getY() + (int) mViewY); + player_node->setDestination(event.getX() + (int) mPixelViewX, + event.getY() + (int) mPixelViewY); } +#else + player_node->stopAttack(); + player_node->setDestination(tilex, tiley); +#endif mPlayerFollowMouse = true; } } @@ -443,13 +414,22 @@ void Viewport::mouseDragged(gcn::MouseEvent &event) if (!mMap || !player_node) return; +#ifdef TMWSERV_SUPPORT if (mPlayerFollowMouse && get_elapsed_time(mLocalWalkTime) >= walkingMouseDelay) { mLocalWalkTime = tick_time; - player_node->setDestination(event.getX() + (int) mViewX, - event.getY() + (int) mViewY); + player_node->setDestination(event.getX() + (int) mPixelViewX, + event.getY() + (int) mPixelViewY); } +#else + if (mPlayerFollowMouse && mWalkTime == player_node->mWalkTime) + { + int destX = event.getX() / 32 + mTileViewX; + int destY = event.getY() / 32 + mTileViewY; + player_node->setDestination(destX, destY); + } +#endif } void Viewport::mouseReleased(gcn::MouseEvent &event) @@ -478,9 +458,8 @@ void Viewport::mouseMoved(gcn::MouseEvent &event) if (!mMap || !player_node) return; - const int tilex = (event.getX() + (int) mViewX) / 32; - const int tiley = (event.getY() + (int) mViewY) / 32; + const int tilex = (event.getX() + (int) mPixelViewX) / 32; + const int tiley = (event.getY() + (int) mPixelViewY) / 32; mSelectedBeing = beingManager->findBeing(tilex, tiley); } - diff --git a/src/gui/viewport.h b/src/gui/viewport.h index dd17fa24..a097a4ac 100644 --- a/src/gui/viewport.h +++ b/src/gui/viewport.h @@ -1,41 +1,41 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_VIEWPORT_H_ -#define _TMW_VIEWPORT_H_ +#ifndef VIEWPORT_H +#define VIEWPORT_H #include <guichan/mouselistener.hpp> #include "windowcontainer.h" #include "../configlistener.h" -#include "../being.h" +#include "../position.h" -class Map; +class Being; class FloorItem; +class Graphics; class ImageSet; class Item; +class Map; class PopupMenu; -class Graphics; -class SimpleAnimation; /** Delay between two mouse calls when dragging mouse and move the player */ const int walkingMouseDelay = 500; @@ -65,101 +65,71 @@ class Viewport : public WindowContainer, public gcn::MouseListener, /** * Sets the map displayed by the viewport. */ - void - setMap(Map *map); + void setMap(Map *map); /** * Draws the viewport. */ - void - draw(gcn::Graphics *graphics); + void draw(gcn::Graphics *graphics); /** * Implements player to keep following mouse. */ - void - logic(); + void logic(); /** * Toggles whether the path debug graphics are shown */ - void - toggleDebugPath() { mShowDebugPath = !mShowDebugPath; } + void toggleDebugPath() { mShowDebugPath = !mShowDebugPath; } /** * Handles mouse press on map. */ - void - mousePressed(gcn::MouseEvent &event); + void mousePressed(gcn::MouseEvent &event); /** * Handles mouse move on map */ - void - mouseDragged(gcn::MouseEvent &event); + void mouseDragged(gcn::MouseEvent &event); /** * Handles mouse button release on map. */ - void - mouseReleased(gcn::MouseEvent &event); + void mouseReleased(gcn::MouseEvent &event); /** * Handles mouse move on map. */ - void - mouseMoved(gcn::MouseEvent &event); + void mouseMoved(gcn::MouseEvent &event); /** * Shows a popup for an item. * TODO Find some way to get rid of Item here */ - void - showPopup(int x, int y, Item *item); + void showPopup(int x, int y, Item *item); /** * A relevant config option changed. */ - void - optionChanged(const std::string &name); + void optionChanged(const std::string &name); /** * Returns camera x offset in pixels. */ - int - getCameraX() const { return (int) mViewX; } + int getCameraX() const { return (int) mPixelViewX; } /** * Returns camera y offset in pixels. */ - int - getCameraY() const { return (int) mViewY; } + int getCameraY() const { return (int) mPixelViewY; } /** * Changes viewpoint by relative pixel coordinates. */ - void - scrollBy(float x, float y) { mViewX += x; mViewY += y; } + void scrollBy(float x, float y) { mPixelViewX += x; mPixelViewY += y; } private: /** - * Helper function for loading target cursors. - */ - void loadTargetCursor(const 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); - - /** * Finds a path from the player to the mouse, and draws it. This is for * debug purposes. */ @@ -170,35 +140,31 @@ class Viewport : public WindowContainer, public gcn::MouseListener, */ void drawPath(Graphics *graphics, const Path &path); - Map *mMap; /**< The current map. */ int mScrollRadius; int mScrollLaziness; int mScrollCenterOffsetX; int mScrollCenterOffsetY; - float mViewX; /**< Current viewpoint in pixels. */ - float mViewY; /**< Current viewpoint in pixels. */ + float mPixelViewX; /**< Current viewpoint in pixels. */ + float mPixelViewY; /**< Current viewpoint in pixels. */ + int mTileViewX; /**< Current viewpoint in tiles. */ + int mTileViewY; /**< Current viewpoint in tiles. */ bool mShowDebugPath; /**< Show a path from player to pointer. */ bool mVisibleNames; /**< Show target names. */ - /** 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; +#ifdef TMWSERV_SUPPORT int mLocalWalkTime; /**< Timestamp before the next walk can be sent. */ +#else + int mWalkTime; +#endif PopupMenu *mPopupMenu; /**< Popup menu. */ Being *mSelectedBeing; /**< Current selected being. */ + }; +extern Viewport *viewport; /**< The viewport */ + #endif diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp index d4c2bc4b..92837603 100644 --- a/src/gui/widgets/dropdown.cpp +++ b/src/gui/widgets/dropdown.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -23,6 +23,11 @@ #include "dropdown.h" +#include "../color.h" +#include "../listbox.h" +#include "../scrollarea.h" + +#include "../../configuration.h" #include "../../graphics.h" #include "../../resources/image.h" @@ -33,12 +38,12 @@ int DropDown::instances = 0; Image *DropDown::buttons[2][2]; ImageRect DropDown::skin; +float DropDown::mAlpha = config.getValue("guialpha", 0.8); -DropDown::DropDown(gcn::ListModel *listModel, - gcn::ScrollArea *scrollArea, - gcn::ListBox *listBox): - gcn::DropDown::DropDown(listModel, - scrollArea, listBox) +DropDown::DropDown(gcn::ListModel *listModel, gcn::ScrollArea *scrollArea, + gcn::ListBox *listBox, bool opacity): + gcn::DropDown::DropDown(listModel, scrollArea, listBox), + mOpaque(opacity) { setFrameSize(2); @@ -58,6 +63,11 @@ DropDown::DropDown(gcn::ListModel *listModel, buttons[0][1] = resman->getImage("graphics/gui/vscroll_down_pressed.png"); + buttons[0][0]->setAlpha(mAlpha); + buttons[0][1]->setAlpha(mAlpha); + buttons[1][0]->setAlpha(mAlpha); + buttons[1][1]->setAlpha(mAlpha); + // get the border skin Image *boxBorder = resman->getImage("graphics/gui/deepbox.png"); int gridx[4] = {0, 3, 28, 31}; @@ -70,6 +80,7 @@ DropDown::DropDown(gcn::ListModel *listModel, gridx[x], gridy[y], gridx[x + 1] - gridx[x] + 1, gridy[y + 1] - gridy[y] + 1); + skin.grid[a]->setAlpha(mAlpha); a++; } } @@ -108,19 +119,44 @@ void DropDown::draw(gcn::Graphics* graphics) h = getHeight(); } - int alpha = getBaseColor().a; + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + + buttons[0][0]->setAlpha(mAlpha); + buttons[0][1]->setAlpha(mAlpha); + buttons[1][0]->setAlpha(mAlpha); + buttons[1][1]->setAlpha(mAlpha); + + for (int a = 0; a < 9; a++) + { + skin.grid[a]->setAlpha(mAlpha); + } + } + + bool valid; + const int alpha = (int)(mAlpha * 255.0f); gcn::Color faceColor = getBaseColor(); faceColor.a = alpha; - gcn::Color highlightColor = faceColor + 0x303030; + gcn::Color highlightColor = textColor->getColor('H', valid); highlightColor.a = alpha; gcn::Color shadowColor = faceColor - 0x303030; shadowColor.a = alpha; + if (mOpaque) + { + int red = getBackgroundColor().r; + int green = getBackgroundColor().g; + int blue = getBackgroundColor().b; + graphics->setColor(gcn::Color(red, green, blue, alpha)); + graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h)); + + red = getForegroundColor().r; + green = getForegroundColor().g; + blue = getForegroundColor().b; + graphics->setColor(gcn::Color(red, green, blue, alpha)); + } - graphics->setColor(getBackgroundColor()); - graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), h)); - - graphics->setColor(getForegroundColor()); graphics->setFont(getFont()); if (mListBox->getListModel() && mListBox->getSelected() >= 0) @@ -140,7 +176,7 @@ void DropDown::draw(gcn::Graphics* graphics) { drawChildren(graphics); - // Draw two lines separating the ListBox with se selected + // Draw two lines separating the ListBox with selected // element view. graphics->setColor(highlightColor); graphics->drawLine(0, h, getWidth(), h); @@ -163,5 +199,5 @@ void DropDown::drawButton(gcn::Graphics *graphics) int height = mDroppedDown ? mFoldedUpHeight : getHeight(); static_cast<Graphics*>(graphics)-> - drawImage(buttons[mDroppedDown][mPushed], getWidth() - height, 1); + drawImage(buttons[mDroppedDown][mPushed], getWidth() - height + 2, 1); } diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h index 58a18a15..1e6dc821 100644 --- a/src/gui/widgets/dropdown.h +++ b/src/gui/widgets/dropdown.h @@ -1,32 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; 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 "../scrollarea.h" -#include "../listbox.h" class Image; class ImageRect; @@ -53,7 +49,8 @@ class DropDown : public gcn::DropDown */ DropDown(gcn::ListModel *listModel = NULL, gcn::ScrollArea *scrollArea = NULL, - gcn::ListBox *listBox = NULL); + gcn::ListBox *listBox = NULL, + bool opacity = true); /** * Destructor. @@ -64,6 +61,22 @@ class DropDown : public gcn::DropDown void drawFrame(gcn::Graphics* graphics); + /** + * Sets the widget to be opaque, that is sets the widget to display its + * background. + * + * @param opaque True if the widget should be opaque, false otherwise. + */ + void setOpaque(bool opaque) {mOpaque = opaque;} + + /** + * Checks if the widget is opaque, that is if the widget area displays + * its background. + * + * @return True if the widget is opaque, false otherwise. + */ + bool isOpaque() const {return mOpaque;} + protected: /** @@ -77,6 +90,9 @@ class DropDown : public gcn::DropDown static int instances; static Image *buttons[2][2]; static ImageRect skin; + static float mAlpha; + + bool mOpaque; }; #endif // end DROPDOWN_H diff --git a/src/gui/widgets/layout.cpp b/src/gui/widgets/layout.cpp index bcc54cf7..4ffdda36 100644 --- a/src/gui/widgets/layout.cpp +++ b/src/gui/widgets/layout.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/gui/widgets/layout.h b/src/gui/widgets/layout.h index d631c154..20a4222d 100644 --- a/src/gui/widgets/layout.h +++ b/src/gui/widgets/layout.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_WIDGET_LAYOUT_H__ -#define _TMW_WIDGET_LAYOUT_H__ +#ifndef WIDGET_LAYOUT_H +#define WIDGET_LAYOUT_H #include <vector> @@ -317,4 +317,4 @@ class Layout: public LayoutCell bool mComputed; }; -#endif +#endif // WIDGET_LAYOUT_H diff --git a/src/gui/widgets/layouthelper.cpp b/src/gui/widgets/layouthelper.cpp new file mode 100644 index 00000000..410de98a --- /dev/null +++ b/src/gui/widgets/layouthelper.cpp @@ -0,0 +1,63 @@ +/* + * The Mana World + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "layouthelper.h" + +LayoutHelper::LayoutHelper(gcn::Container *container): + mContainer(container) +{ + mContainer->addWidgetListener(this); +} + +LayoutHelper::~LayoutHelper() +{ + mContainer->removeWidgetListener(this); +} + +Layout &LayoutHelper::getLayout() +{ + return mLayout; +} + +LayoutCell &LayoutHelper::place(int x, int y, gcn::Widget *wg, int w, int h) +{ + mContainer->add(wg); + return mLayout.place(wg, x, y, w, h); +} + +ContainerPlacer LayoutHelper::getPlacer(int x, int y) +{ + return ContainerPlacer(mContainer, &mLayout.at(x, y)); +} + +void LayoutHelper::reflowLayout(int w, int h) +{ + mLayout.reflow(w, h); + mContainer->setSize(w, h); +} + +void LayoutHelper::widgetResized(const gcn::Event &event) +{ + const gcn::Rectangle area = mContainer->getChildrenArea(); + int w = area.width; + int h = area.height; + mLayout.reflow(w, h); +} diff --git a/src/gui/widgets/layouthelper.h b/src/gui/widgets/layouthelper.h new file mode 100644 index 00000000..afa92a18 --- /dev/null +++ b/src/gui/widgets/layouthelper.h @@ -0,0 +1,84 @@ +/* + * The Mana World + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LAYOUTHELPER_H +#define LAYOUTHELPER_H + +#include "layout.h" + +#include <guichan/widgetlistener.hpp> + +/** + * A helper class for adding a layout to a Guichan container widget. The layout + * will register itself as a widget listener and relayout the widgets in the + * container dynamically on resize. + */ +class LayoutHelper : public gcn::WidgetListener +{ + public: + /** + * Constructor. + */ + LayoutHelper(gcn::Container *container); + + /** + * Destructor. + */ + ~LayoutHelper(); + + /** + * Gets the layout handler. + */ + Layout &getLayout(); + + /** + * Computes the position of the widgets according to the current + * layout. Resizes the managed container so that the layout fits. + * + * @note This function is meant to be called with fixed-size + * containers. + * + * @param w if non-zero, force the container to this width. + * @param h if non-zero, force the container to this height. + */ + void reflowLayout(int w = 0, int h = 0); + + /** + * Adds a widget to the container and sets it at given cell. + */ + LayoutCell &place(int x, int y, gcn::Widget *, int w = 1, int h = 1); + + /** + * Returns a proxy for adding widgets in an inner table of the layout. + */ + ContainerPlacer getPlacer(int x, int y); + + /** + * Called whenever the managed container changes size. + */ + void widgetResized(const gcn::Event &event); + + private: + Layout mLayout; /**< Layout handler */ + gcn::Container *mContainer; /**< Managed container */ +}; + +#endif // LAYOUTHELPER_H diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp index c3b537db..fa264e37 100644 --- a/src/gui/widgets/resizegrip.cpp +++ b/src/gui/widgets/resizegrip.cpp @@ -1,28 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "resizegrip.h" - #include <guichan/graphics.hpp> +#include "resizegrip.h" + +#include "../../configuration.h" #include "../../graphics.h" #include "../../resources/image.h" @@ -30,14 +31,16 @@ Image *ResizeGrip::gripImage = 0; int ResizeGrip::mInstances = 0; +float ResizeGrip::mAlpha = config.getValue("guialpha", 0.8); -ResizeGrip::ResizeGrip() +ResizeGrip::ResizeGrip(std::string image) { if (mInstances == 0) { // Load the grip image ResourceManager *resman = ResourceManager::getInstance(); - gripImage = resman->getImage("graphics/gui/resize.png"); + gripImage = resman->getImage(image); + gripImage->setAlpha(mAlpha); } mInstances++; @@ -56,8 +59,13 @@ ResizeGrip::~ResizeGrip() } } -void -ResizeGrip::draw(gcn::Graphics *graphics) +void ResizeGrip::draw(gcn::Graphics *graphics) { + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + gripImage->setAlpha(mAlpha); + } + static_cast<Graphics*>(graphics)->drawImage(gripImage, 0, 0); } diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h index f57eda94..620c133f 100644 --- a/src/gui/widgets/resizegrip.h +++ b/src/gui/widgets/resizegrip.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_RESIZEGRIP_H -#define _TMW_RESIZEGRIP_H +#ifndef RESIZEGRIP_H +#define RESIZEGRIP_H #include <guichan/widget.hpp> @@ -39,7 +39,7 @@ class ResizeGrip : public gcn::Widget /** * Constructor. */ - ResizeGrip(); + ResizeGrip(std::string image = "graphics/gui/resize.png"); /** * Destructor. @@ -54,6 +54,7 @@ class ResizeGrip : public gcn::Widget private: static Image *gripImage; /**< Resize grip image */ static int mInstances; /**< Number of resize grip instances */ + static float mAlpha; }; #endif diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp index b09bc5b3..21402c89 100644 --- a/src/gui/widgets/tab.cpp +++ b/src/gui/widgets/tab.cpp @@ -1,31 +1,30 @@ /* * The Mana World - * Copyright 2008 The Mana World Development Team + * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> - #include <guichan/widgets/label.hpp> #include "tab.h" #include "tabbedarea.h" +#include "../../configuration.h" #include "../../graphics.h" #include "../../resources/image.h" @@ -34,6 +33,7 @@ #include "../../utils/dtor.h" int Tab::mInstances = 0; +float Tab::mAlpha = config.getValue("guialpha", 0.8); enum{ TAB_STANDARD, // 0 @@ -51,10 +51,10 @@ struct TabData }; static TabData const data[TAB_COUNT] = { - {"graphics/gui/tab.png", 0, 0}, - {"graphics/gui/tab.png", 9, 4}, - {"graphics/gui/tabselected.png", 16, 19}, - {"graphics/gui/tab.png", 25, 23} + { "graphics/gui/tab.png", 0, 0 }, + { "graphics/gui/tab.png", 9, 4 }, + { "graphics/gui/tabselected.png", 16, 19 }, + { "graphics/gui/tab.png", 25, 23 } }; ImageRect Tab::tabImg[TAB_COUNT]; @@ -100,6 +100,7 @@ void Tab::init() data[x].gridX, data[y].gridY, data[x + 1].gridX - data[x].gridX + 1, data[y + 1].gridY - data[y].gridY + 1); + tabImg[mode].grid[a]->setAlpha(mAlpha); a++; } } @@ -116,7 +117,7 @@ void Tab::draw(gcn::Graphics *graphics) // check which type of tab to draw if (mTabbedArea) { - if(mTabbedArea->isTabSelected(this)) + if (mTabbedArea->isTabSelected(this)) { mode = TAB_SELECTED; // if tab is selected, it doesnt need to highlight activity @@ -130,6 +131,15 @@ void Tab::draw(gcn::Graphics *graphics) } } + if (config.getValue("guialpha", 0.8) != mAlpha) + { + mAlpha = config.getValue("guialpha", 0.8); + for (int a = 0; a < 9; a++) + { + tabImg[TAB_SELECTED].grid[a]->setAlpha(mAlpha); + tabImg[TAB_STANDARD].grid[a]->setAlpha(mAlpha); + } + } // draw tab static_cast<Graphics*>(graphics)-> diff --git a/src/gui/widgets/tab.h b/src/gui/widgets/tab.h index 65cc3fa0..3af4e2bf 100644 --- a/src/gui/widgets/tab.h +++ b/src/gui/widgets/tab.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2008 The Mana World Development Team + * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_TAB_H -#define _TMW_TAB_H +#ifndef TAB_H +#define TAB_H #include <guichan/widgets/tab.hpp> @@ -58,6 +58,7 @@ class Tab : public gcn::Tab static ImageRect tabImg[4]; /**< Tab state graphics */ static int mInstances; /**< Number of tab instances */ + static float mAlpha; bool mHighlighted; }; diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp index 205fdc99..ce11fe69 100644 --- a/src/gui/widgets/tabbedarea.cpp +++ b/src/gui/widgets/tabbedarea.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2008 The Mana World Development Team + * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -75,7 +75,7 @@ gcn::Widget* TabbedArea::getWidget(const std::string &name) void TabbedArea::addTab(const std::string &caption, gcn::Widget *widget) { - Tab* tab = new Tab(); + Tab* tab = new Tab; tab->setCaption(caption); mTabsToDelete.push_back(tab); @@ -90,7 +90,7 @@ void TabbedArea::addTab(Tab *tab, gcn::Widget *widget) mTabContainer->add(tab); mTabs.push_back(std::pair<Tab*, gcn::Widget*>(tab, widget)); - if (mSelectedTab == NULL) + if (!mSelectedTab) { setSelectedTab(tab); } diff --git a/src/gui/widgets/tabbedarea.h b/src/gui/widgets/tabbedarea.h index 2199264b..01d70380 100644 --- a/src/gui/widgets/tabbedarea.h +++ b/src/gui/widgets/tabbedarea.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2008 The Mana World Development Team + * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_TABBEDAREA_H -#define _TMW_TABBEDAREA_H +#ifndef TABBEDAREA_H +#define TABBEDAREA_H #include <guichan/widget.hpp> #include <guichan/widgets/tabbedarea.hpp> diff --git a/src/gui/window.cpp b/src/gui/window.cpp index 64607243..58439316 100644 --- a/src/gui/window.cpp +++ b/src/gui/window.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -24,13 +24,9 @@ #include <climits> #include <guichan/exception.hpp> -#include <guichan/widgets/icon.hpp> - -#include <libxml/tree.h> - -#include "window.h" #include "gui.h" +#include "window.h" #include "windowcontainer.h" #include "widgets/layout.h" @@ -38,7 +34,6 @@ #include "../configlistener.h" #include "../configuration.h" -#include "../graphics.h" #include "../log.h" #include "../resources/image.h" @@ -50,55 +45,53 @@ ConfigListener *Window::windowConfigListener = 0; WindowContainer *Window::windowContainer = 0; int Window::instances = 0; int Window::mouseResize = 0; +//ImageRect Window::border; Image *Window::closeImage = NULL; -bool mLoaded = false; 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))); - } - */ - void optionChanged(const std::string &) { Window::mAlphaChanged = true; } }; -Window::Window(const std::string& caption, bool modal, Window *parent): +Window::Window(const std::string& caption, bool modal, Window *parent, const std::string& skin): gcn::Window(caption), mGrip(0), mParent(parent), mLayout(NULL), + mWindowName("window"), + mShowTitle(true), mModal(modal), mCloseButton(false), mSticky(false), mMinWinWidth(100), mMinWinHeight(40), mMaxWinWidth(INT_MAX), - mMaxWinHeight(INT_MAX) + mMaxWinHeight(INT_MAX), + mSkin(skin) { logger->log("Window::Window(\"%s\")", caption.c_str()); - if (!windowContainer) { + if (!windowContainer) + { throw GCN_EXCEPTION("Window::Window(): no windowContainer set"); } - loadSkin("graphics/gui/gui.xml"); + // Loads the skin + loadSkin(mSkin); + + setGuiAlpha(); - //if (instances == 0) - //{ - //WindowConfigListener = new WindowConfigListener(); + if (instances == 0) + { + windowConfigListener = new WindowConfigListener; // Send GUI alpha changed for initialization - //windowConfigListener->optionChanged("guialpha"); - //config.addListener("guialpha", windowConfigListener); - //} + windowConfigListener->optionChanged("guialpha"); + config.addListener("guialpha", windowConfigListener); + } instances++; @@ -106,8 +99,6 @@ Window::Window(const std::string& caption, bool modal, Window *parent): setPadding(3); setTitleBarHeight(20); - setGuiAlpha(); - // Add this window to the window container windowContainer->add(this); @@ -125,16 +116,18 @@ Window::Window(const std::string& caption, bool modal, Window *parent): Window::~Window() { - logger->log("UNLOAD: Window::~Window(\"%s\")", getCaption().c_str()); + logger->log("Window::~Window(\"%s\")", getCaption().c_str()); const std::string &name = mWindowName; // Saving X, Y and Width and Height for resizables in the config - if (!name.empty()) { + if (!name.empty()) + { config.setValue(name + "WinX", getX()); config.setValue(name + "WinY", getY()); config.setValue(name + "Visible", isVisible()); - if (mGrip) { + if (mGrip) + { config.setValue(name + "WinWidth", getWidth()); config.setValue(name + "WinHeight", getHeight()); } @@ -151,22 +144,21 @@ 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 closeImage->decRef(); } - - // Clean up Border images. - for( int i = 0; i < 9; i++ ) - { - delete border[i]; - border[i] = NULL; - } } void Window::setWindowContainer(WindowContainer *wc) @@ -176,17 +168,12 @@ void Window::setWindowContainer(WindowContainer *wc) void Window::draw(gcn::Graphics *graphics) { - if (mAlphaChanged) - setGuiAlpha(); - Graphics *g = static_cast<Graphics*>(graphics); - //g->drawImageRect(0, 0, getWidth(), getHeight(), border); - - g->drawImageRect(0, 0, getWidth(), getHeight(), border[0], border[2], border[6], border[8], border[1], border[5], border[7], border[3], border[4]); + g->drawImageRect(0, 0, getWidth(), getHeight(), border); // Draw title - if (getTitleBarHeight()) + if (mShowTitle) { g->setColor(gcn::Color(0, 0, 0)); g->setFont(getFont()); @@ -201,6 +188,15 @@ void Window::draw(gcn::Graphics *graphics) getPadding() ); } + + // Update window alpha values + if (mAlphaChanged) + { + for_each(border.grid, border.grid + 9, + std::bind2nd(std::mem_fun(&Image::setAlpha), + config.getValue("guialpha", 0.8))); + closeImage->setAlpha(config.getValue("guialpha", 0.8)); + } drawChildren(graphics); } @@ -248,7 +244,7 @@ void Window::setResizable(bool r) if (r) { - mGrip = new ResizeGrip(); + mGrip = new ResizeGrip; mGrip->setX(getWidth() - mGrip->getWidth() - getChildrenArea().x); mGrip->setY(getHeight() - mGrip->getHeight() - getChildrenArea().y); add(mGrip); @@ -263,17 +259,16 @@ void Window::setResizable(bool r) void Window::widgetResized(const gcn::Event &event) { + const gcn::Rectangle area = getChildrenArea(); + if (mGrip) - { - const gcn::Rectangle area = getChildrenArea(); mGrip->setPosition(getWidth() - mGrip->getWidth() - area.x, getHeight() - mGrip->getHeight() - area.y); - } if (mLayout) { - int w = getWidth() - 2 * getPadding(); - int h = getHeight() - getPadding() - getTitleBarHeight(); + int w = area.width; + int h = area.height; mLayout->reflow(w, h); } } @@ -527,39 +522,13 @@ int Window::getResizeHandles(gcn::MouseEvent &event) return resizeHandles; } -Layout &Window::getLayout() -{ - if (!mLayout) mLayout = new Layout; - return *mLayout; -} - -LayoutCell &Window::place(int x, int y, gcn::Widget *wg, int w, int h) -{ - add(wg); - return getLayout().place(wg, x, y, w, h); -} - -ContainerPlacer Window::getPlacer(int x, int y) -{ - return ContainerPlacer(this, &getLayout().at(x, y)); -} - -void Window::reflowLayout(int w, int h) -{ - assert(mLayout); - mLayout->reflow(w, h); - delete mLayout; - mLayout = NULL; - setContentSize(w, h); -} - void Window::setGuiAlpha() { //logger->log("Window::setGuiAlpha: Alpha Value %f", config.getValue("guialpha", 0.8)); - for(int i = 0; i < 9; i++) + for (int i = 0; i < 9; i++) { //logger->log("Window::setGuiAlpha: Border Image (%i)", i); - border[i]->setAlpha(config.getValue("guialpha", 0.8)); + border.grid[i]->setAlpha(config.getValue("guialpha", 0.8)); } mAlphaChanged = false; @@ -567,13 +536,15 @@ void Window::setGuiAlpha() 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'.", Window::getId().c_str()); + logger->log("Loading Window ID '%s'.", windowId.c_str()); - if (fileName == "") + if (fileName.empty()) logger->error("Window::loadSkin(): Invalid File Name."); // TODO: @@ -591,7 +562,7 @@ void Window::loadSkin(const std::string &fileName) std::string skinSetImage; skinSetImage = XML::getProperty(rootNode, "image", ""); Image *dBorders = NULL; - if(skinSetImage != "") + if (!skinSetImage.empty()) { logger->log("Window::loadSkin(): <skinset> defines '%s' as a skin image.", skinSetImage.c_str()); dBorders = resman->getImage("graphics/gui/" + skinSetImage);//"graphics/gui/speech_bubble.png"); @@ -611,7 +582,7 @@ void Window::loadSkin(const std::string &fileName) widgetType = XML::getProperty(widgetNode, "type", "unknown"); if (widgetType == "Window") { - // Itarate through <part>'s + // 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. @@ -625,90 +596,90 @@ void Window::loadSkin(const std::string &fileName) std::string partType; partType = XML::getProperty(partNode, "type", "unknown"); // TOP ROW - if(partType == "top-left-corner") + 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[0] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[0] = dBorders->getSubImage(xPos, yPos, width, height); } - else if(partType == "top-edge") + 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[1] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[1] = dBorders->getSubImage(xPos, yPos, width, height); } - else if(partType == "top-right-corner") + 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[2] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[2] = dBorders->getSubImage(xPos, yPos, width, height); } // MIDDLE ROW - else if(partType == "left-edge") + 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[3] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[3] = dBorders->getSubImage(xPos, yPos, width, height); } - else if(partType == "bg-quad") + 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[4] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[4] = dBorders->getSubImage(xPos, yPos, width, height); } - else if(partType == "right-edge") + 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[5] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[5] = dBorders->getSubImage(xPos, yPos, width, height); } // BOTTOM ROW - else if(partType == "bottom-left-corner") + 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[6] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[6] = dBorders->getSubImage(xPos, yPos, width, height); } - else if(partType == "bottom-edge") + 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[7] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[7] = dBorders->getSubImage(xPos, yPos, width, height); } - else if(partType == "bottom-right-corner") + 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[8] = dBorders->getSubImage(xPos, yPos, width, height); + border.grid[8] = dBorders->getSubImage(xPos, yPos, width, height); } // Part is of an uknown type. @@ -731,3 +702,29 @@ void Window::loadSkin(const std::string &fileName) // Hard-coded for now until we update the above code to look for window buttons. closeImage = resman->getImage("graphics/gui/close_button.png"); } + +Layout &Window::getLayout() +{ + if (!mLayout) mLayout = new Layout; + return *mLayout; +} + +LayoutCell &Window::place(int x, int y, gcn::Widget *wg, int w, int h) +{ + add(wg); + return getLayout().place(wg, x, y, w, h); +} + +ContainerPlacer Window::getPlacer(int x, int y) +{ + return ContainerPlacer(this, &getLayout().at(x, y)); +} + +void Window::reflowLayout(int w, int h) +{ + assert(mLayout); + mLayout->reflow(w, h); + delete mLayout; + mLayout = NULL; + setContentSize(w, h); +} diff --git a/src/gui/window.h b/src/gui/window.h index 50a206f0..3806342a 100644 --- a/src/gui/window.h +++ b/src/gui/window.h @@ -1,30 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_WINDOW_H__ -#define _TMW_WINDOW_H__ +#ifndef WINDOW_H +#define WINDOW_H -#include <guichan/widgets/window.hpp> #include <guichan/widgetlistener.hpp> +#include <guichan/widgets/window.hpp> + +#include "../graphics.h" #include "../guichanfwd.h" class ConfigListener; @@ -56,9 +58,10 @@ class Window : public gcn::Window, gcn::WidgetListener * @param parent The parent window. This is the window standing above * this one in the window hiearchy. When reordering, * a window will never go below its parent window. + * @param skin The location where the window's skin XML can be found. */ Window(const std::string &caption = "Window", bool modal = false, - Window *parent = NULL); + Window *parent = NULL, const std::string &skin = "graphics/gui/gui.xml"); /** * Destructor. Deletes all the added widgets. @@ -126,6 +129,26 @@ class Window : public gcn::Window, gcn::WidgetListener void setMaxHeight(unsigned int height); /** + * Gets the minimum width of the window. + */ + int getMinWidth() { return mMinWinWidth; } + + /** + * Gets the minimum height of the window. + */ + int getMinHeight() { return mMinWinHeight; } + + /** + * Gets the maximum width of the window. + */ + int getMaxWidth() { return mMaxWinWidth; } + + /** + * Gets the minimum height of the window. + */ + int getMaxHeight() { return mMaxWinHeight; } + + /** * Sets flag to show a title or not. */ void setShowTitle(bool flag) @@ -238,6 +261,11 @@ class Window : public gcn::Window, gcn::WidgetListener void reflowLayout(int w = 0, int h = 0); /** + * Loads a window skin + */ + void loadSkin(const std::string &fileName); + + /** * Adds a widget to the window and sets it at given cell. */ LayoutCell &place(int x, int y, gcn::Widget *, int w = 1, int h = 1); @@ -247,11 +275,6 @@ class Window : public gcn::Window, gcn::WidgetListener */ ContainerPlacer getPlacer(int x, int y); - /** - * Loads a window skin - */ - void loadSkin(const std::string &fileName); - protected: /** The window container windows add themselves to. */ static WindowContainer *windowContainer; @@ -274,6 +297,8 @@ class Window : public gcn::Window, gcn::WidgetListener */ int getResizeHandles(gcn::MouseEvent &event); + void setGuiAlpha(); + ResizeGrip *mGrip; /**< Resize grip */ Window *mParent; /**< The parent window */ Layout *mLayout; /**< Layout handler */ @@ -282,6 +307,7 @@ class Window : public gcn::Window, gcn::WidgetListener bool mModal; /**< Window is modal */ bool mCloseButton; /**< Window has a close button */ bool mSticky; /**< Window resists minimization */ + static bool mAlphaChanged; /**< Whether the alpha percent was changed */ int mMinWinWidth; /**< Minimum window width */ int mMinWinHeight; /**< Minimum window height */ int mMaxWinWidth; /**< Maximum window width */ @@ -290,6 +316,7 @@ class Window : public gcn::Window, gcn::WidgetListener int mDefaultY; /**< Default window Y position */ int mDefaultWidth; /**< Default window width */ int mDefaultHeight; /**< Default window height */ + std::string mSkin; /**< Name of the skin to use */ /** * The config listener that listens to changes relevant to all windows. @@ -298,10 +325,7 @@ class Window : public gcn::Window, gcn::WidgetListener static int mouseResize; /**< Active resize handles */ static int instances; /**< Number of Window instances */ - - void setGuiAlpha(); - static bool mAlphaChanged; - Image *border[9]; + 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 d8535f73..2846b1c1 100644 --- a/src/gui/windowcontainer.cpp +++ b/src/gui/windowcontainer.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/gui/windowcontainer.h b/src/gui/windowcontainer.h index 88a13d31..62704d1b 100644 --- a/src/gui/windowcontainer.h +++ b/src/gui/windowcontainer.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_WINDOWCONTAINER_H_ -#define _TMW_WINDOWCONTAINER_H_ +#ifndef WINDOWCONTAINER_H +#define WINDOWCONTAINER_H #include <guichan/widgets/container.hpp> @@ -30,7 +30,8 @@ * * \ingroup GUI */ -class WindowContainer : public gcn::Container { +class WindowContainer : public gcn::Container +{ public: /** * Do GUI logic. This functions adds automatic deletion of objects that diff --git a/src/guichanfwd.h b/src/guichanfwd.h index 4fb7ea3e..4863421c 100644 --- a/src/guichanfwd.h +++ b/src/guichanfwd.h @@ -1,28 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_GUICHANFWD_H -#define _TMW_GUICHANFWD_H +#ifndef GUICHANFWD_H +#define GUICHANFWD_H -namespace gcn { +namespace gcn +{ class ActionListener; class AllegroGraphics; class AllegroImage; diff --git a/src/imageparticle.cpp b/src/imageparticle.cpp index 65780345..557b3553 100644 --- a/src/imageparticle.cpp +++ b/src/imageparticle.cpp @@ -1,27 +1,26 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * 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/imageparticle.h b/src/imageparticle.h index c18b30b8..317b17ea 100644 --- a/src/imageparticle.h +++ b/src/imageparticle.h @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/inventory.cpp b/src/inventory.cpp index 85461f90..cdd7b61c 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -1,47 +1,52 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "inventory.h" - #include <algorithm> +#include "inventory.h" #include "item.h" #include "log.h" struct SlotUsed : public std::unary_function<Item*, bool> { - bool operator()(const Item *item) const { + bool operator()(const Item *item) const + { +#ifdef TMWSERV_SUPPORT return item && item->getId() && item->getQuantity(); +#else + return item && item->getId() != -1 && item->getQuantity() > 0; +#endif } }; -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; @@ -49,53 +54,70 @@ Inventory::~Inventory() Item* Inventory::getItem(int index) const { - if (index < 0 || index >= INVENTORY_SIZE) +#ifdef TMWSERV_SUPPORT + if (index < 0 || index >= mSize) +#else + if (index < 0 || index >= mSize || !mItems[index] || mItems[index]->getQuantity() <= 0) +#endif return 0; return mItems[index]; } +Item* Inventory::findItem(int itemId) const +{ + for (int i = 0; i < mSize; i++) + if (mItems[i] && mItems[i]->getId() == itemId) + return mItems[i]; + + return NULL; +} -void Inventory::addItem(int id, int quantity) +void Inventory::addItem(int id, int quantity, bool equipment) { - setItem(getFreeSlot(), id, quantity); + setItem(getFreeSlot(), id, quantity, equipment); } -void Inventory::setItem(int index, int id, int quantity) +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; } - if (!mItems[index] && id > 0) { - mItems[index] = new Item(id, quantity); - mItems[index]->setInvIndex(index); - } else if (id > 0) { + if (!mItems[index] && id > 0) + { + Item *item = new Item(id, quantity, equipment); + item->setInvIndex(index); + mItems[index] = item; + } + else if (id > 0) + { mItems[index]->setId(id); mItems[index]->setQuantity(quantity); - } else if (mItems[index]) { - removeItemIndex(index); + mItems[index]->setEquipment(equipment); + } + else if (mItems[index]) + { + removeItemAt(index); } } void Inventory::clear() { - for (int i = 0; i < INVENTORY_SIZE; i++) { - removeItemIndex(i); - } + for (int i = 0; i < mSize; i++) + removeItemAt(i); } void Inventory::removeItem(int id) { - for (int i = 0; i < INVENTORY_SIZE; i++) { - if (mItems[i] && mItems[i]->getId() == id) { - removeItemIndex(i); - } - } + for (int i = 0; i < mSize; i++) + if (mItems[i] && mItems[i]->getId() == id) + removeItemAt(i); } -void Inventory::removeItemIndex(int index) +void Inventory::removeItemAt(int index) { delete mItems[index]; mItems[index] = 0; @@ -103,34 +125,34 @@ void Inventory::removeItemIndex(int index) bool Inventory::contains(Item *item) const { - for (int i = 0; i < INVENTORY_SIZE; i++) { - if (mItems[i] && mItems[i]->getId() == item->getId()) { + for (int i = 0; i < mSize; i++) + if (mItems[i] && mItems[i]->getId() == item->getId()) return true; - } - } return false; } int Inventory::getFreeSlot() const { - Item **i = std::find_if(mItems, mItems + INVENTORY_SIZE, +#ifdef TMWSERV_SUPPORT + Item **i = std::find_if(mItems, mItems + mSize, +#else + Item **i = std::find_if(mItems + 2, mItems + mSize, +#endif std::not1(SlotUsed())); - return (i == mItems + INVENTORY_SIZE) ? -1 : (i - mItems); + return (i == mItems + mSize) ? -1 : (i - mItems); } int Inventory::getNumberOfSlotsUsed() const { - return count_if(mItems, mItems + INVENTORY_SIZE, SlotUsed()); + return count_if(mItems, mItems + mSize, SlotUsed()); } int Inventory::getLastUsedSlot() const { - for (int i = INVENTORY_SIZE - 1; i >= 0; i--) { - if (SlotUsed()(mItems[i])) { + for (int i = mSize - 1; i >= 0; i--) + if (SlotUsed()(mItems[i])) return i; - } - } return -1; } diff --git a/src/inventory.h b/src/inventory.h index 90d9c7a2..d2a81edf 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -24,15 +24,13 @@ class Item; -#define INVENTORY_SIZE 50 - class Inventory { public: /** * Constructor. */ - Inventory(); + Inventory(int size); /** * Destructor. @@ -40,19 +38,32 @@ 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; /** + * Searches for the specified item by it's id. + * + * @param itemId The id of the item to be searched. + * @return Item found on success, NULL on failure. + */ + Item* findItem(int itemId) const; + + /** * Adds a new item in a free slot. */ - void addItem(int id, int quantity); + void addItem(int id, int quantity, bool equipment = false); /** * Sets the item at the given position. */ - void setItem(int index, int id, int quantity); + void setItem(int index, int id, int quantity, bool equipment = false); /** * Remove a item from the inventory. @@ -60,9 +71,9 @@ class Inventory void removeItem(int id); /** - * Remove a item from the inventory, specified by the index. + * Remove the item at the specified index from the inventory. */ - void removeItemIndex(int index); + void removeItemAt(int index); /** * Checks if the given item is in the inventory @@ -92,6 +103,7 @@ class Inventory static const int NO_SLOT_INDEX = -1; /**< Slot has no index. */ protected: Item **mItems; /**< The holder of items */ + int mSize; /**< The max number of inventory items */ }; #endif diff --git a/src/item.cpp b/src/item.cpp index 374d5051..042c3800 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -24,9 +24,17 @@ #include "resources/image.h" #include "resources/resourcemanager.h" -Item::Item(int id, int quantity) : +Item::Item(int id, int quantity, bool equipment +#ifdef EATHENA_SUPPORT + , bool equipped +#endif + ): mImage(0), - mQuantity(quantity) + mQuantity(quantity), + mEquipment(equipment) +#ifdef EATHENA_SUPPORT + , mEquipped(equipped) +#endif { setId(id); } @@ -41,8 +49,10 @@ void Item::setId(int id) { mId = id; +#ifdef TMWSERV_SUPPORT // Types 0 and 1 are not equippable items. mEquipment = id && getInfo().getType() >= 2; +#endif // Load the associated image if (mImage) @@ -55,4 +65,3 @@ void Item::setId(int id) if (!mImage) mImage = resman->getImage("graphics/gui/unknown-item.png"); } - @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _ITEM_H_ -#define _ITEM_H_ +#ifndef ITEM_H +#define ITEM_H #include "resources/itemdb.h" @@ -35,7 +35,11 @@ class Item /** * Constructor. */ - Item(int id = 0, int quantity = 0); + Item(int id = -1, int quantity = 0, bool equipment = false +#ifdef EATHENA_SUPPORT + , bool equipped = false +#endif + ); /** * Destructor. @@ -50,8 +54,7 @@ class Item /** * Returns the item id. */ - int - getId() const { return mId; } + int getId() const { return mId; } /** * Returns the item image. @@ -61,50 +64,63 @@ class Item /** * Sets the number of items. */ - void - setQuantity(int quantity) { mQuantity = quantity; } + void setQuantity(int quantity) { mQuantity = quantity; } /** * Increases the number of items by the given amount. */ - void - increaseQuantity(int amount) { mQuantity += amount; } + void increaseQuantity(int amount) { mQuantity += amount; } /** * Returns the number of items. */ - int - getQuantity() const { return mQuantity; } + int getQuantity() const { return mQuantity; } + + /** + * Sets whether this item is considered equipment. + */ + void setEquipment(bool equipment) { mEquipment = equipment; } /** * Returns whether this item is considered equipment. */ - bool - isEquipment() const { return mEquipment; } + bool isEquipment() const { return mEquipment; } + +#ifdef EATHENA_SUPPORT + /** + * Sets whether this item is equipped. + */ + void setEquipped(bool equipped) { mEquipped = equipped; } + + /** + * Returns whether this item is equipped. + */ + bool isEquipped() const { return mEquipped; } +#endif /** * Sets the inventory index of this item. */ - void - setInvIndex(int index) { mInvIndex = index; } + void setInvIndex(int index) { mInvIndex = index; } /** * Returns the inventory index of this item. */ - int - getInvIndex() const { return mInvIndex; } + int getInvIndex() const { return mInvIndex; } /** * Returns information about this item type. */ - const ItemInfo& - getInfo() const { return ItemDB::get(mId); } + const ItemInfo& getInfo() const { return ItemDB::get(mId); } protected: int mId; /**< Item type id. */ Image *mImage; /**< Item image. */ int mQuantity; /**< Number of items. */ bool mEquipment; /**< Item is equipment. */ +#ifdef EATHENA_SUPPORT + bool mEquipped; /**< Item is equipped. */ +#endif int mInvIndex; /**< Inventory index. */ }; diff --git a/src/itemshortcut.cpp b/src/itemshortcut.cpp index bea14864..2dea8c56 100644 --- a/src/itemshortcut.cpp +++ b/src/itemshortcut.cpp @@ -1,31 +1,31 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * 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 "configuration.h" -#include "utils/tostring.h" +#include "utils/stringutils.h" ItemShortcut::ItemShortcut *itemShortcut; @@ -33,9 +33,8 @@ ItemShortcut::ItemShortcut(): mItemSelected(-1) { for (int i = 0; i < SHORTCUT_ITEMS; i++) - { mItems[i] = -1; - } + load(); } @@ -51,9 +50,7 @@ void ItemShortcut::load() int itemId = (int) config.getValue("shortcut" + toString(i), -1); if (itemId != -1) - { mItems[i] = itemId; - } } } @@ -70,21 +67,26 @@ void ItemShortcut::useItem(int index) { if (mItems[index]) { - Item *item = player_node->searchForItem(mItems[index]); + Item *item = player_node->getInventory()->findItem(mItems[index]); if (item && item->getQuantity()) { - // TODO: Fix this (index vs. pointer mismatch) - /* - if (item->isEquipment()) { - if (item->isEquipped()) { + if (item->isEquipment()) + { +#ifdef EATHENA_SUPPORT + if (item->isEquipped()) player_node->unequipItem(item); - } else { + else +#endif player_node->equipItem(item); - } - } else { + } + else + { +#ifdef TMWSERV_SUPPORT + player_node->useItem(item->getInvIndex()); +#else player_node->useItem(item); +#endif } - */ } } } diff --git a/src/itemshortcut.h b/src/itemshortcut.h index a0c52468..95e17f44 100644 --- a/src/itemshortcut.h +++ b/src/itemshortcut.h @@ -1,28 +1,28 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ITEMSHORTCUT_H__ -#define _TMW_ITEMSHORTCUT_H__ +#ifndef ITEMSHORTCUT_H +#define ITEMSHORTCUT_H -#define SHORTCUT_ITEMS 10 +#define SHORTCUT_ITEMS 12 class Item; diff --git a/src/joystick.cpp b/src/joystick.cpp index b05e9b5f..b72c9103 100644 --- a/src/joystick.cpp +++ b/src/joystick.cpp @@ -1,27 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "joystick.h" - #include "configuration.h" +#include "joystick.h" #include "log.h" #include <cassert> diff --git a/src/joystick.h b/src/joystick.h index ee029915..4c5390c2 100644 --- a/src/joystick.h +++ b/src/joystick.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_JOYSTICK_H -#define _TMW_JOYSTICK_H +#ifndef JOYSTICK_H +#define JOYSTICK_H #include <SDL.h> @@ -30,12 +30,16 @@ class Joystick /** * Number of buttons we can handle. */ - enum { MAX_BUTTONS = 6 }; + enum + { + MAX_BUTTONS = 6 + }; /** * Directions, to be used as bitmask values. */ - enum { + enum + { UP = 1, DOWN = 2, LEFT = 4, @@ -96,4 +100,4 @@ class Joystick void doCalibration(); }; -#endif // _TMW_JOYSTICK_H +#endif // JOYSTICK_H diff --git a/src/keyboardconfig.cpp b/src/keyboardconfig.cpp index 3e4e52c4..73c0fe0a 100644 --- a/src/keyboardconfig.cpp +++ b/src/keyboardconfig.cpp @@ -1,71 +1,103 @@ /* - * The Mana World - * Copyright 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "keyboardconfig.h" #include "configuration.h" +#include "keyboardconfig.h" #include "log.h" -#include <guichan/sdl/sdlinput.hpp> - +#include "gui/sdlinput.h" #include "gui/setup_keyboard.h" +#include "utils/gettext.h" +#include "utils/strprintf.h" + struct KeyData { const char *configField; int defaultValue; - const char *caption; + std::string caption; }; // keyData must be in same order as enum keyAction. static KeyData const keyData[KeyboardConfig::KEY_TOTAL] = { - {"keyMoveUp", SDLK_UP, "Move Up"}, - {"keyMoveDown", SDLK_DOWN, "Move Down"}, - {"keyMoveLeft", SDLK_LEFT, "Move Left"}, - {"keyMoveRight", SDLK_RIGHT, "Move Right"}, - {"keyAttack", SDLK_LCTRL, "Attack"}, - {"keyTarget", SDLK_LSHIFT, "Target"}, - {"keyTargetClosest", SDLK_a, "Target Closest"}, - {"keyTargetPlayer", SDLK_q, "Target Player"}, - {"keyPickup", SDLK_z, "Pickup"}, - {"keyHideWindows", SDLK_h, "Hide Windows"}, - {"keyBeingSit", SDLK_s, "Sit"}, - {"keyShortcut0", SDLK_0, "Item Shortcut 0"}, - {"keyShortcut1", SDLK_1, "Item Shortcut 1"}, - {"keyShortcut2", SDLK_2, "Item Shortcut 2"}, - {"keyShortcut3", SDLK_3, "Item Shortcut 3"}, - {"keyShortcut4", SDLK_4, "Item Shortcut 4"}, - {"keyShortcut5", SDLK_5, "Item Shortcut 5"}, - {"keyShortcut6", SDLK_6, "Item Shortcut 6"}, - {"keyShortcut7", SDLK_7, "Item Shortcut 7"}, - {"keyShortcut8", SDLK_8, "Item Shortcut 8"}, - {"keyShortcut9", SDLK_9, "Item Shortcut 9"}, - {"keyWindowStatus", SDLK_F2, "Status Window"}, - {"keyWindowInventory", SDLK_F3, "Inventory Window"}, - {"keyWindowEquipment", SDLK_F4, "Equipment WIndow"}, - {"keyWindowSkill", SDLK_F5, "Skill Window"}, - {"keyWindowMinimap", SDLK_F6, "Minimap Window"}, - {"keyWindowChat", SDLK_F7, "Chat Window"}, - {"keyWindowShortcut", SDLK_F8, "Item Shortcut Window"}, - {"keyWindowSetup", SDLK_F9, "Setup Window"}, - {"keyWindowDebug", SDLK_F10, "Debug Window"} + {"keyMoveUp", SDLK_UP, _("Move Up")}, + {"keyMoveDown", SDLK_DOWN, _("Move Down")}, + {"keyMoveLeft", SDLK_LEFT, _("Move Left")}, + {"keyMoveRight", SDLK_RIGHT, _("Move Right")}, + {"keyAttack", SDLK_LCTRL, _("Attack")}, + {"keySmilie", SDLK_LALT, _("Smilie")}, + {"keyTalk", SDLK_t, _("Talk")}, + {"keyTarget", SDLK_LSHIFT, _("Stop Attack")}, + {"keyTargetClosest", SDLK_a, _("Target Closest")}, + {"keyTargetNPC", SDLK_n, _("Target NPC")}, + {"keyTargetPlayer", SDLK_q, _("Target Player")}, + {"keyPickup", SDLK_z, _("Pickup")}, + {"keyHideWindows", SDLK_h, _("Hide Windows")}, + {"keyBeingSit", SDLK_s, _("Sit")}, + {"keyScreenshot", SDLK_p, _("Screenshot")}, + {"keyTrade", SDLK_r, _("Enable/Disable Trading")}, + {"keyPathfind", SDLK_f, _("Find Path to Mouse")}, + {"keyShortcut1", SDLK_1, strprintf(_("Item Shortcut %d"), 1)}, + {"keyShortcut2", SDLK_2, strprintf(_("Item Shortcut %d"), 2)}, + {"keyShortcut3", SDLK_3, strprintf(_("Item Shortcut %d"), 3)}, + {"keyShortcut4", SDLK_4, strprintf(_("Item Shortcut %d"), 4)}, + {"keyShortcut5", SDLK_5, strprintf(_("Item Shortcut %d"), 5)}, + {"keyShortcut6", SDLK_6, strprintf(_("Item Shortcut %d"), 6)}, + {"keyShortcut7", SDLK_7, strprintf(_("Item Shortcut %d"), 7)}, + {"keyShortcut8", SDLK_8, strprintf(_("Item Shortcut %d"), 8)}, + {"keyShortcut9", SDLK_9, strprintf(_("Item Shortcut %d"), 9)}, + {"keyShortcut10", SDLK_0, strprintf(_("Item Shortcut %d"), 10)}, + {"keyShortcut11", SDLK_MINUS, strprintf(_("Item Shortcut %d"), 11)}, + {"keyShortcut12", SDLK_EQUALS, strprintf(_("Item Shortcut %d"), 12)}, + {"keyWindowHelp", SDLK_F1, _("Help Window")}, + {"keyWindowStatus", SDLK_F2, _("Status Window")}, + {"keyWindowInventory", SDLK_F3, _("Inventory Window")}, + {"keyWindowEquipment", SDLK_F4, _("Equipment WIndow")}, + {"keyWindowSkill", SDLK_F5, _("Skill Window")}, + {"keyWindowMinimap", SDLK_F6, _("Minimap Window")}, + {"keyWindowChat", SDLK_F7, _("Chat Window")}, + {"keyWindowShortcut", SDLK_F8, _("Item Shortcut Window")}, + {"keyWindowSetup", SDLK_F9, _("Setup Window")}, + {"keyWindowDebug", SDLK_F10, _("Debug Window")}, + {"keyWindowEmote", SDLK_F11, _("Emote Window")}, + {"keyWindowEmoteBar", SDLK_F12, _("Emote Shortcut Window")}, + {"keyEmoteShortcut1", SDLK_1, strprintf(_("Emote Shortcut %d"), 1)}, + {"keyEmoteShortcut2", SDLK_2, strprintf(_("Emote Shortcut %d"), 2)}, + {"keyEmoteShortcut3", SDLK_3, strprintf(_("Emote Shortcut %d"), 3)}, + {"keyEmoteShortcut4", SDLK_4, strprintf(_("Emote Shortcut %d"), 4)}, + {"keyEmoteShortcut5", SDLK_5, strprintf(_("Emote Shortcut %d"), 5)}, + {"keyEmoteShortcut6", SDLK_6, strprintf(_("Emote Shortcut %d"), 6)}, + {"keyEmoteShortcut7", SDLK_7, strprintf(_("Emote Shortcut %d"), 7)}, + {"keyEmoteShortcut8", SDLK_8, strprintf(_("Emote Shortcut %d"), 8)}, + {"keyEmoteShortcut9", SDLK_9, strprintf(_("Emote Shortcut %d"), 9)}, + {"keyEmoteShortcut10", SDLK_0, strprintf(_("Emote Shortcut %d"), 10)}, + {"keyEmoteShortcut11", SDLK_MINUS, strprintf(_("Emote Shortcut %d"), 11)}, + {"keyEmoteShortcut12", SDLK_EQUALS, strprintf(_("Emote Shortcut %d"), 12)}, + {"keyChat", SDLK_RETURN, _("Toggle Chat")}, + {"keyChatScrollUp", SDLK_PAGEUP, _("Scroll Chat Up")}, + {"keyChatScrollDown", SDLK_PAGEDOWN, _("Scroll Chat Down")}, + {"keyOK", SDLK_RETURN, _("Select OK")}, + {"keyQuit", SDLK_ESCAPE, _("Quit")}, + {"keyIgnoreInput1", SDLK_LSUPER, _("Ignore input 1")}, + {"keyIgnoreInput2", SDLK_RSUPER, _("Ignore input 2")} }; void KeyboardConfig::init() @@ -111,11 +143,20 @@ void KeyboardConfig::makeDefault() bool KeyboardConfig::hasConflicts() { int i, j; + /** + * No need to parse the square matrix: only check one triangle + * that's enough to detect conflicts + */ for (i = 0; i < KEY_TOTAL; i++) { - for (j = 0; j < KEY_TOTAL; j++) + for (j = i, j++; j < KEY_TOTAL; j++) { - if (i != j && mKey[i].value == mKey[j].value) + // Allow for item shortcut and emote keys to overlap, but no other keys + if (!((((i >= KEY_SHORTCUT_1) && (i <= KEY_SHORTCUT_12)) && + ((j >= KEY_EMOTE_1) && (j <= KEY_EMOTE_12))) || + ((i == KEY_TOGGLE_CHAT) && (j == KEY_OK))) && + (mKey[i].value == mKey[j].value) + ) { return true; } @@ -133,7 +174,7 @@ int KeyboardConfig::getKeyIndex(int keyValue) const { for (int i = 0; i < KEY_TOTAL; i++) { - if(keyValue == mKey[i].value) + if (keyValue == mKey[i].value) { return i; } @@ -141,9 +182,22 @@ int KeyboardConfig::getKeyIndex(int keyValue) const return KEY_NO_VALUE; } + +int KeyboardConfig::getKeyEmoteOffset(int keyValue) const +{ + for (int i = KEY_EMOTE_1; i <= KEY_EMOTE_12; i++) + { + if (keyValue == mKey[i].value) + { + return 1 + i - KEY_EMOTE_1; + } + } + return 0; +} + bool KeyboardConfig::isKeyActive(int index) { - return mActiveKeys[ mKey[index].value]; + return mActiveKeys[mKey[index].value]; } void KeyboardConfig::refreshActiveKeys() diff --git a/src/keyboardconfig.h b/src/keyboardconfig.h index 729bad5a..f7750b30 100644 --- a/src/keyboardconfig.h +++ b/src/keyboardconfig.h @@ -1,33 +1,30 @@ /* - * The Mana World - * Copyright 2007 The Mana World Development Team + * Custom keyboard shortcuts configuration + * Copyright (C) 2007 Joshua Langley <joshlangley@optusnet.com.au> * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_KEYBOARDCONFIG_H -#define _TMW_KEYBOARDCONFIG_H +#ifndef KEYBOARDCONFIG_H +#define KEYBOARDCONFIG_H +#include <SDL_types.h> #include <string> -#include "gui/setup_keyboard.h" - -#include <guichan/sdl/sdlinput.hpp> - /** * Each key represents a key function. Such as 'Move up', 'Attack' etc. */ @@ -39,6 +36,8 @@ struct KeyFunction int value; /** The actual value that is used. */ }; +class Setup_Keyboard; + class KeyboardConfig { public: @@ -102,6 +101,11 @@ class KeyboardConfig int getKeyIndex(int keyValue) const; /** + * Get the key function index for an emote by providing the offset value. + */ + int getKeyEmoteOffset(int keyValue) const; + + /** * Set the enable flag, which will stop the user from doing actions. */ void setEnabled(bool flag) @@ -142,20 +146,26 @@ class KeyboardConfig * The key assignment view gets arranged according to the order of * these values. */ - enum KeyAction { + enum KeyAction + { KEY_NO_VALUE = -1, KEY_MOVE_UP, KEY_MOVE_DOWN, KEY_MOVE_LEFT, KEY_MOVE_RIGHT, KEY_ATTACK, + KEY_EMOTE, + KEY_TALK, KEY_TARGET, KEY_TARGET_CLOSEST, + KEY_TARGET_NPC, KEY_TARGET_PLAYER, KEY_PICKUP, KEY_HIDE_WINDOWS, KEY_SIT, - KEY_SHORTCUT_0, + KEY_SCREENSHOT, + KEY_TRADE, + KEY_PATHFIND, KEY_SHORTCUT_1, KEY_SHORTCUT_2, KEY_SHORTCUT_3, @@ -165,6 +175,10 @@ class KeyboardConfig KEY_SHORTCUT_7, KEY_SHORTCUT_8, KEY_SHORTCUT_9, + KEY_SHORTCUT_10, + KEY_SHORTCUT_11, + KEY_SHORTCUT_12, + KEY_WINDOW_HELP, KEY_WINDOW_STATUS, KEY_WINDOW_INVENTORY, KEY_WINDOW_EQUIPMENT, @@ -174,6 +188,27 @@ class KeyboardConfig KEY_WINDOW_SHORTCUT, KEY_WINDOW_SETUP, KEY_WINDOW_DEBUG, + KEY_WINDOW_EMOTE, + KEY_WINDOW_EMOTE_SHORTCUT, + KEY_EMOTE_1, + KEY_EMOTE_2, + KEY_EMOTE_3, + KEY_EMOTE_4, + KEY_EMOTE_5, + KEY_EMOTE_6, + KEY_EMOTE_7, + KEY_EMOTE_8, + KEY_EMOTE_9, + KEY_EMOTE_10, + KEY_EMOTE_11, + KEY_EMOTE_12, + KEY_TOGGLE_CHAT, + KEY_SCROLL_CHAT_UP, + KEY_SCROLL_CHAT_DOWN, + KEY_OK, + KEY_QUIT, + KEY_IGNORE_INPUT_1, + KEY_IGNORE_INPUT_2, KEY_TOTAL }; diff --git a/src/localplayer.cpp b/src/localplayer.cpp index ffb4aac9..21ee3a22 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -1,57 +1,77 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <cassert> -#include "localplayer.h" - +#include "configuration.h" #include "equipment.h" #include "floor_item.h" #include "game.h" -#include "guild.h" +#include "graphics.h" #include "inventory.h" #include "item.h" -#include "main.h" +#include "localplayer.h" +#include "map.h" +#include "monster.h" #include "particle.h" +#include "simpleanimation.h" #include "sound.h" -#include "log.h" +#include "statuseffect.h" +#include "text.h" + +#include "gui/gui.h" +#include "gui/ministatus.h" + +#ifdef TMWSERV_SUPPORT #include "effectmanager.h" +#include "guild.h" #include "net/gameserver/player.h" #include "net/chatserver/guild.h" #include "net/chatserver/party.h" +#endif -#include "gui/gui.h" - +#ifdef EATHENA_SUPPORT #include "net/messageout.h" -#include "net/protocol.h" +#include "net/ea/protocol.h" +#endif + +#include "resources/animation.h" +#include "resources/imageset.h" +#include "resources/resourcemanager.h" -#include "utils/tostring.h" #include "utils/gettext.h" +#include "utils/stringutils.h" +#ifdef TMWSERV_SUPPORT const short walkingKeyboardDelay = 100; +#endif LocalPlayer *player_node = NULL; +static const int NAME_X_OFFSET = 15; +static const int NAME_Y_OFFSET = 30; + +#ifdef TMWSERV_SUPPORT LocalPlayer::LocalPlayer(): Player(65535, 0, NULL), - mInventory(new Inventory), mEquipment(new Equipment), mAttributeBase(NB_CHARACTER_ATTRIBUTES, -1), mAttributeEffective(NB_CHARACTER_ATTRIBUTES, -1), @@ -59,32 +79,114 @@ LocalPlayer::LocalPlayer(): mExpNext(CHAR_SKILL_NB, -1), mCharacterPoints(-1), mCorrectionPoints(-1), - mLevel(1), mLevelProgress(0), + mLevelProgress(0), +#else +LocalPlayer::LocalPlayer(Uint32 id, Uint16 job, Map *map): + Player(id, job, map), + mCharId(0), + mJobXp(0), + mJobLevel(0), + mXpForNextLevel(0), mJobXpForNextLevel(0), + mMp(0), mMaxMp(0), + mAttackRange(0), + ATK(0), MATK(0), DEF(0), MDEF(0), HIT(0), FLEE(0), + ATK_BONUS(0), MATK_BONUS(0), DEF_BONUS(0), MDEF_BONUS(0), FLEE_BONUS(0), + mStatPoint(0), mSkillPoint(0), + mStatsPointsToAttribute(0), + mEquipment(new Equipment), + mNetwork(0), + mXp(0), + mInStorage(false), + mTargetTime(-1), + mLastTarget(-1), +#endif + mLevel(1), mMoney(0), mTotalWeight(1), mMaxWeight(1), - mHP(1), mMaxHP(1), + mHp(1), mMaxHp(1), mTarget(NULL), mPickUpTarget(NULL), mTrading(false), mGoingToTarget(false), mLastAction(-1), mWalkingDir(0), mDestX(0), mDestY(0), +#ifdef TMWSERV_SUPPORT mLocalWalkTime(-1), - mExpMessageTime(0) +#endif + mInventory(new Inventory(INVENTORY_SIZE)) +#ifdef EATHENA_SUPPORT + , mStorage(new Inventory(STORAGE_SIZE)) +#else + , mExpMessageTime(0) +#endif { + // Variable to keep the local player from doing certain actions before a map + // is initialized. e.g. drawing a player's name using the TextManager, since + // it appears to be dependant upon map coordinates for updating drawing. + mMapInitialized = false; + + mUpdateName = true; + + initTargetCursor(); } LocalPlayer::~LocalPlayer() { delete mInventory; +#ifdef EATHENA_SUPPORT + delete mStorage; +#endif + + for (int i = Being::TC_SMALL; i < Being::NUM_TC; i++) + { + delete mTargetCursor[0][i]; + delete mTargetCursor[1][i]; + mTargetCursorImages[0][i]->decRef(); + mTargetCursorImages[1][i]->decRef(); + } } void LocalPlayer::logic() { +#ifdef EATHENA_SUPPORT + switch (mAction) { + case STAND: + break; + + case SIT: + break; + + case DEAD: + break; + + case HURT: + break; + + case WALK: + mFrame = (get_elapsed_time(mWalkTime) * 6) / getWalkSpeed(); + if (mFrame >= 6) + nextStep(); + break; + + case ATTACK: + int frames = 4; + if (mEquippedWeapon && + mEquippedWeapon->getAttackType() == ACTION_ATTACK_BOW) + frames = 5; + + mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed; + + if (mFrame >= frames) + nextStep(); + + break; + } +#endif + // Actions are allowed once per second - if (get_elapsed_time(mLastAction) >= 1000) { + if (get_elapsed_time(mLastAction) >= 1000) mLastAction = -1; - } +#ifdef TMWSERV_SUPPORT // Show XP messages if (!mExpMessages.empty()) { @@ -93,7 +195,7 @@ void LocalPlayer::logic() const Vector &pos = getPosition(); particleEngine->addTextRiseFadeOutEffect(mExpMessages.front(), 0, 128, 255, - speechFont, + gui->getFont(), (int) pos.x + 16, (int) pos.y - 16); mExpMessages.pop_front(); @@ -101,10 +203,63 @@ void LocalPlayer::logic() } mExpMessageTime--; } +#else + // 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) + { + // Find whether target is in range + const int rangeX = abs(mTarget->mX - mX); + const int rangeY = abs(mTarget->mY - mY); + const int attackRange = getAttackRange(); + const int inRange = rangeX > attackRange || rangeY > attackRange ? 1 : 0; + + mTarget->setTargetAnimation( + mTargetCursor[inRange][mTarget->getTargetCursorSize()]); + + if (mTarget->mAction == DEAD) + stopAttack(); + + if (mKeepAttacking && mTarget) + attack(mTarget, true); + } +#endif Being::logic(); } +void LocalPlayer::setGM() +{ + mIsGM = !mIsGM; + mNameColor = mIsGM ? 0x009000: 0x202020; + setName(getName()); + config.setValue(getName() + "GMassert", mIsGM); +} + +void LocalPlayer::setName(const std::string &name) +{ + if (mName) + { + delete mName; + mName = 0; + } + + if (config.getValue("showownname", false) && mMapInitialized) + Player::setName(name); + else + Being::setName(name); +} + void LocalPlayer::nextStep() { // TODO: Fix picking up when reaching target (this method is obsolete) @@ -112,21 +267,19 @@ void LocalPlayer::nextStep() if (mPath.empty()) { if (mPickUpTarget) - { pickUp(mPickUpTarget); - } if (mWalkingDir) - { walk(mWalkingDir); - } } // TODO: Fix automatically walking within range of target, when wanted if (mGoingToTarget && mTarget && withinAttackRange(mTarget)) { mAction = Being::STAND; - //attack(mTarget, true); +#ifdef EATHENA_SUPPORT + attack(mTarget, true); +#endif mGoingToTarget = false; mPath.clear(); return; @@ -136,8 +289,13 @@ void LocalPlayer::nextStep() mGoingToTarget = false; mPath.clear(); } + +#ifdef EATHENA_SUPPORT + Player::nextStep(); +#endif } +#ifdef TMWSERV_SUPPORT bool LocalPlayer::checkInviteRights(const std::string &guildName) { Guild *guild = getGuild(guildName); @@ -181,34 +339,35 @@ void LocalPlayer::setInvItem(int index, int id, int amount) mInventory->setItem(index, id, amount); } +#endif + void LocalPlayer::moveInvItem(Item *item, int newIndex) { // special case, the old and new cannot copy over each other. if (item->getInvIndex() == newIndex) return; +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::moveItem( item->getInvIndex(), newIndex, item->getQuantity()); -} - -Item* LocalPlayer::searchForItem(int itemId) -{ - for (int i = 0; i < INVENTORY_SIZE; i++) - { - if (Item *item = mInventory->getItem(i)) { - if (item->getId() == itemId) { - return item; - } - } - } - return NULL; +#endif + // TODO: eAthena support } void LocalPlayer::equipItem(Item *item) { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::equip(item->getInvIndex()); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_EQUIP); + outMsg.writeInt16(item->getInvIndex()); + outMsg.writeInt16(0); +#endif } +#ifdef TMWSERV_SUPPORT + void LocalPlayer::unequipItem(int slot) { Net::GameServer::Player::unequip(slot); @@ -222,11 +381,46 @@ void LocalPlayer::useItem(int slot) Net::GameServer::Player::useItem(slot); } +#else + +void LocalPlayer::unequipItem(Item *item) +{ + if (!item) + return; + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_UNEQUIP); + outMsg.writeInt16(item->getInvIndex()); + + // Tidy equipment directly to avoid weapon still shown bug, for instance + mEquipment->removeEquipment(item->getInvIndex()); +} + +void LocalPlayer::useItem(Item *item) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_INVENTORY_USE); + outMsg.writeInt16(item->getInvIndex()); + outMsg.writeInt32(item->getId()); + // Note: id is dest of item, usually player_node->account_ID ?? +} + +#endif + void LocalPlayer::dropItem(Item *item, int quantity) { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::drop(item->getInvIndex(), quantity); +#else + // TODO: Fix wrong coordinates of drops, serverside? + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_INVENTORY_DROP); + outMsg.writeInt16(item->getInvIndex()); + outMsg.writeInt16(quantity); +#endif } +#ifdef TMWSERV_SUPPORT void LocalPlayer::splitItem(Item *item, int quantity) { int newIndex = mInventory->getFreeSlot(); @@ -236,39 +430,68 @@ void LocalPlayer::splitItem(Item *item, int quantity) item->getInvIndex(), newIndex, quantity); } } +#endif void LocalPlayer::pickUp(FloorItem *item) { +#ifdef TMWSERV_SUPPORT int dx = item->getX() - (int) getPosition().x / 32; int dy = item->getY() - (int) getPosition().y / 32; +#else + int dx = item->getX() - mX; + int dy = item->getY() - mY; +#endif - if (dx * dx + dy * dy < 4) { + if (dx * dx + dy * dy < 4) + { +#ifdef TMWSERV_SUPPORT int id = item->getId(); Net::GameServer::Player::pickUp(id >> 16, id & 0xFFFF); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_ITEM_PICKUP); + outMsg.writeInt32(item->getId()); +#endif mPickUpTarget = NULL; - } else { + } + else + { +#ifdef TMWSERV_SUPPORT setDestination(item->getX() * 32 + 16, item->getY() * 32 + 16); +#else + setDestination(item->getX(), item->getY()); +#endif mPickUpTarget = item; +#ifdef EATHENA_SUPPORT + stopAttack(); +#endif } } void LocalPlayer::walk(unsigned char dir) { - // TODO: Evaluate the implementation of this method + // TODO: Evaluate the implementation of this method for tmwserv if (!mMap || !dir) return; +#ifdef TMWSERV_SUPPORT const Vector &pos = getPosition(); int dScaler; // Distance to walk +#endif if (mAction == WALK && !mPath.empty()) { // Just finish the current action, otherwise we get out of sync +#ifdef TMWSERV_SUPPORT Being::setDestination(pos.x, pos.y); +#else + Being::setDestination(mX, mY); +#endif return; } int dx = 0, dy = 0; +#ifdef TMWSERV_SUPPORT if (dir & UP) dy -= 32; if (dir & DOWN) @@ -277,17 +500,35 @@ void LocalPlayer::walk(unsigned char dir) dx -= 32; if (dir & RIGHT) dx += 32; +#else + if (dir & UP) + dy--; + if (dir & DOWN) + dy++; + if (dir & LEFT) + dx--; + if (dir & RIGHT) + dx++; +#endif // Prevent skipping corners over colliding tiles +#ifdef TMWSERV_SUPPORT if (dx && !mMap->getWalk(((int) pos.x + dx) / 32, (int) pos.y / 32, getWalkMask())) dx = 16 - (int) pos.x % 32; if (dy && !mMap->getWalk((int) pos.x / 32, ((int) pos.y + dy) / 32, getWalkMask())) dy = 16 - (int) pos.y % 32; +#else + if (dx && !mMap->getWalk(mX + dx, mY, getWalkMask())) + dx = 0; + if (dy && !mMap->getWalk(mX, mY + dy, getWalkMask())) + dy = 0; +#endif // Choose a straight direction when diagonal target is blocked +#ifdef TMWSERV_SUPPORT if (dx && dy && !mMap->getWalk((pos.x + dx) / 32, (pos.y + dy) / 32, getWalkMask())) dx = 16 - (int) pos.x % 32; @@ -309,16 +550,74 @@ void LocalPlayer::walk(unsigned char dir) { setDestination((int) pos.x + (dx * dScaler), (int) pos.y + (dy * dScaler)); } +#else + if (dx && dy && !mMap->getWalk(mX + dx, mY + dy, getWalkMask())) + dx = 0; + + // Walk to where the player can actually go + if ((dx || dy) && mMap->getWalk(mX + dx, mY + dy, getWalkMask())) + { + setDestination(mX + dx, mY + dy); + } +#endif else if (dir) { // If the being can't move, just change direction +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::changeDir(dir); +#else + // TODO: Communicate this to the server +#endif setDirection(dir); } } +Being* LocalPlayer::getTarget() const +{ + return mTarget; +} + +void LocalPlayer::setTarget(Being *target) +{ +#ifdef EATHENA_SUPPORT + if (mLastTarget != -1 || target == this) + return; + + mLastTarget = tick_time; + + if (target == mTarget) + target = NULL; + + if (target || mAction == ATTACK) + { + mTargetTime = tick_time; + } + else + { + mKeepAttacking = false; + mTargetTime = -1; + } +#endif + + if (mTarget) + mTarget->untarget(); + + if (mTarget && mTarget->getType() == Being::MONSTER) + static_cast<Monster *>(mTarget)->showName(false); + + mTarget = target; + + if (target && target->getType() == Being::MONSTER) + static_cast<Monster *>(target)->showName(true); +} + +#ifdef TMWSERV_SUPPORT +void LocalPlayer::setDestination(int x, int y) +#else void LocalPlayer::setDestination(Uint16 x, Uint16 y) +#endif { +#ifdef TMWSERV_SUPPORT // Fix coordinates so that the player does not seem to dig into walls. const int tx = x / 32; const int ty = y / 32; @@ -336,15 +635,25 @@ void LocalPlayer::setDestination(Uint16 x, Uint16 y) x = tx * 32 + fx; y = ty * 32 + fy; +#endif + // Only send a new message to the server when destination changes if (x != mDestX || y != mDestY) { mDestX = x; mDestY = y; +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::walk(x, y); //Debugging fire burst effectManager->trigger(15,x,y); +#else + char temp[4] = ""; + MessageOut outMsg(mNetwork); + set_coordinates(temp, x, y, mDirection); + outMsg.writeInt16(0x0085); + outMsg.writeString(temp, 3); +#endif } mPickUpTarget = NULL; @@ -357,12 +666,16 @@ void LocalPlayer::setWalkingDir(int dir) // If we're not already walking, start walking. if (mAction != WALK && dir - && get_elapsed_time(mLocalWalkTime) >= walkingKeyboardDelay) +#ifdef TMWSERV_SUPPORT + && get_elapsed_time(mLocalWalkTime) >= walkingKeyboardDelay +#endif + ) { walk(dir); } } +#ifdef TMWSERV_SUPPORT void LocalPlayer::stopWalking(bool sendToServer) { if (mAction == WALK && mWalkingDir) { @@ -376,6 +689,53 @@ void LocalPlayer::stopWalking(bool sendToServer) clearPath(); } +#endif + +#ifdef EATHENA_SUPPORT +void LocalPlayer::raiseAttribute(Attribute attr) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_STAT_UPDATE_REQUEST); + + switch (attr) + { + case STR: + outMsg.writeInt16(0x000d); + break; + + case AGI: + outMsg.writeInt16(0x000e); + break; + + case VIT: + outMsg.writeInt16(0x000f); + break; + + case INT: + outMsg.writeInt16(0x0010); + break; + + case DEX: + outMsg.writeInt16(0x0011); + break; + + case LUK: + outMsg.writeInt16(0x0012); + break; + } + outMsg.writeInt8(1); +} + +void LocalPlayer::raiseSkill(Uint16 skillId) +{ + if (mSkillPoint <= 0) + return; + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_SKILL_LEVELUP_REQUEST); + outMsg.writeInt16(skillId); +} +#endif void LocalPlayer::toggleSit() { @@ -386,13 +746,20 @@ void LocalPlayer::toggleSit() Being::Action newAction; switch (mAction) { - case Being::STAND: newAction = Being::SIT; break; - case Being::SIT: newAction = Being::STAND; break; + case STAND: newAction = SIT; break; + case SIT: newAction = STAND; break; default: return; } +#ifdef TMWSERV_SUPPORT setAction(newAction); Net::GameServer::Player::changeAction(newAction); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0089); + outMsg.writeInt32(0); + outMsg.writeInt8((newAction == SIT) ? 2 : 3); +#endif } void LocalPlayer::emote(Uint8 emotion) @@ -402,19 +769,38 @@ void LocalPlayer::emote(Uint8 emotion) mLastAction = tick_time; // XXX Convert for new server - /* - MessageOut outMsg(0x00bf); +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x00bf); outMsg.writeInt8(emotion); - */ +#endif } +#ifdef EATHENA_SUPPORT +void LocalPlayer::tradeReply(bool accept) +{ + if (!accept) + mTrading = false; + + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_RESPONSE); + outMsg.writeInt8(accept ? 3 : 4); +} +#endif + void LocalPlayer::trade(Being *being) const { +#ifdef TMWSERV_SUPPORT extern std::string tradePartnerName; extern int tradePartnerID; tradePartnerName = being->getName(); tradePartnerID = being->getId(); Net::GameServer::Player::requestTrade(tradePartnerID); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_TRADE_REQUEST); + outMsg.writeInt32(being->getId()); +#endif } bool LocalPlayer::tradeRequestOk() const @@ -422,6 +808,8 @@ bool LocalPlayer::tradeRequestOk() const return !mTrading; } +#ifdef TMWSERV_SUPPORT + void LocalPlayer::attack() { if (mLastAction != -1) @@ -477,20 +865,97 @@ void LocalPlayer::useSpecial(int special) Net::GameServer::Player::useSpecial(special); } -Being* LocalPlayer::getTarget() const +#else + +void LocalPlayer::attack(Being *target, bool keep) { - return mTarget; + mKeepAttacking = keep; + + if (!target) + return; + + if ((mTarget != target) || !mTarget) + { + mLastTarget = -1; + setTarget(target); + } + + 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) + setDirection(DOWN); + else + setDirection(UP); + } + else + { + if (dist_x > 0) + setDirection(RIGHT); + else + setDirection(LEFT); + } + + // Implement charging attacks here + mLastAttackTime = 0; + + mWalkTime = tick_time; + mTargetTime = tick_time; + + setAction(ATTACK); + + if (mEquippedWeapon) + { + std::string soundFile = mEquippedWeapon->getSound(EQUIP_EVENT_STRIKE); + if (!soundFile.empty()) + sound.playSfx(soundFile); + } + else + { + sound.playSfx("sfx/fist-swish.ogg"); + } + + MessageOut outMsg(mNetwork); + 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; } +#endif // no TMWSERV_SUPPORT + void LocalPlayer::revive() { // XXX Convert for new server - /* - MessageOut outMsg(0x00b2); +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x00b2); outMsg.writeInt8(0); - */ +#endif } +#ifdef TMWSERV_SUPPORT + void LocalPlayer::raiseAttribute(size_t attr) { // we assume that the server allows the change. When not we will undo it later. @@ -556,8 +1021,28 @@ std::pair<int, int> LocalPlayer::getExperience(int skill) return std::pair<int, int> (mExpCurrent.at(skill), mExpNext.at(skill)); } +#else + +void LocalPlayer::setXp(int xp) +{ + if (mMap && xp > mXp) + { + const std::string text = toString(xp - mXp) + " xp"; + + // Show XP number + particleEngine->addTextRiseFadeOutEffect(text, + 255, 255, 0, + hitYellowFont, + mPx + 16, mPy - 16); + } + mXp = xp; +} + +#endif + int LocalPlayer::getAttackRange() { +#ifdef TMWSERV_SUPPORT Item *weapon = mEquipment->getEquipment(EQUIP_FIGHT1_SLOT); if (weapon) { @@ -565,10 +1050,14 @@ int LocalPlayer::getAttackRange() return info.getAttackRange(); } return 32; // unarmed range +#else + return mAttackRange; +#endif } bool LocalPlayer::withinAttackRange(Being *target) { +#ifdef TMWSERV_SUPPORT const Vector &targetPos = target->getPosition(); const Vector &pos = getPosition(); const int dx = abs(targetPos.x - pos.x); @@ -576,12 +1065,119 @@ bool LocalPlayer::withinAttackRange(Being *target) const int range = getAttackRange(); return !(dx > range || dy > range); +#else + int dist_x = abs(target->mX - mX); + int dist_y = abs(target->mY - mY); + + if (dist_x > getAttackRange() || dist_y > getAttackRange()) + { + return false; + } + + return true; +#endif } void LocalPlayer::setGotoTarget(Being *target) { +#ifdef TMWSERV_SUPPORT mTarget = target; mGoingToTarget = true; const Vector &targetPos = target->getPosition(); setDestination(targetPos.x, targetPos.y); +#else + mLastTarget = -1; + setTarget(target); + mGoingToTarget = true; + setDestination(target->mX, target->mY); +#endif } + + +extern MiniStatusWindow *miniStatusWindow; + +void LocalPlayer::handleStatusEffect(StatusEffect *effect, int effectId) +{ + Being::handleStatusEffect(effect, effectId); + + + + if (effect) { + effect->deliverMessage(); + effect->playSFX(); + + AnimatedSprite *sprite = effect->getIcon(); + + if (!sprite) { + // delete sprite, if necessary + for (unsigned int i = 0; i < mStatusEffectIcons.size();) + if (mStatusEffectIcons[i] == effectId) { + mStatusEffectIcons.erase(mStatusEffectIcons.begin() + i); + miniStatusWindow->eraseIcon(i); + } else i++; + } else { + // replace sprite or append + bool found = false; + + for (unsigned int i = 0; i < mStatusEffectIcons.size(); i++) + if (mStatusEffectIcons[i] == effectId) { + miniStatusWindow->setIcon(i, sprite); + found = true; + break; + } + + if (!found) { // add new + int offset = mStatusEffectIcons.size(); + miniStatusWindow->setIcon(offset, sprite); + mStatusEffectIcons.push_back(effectId); + } + } + } +} + +void LocalPlayer::initTargetCursor() +{ + // Load target cursors + loadTargetCursor("graphics/gui/target-cursor-blue-s.png", 44, 35, + false, TC_SMALL); + loadTargetCursor("graphics/gui/target-cursor-red-s.png", 44, 35, + true, TC_SMALL); + loadTargetCursor("graphics/gui/target-cursor-blue-m.png", 62, 44, + false, TC_MEDIUM); + loadTargetCursor("graphics/gui/target-cursor-red-m.png", 62, 44, + true, TC_MEDIUM); + loadTargetCursor("graphics/gui/target-cursor-blue-l.png", 82, 60, + false, TC_LARGE); + loadTargetCursor("graphics/gui/target-cursor-red-l.png", 82, 60, + true, TC_LARGE); +} + +void LocalPlayer::loadTargetCursor(std::string filename, int width, int height, + bool outRange, TargetCursorSize size) +{ + assert(size > -1); + assert(size < 3); + + ImageSet* currentImageSet; + SimpleAnimation* currentCursor; + + ResourceManager *resman = ResourceManager::getInstance(); + + currentImageSet = resman->getImageSet(filename, width, height); + Animation *anim = new Animation; + + for (unsigned int i = 0; i < currentImageSet->size(); ++i) + { + anim->addFrame(currentImageSet->get(i), 75, + (16 - (currentImageSet->getWidth() / 2)), + (16 - (currentImageSet->getHeight() / 2))); + } + + currentCursor = new SimpleAnimation(anim); + + const int index = outRange ? 1 : 0; + + mTargetCursorImages[index][size] = currentImageSet; + mTargetCursor[index][size] = currentCursor; +} + diff --git a/src/localplayer.h b/src/localplayer.h index 0b9ba712..7ced3fdf 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -1,34 +1,53 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_LOCALPLAYER_H -#define _TMW_LOCALPLAYER_H +#ifndef LOCALPLAYER_H +#define LOCALPLAYER_H + +#include <memory> +#include <vector> #include "player.h" -#include <memory> +#ifdef EATHENA_SUPPORT +// TODO move into some sane place... +#define MAX_SLOT 2 +#define INVENTORY_SIZE 102 +#define STORAGE_SIZE 301 +#else +#define INVENTORY_SIZE 50 +#endif + +class Equipment; class FloorItem; +class ImageSet; class Inventory; class Item; +class Map; +#ifdef EATHENA_SUPPORT +class Network; +#endif + +#ifdef TMWSERV_SUPPORT /** * Attributes used during combat. Available to all the beings. @@ -113,26 +132,43 @@ enum NB_CHARACTER_ATTRIBUTES = CHAR_SKILL_END }; +#endif + /** * The local player character. */ class LocalPlayer : public Player { public: - enum Attribute { + enum Attribute + { +#ifdef TMWSERV_SUPPORT STR = 0, AGI, DEX, VIT, INT, WIL, CHR +#else + STR = 0, AGI, VIT, INT, DEX, LUK +#endif }; /** * Constructor. */ +#ifdef TMWSERV_SUPPORT LocalPlayer(); +#else + LocalPlayer(Uint32 id, Uint16 job, Map *map); +#endif /** * Destructor. */ ~LocalPlayer(); + virtual void setName(const std::string &name); + +#ifdef EATHENA_SUPPORT + void setNetwork(Network *network) { mNetwork = network; } + Network *getNetwork() {return mNetwork; } +#endif virtual void logic(); /** @@ -142,11 +178,18 @@ class LocalPlayer : public Player virtual void nextStep(); /** - * Draws the name text below the being. + * Returns the player's inventory. */ - virtual void - drawName(Graphics *, int, int) {}; + Inventory* getInventory() const { return mInventory; } + +#ifdef EATHENA_SUPPORT + /** + * Returns the player's storage + */ + Inventory* getStorage() const { return mStorage; } +#endif +#ifdef TMWSERV_SUPPORT /** * Check the player has permission to invite users to specific guild */ @@ -164,6 +207,7 @@ class LocalPlayer : public Player void clearInventory(); void setInvItem(int index, int id, int amount); +#endif /** * Move the Inventory item from the old slot to the new slot. @@ -171,14 +215,6 @@ class LocalPlayer : public Player void moveInvItem(Item *item, int newIndex); /** - * Searches for the specified item by it's identification. - * - * @param itemId The id of the item to be searched. - * @return Item found on success, NULL on failure. - */ - Item* searchForItem(int itemId); - - /** * Equips an item. */ void equipItem(Item *item); @@ -186,16 +222,33 @@ class LocalPlayer : public Player /** * Unequips an item. */ +#ifdef TMWSERV_SUPPORT void unequipItem(int slot); +#else + void unequipItem(Item *item); +#endif +#ifdef TMWSERV_SUPPORT void useItem(int slot); +#else + void useItem(Item *item); +#endif void dropItem(Item *item, int quantity); +#ifdef TMWSERV_SUPPORT void splitItem(Item *item, int quantity); +#endif void pickUp(FloorItem *item); +#ifdef EATHENA_SUPPORT + /** + * Sets the attack range. + */ + void setAttackRange(int range) { mAttackRange = range; } +#endif + /** * Gets the attack range. */ @@ -223,28 +276,56 @@ class LocalPlayer : public Player */ void setTrading(bool trading) { mTrading = trading; } +#ifdef TMWSERV_SUPPORT void attack(); - void useSpecial(int id); +#else + void attack(Being *target = NULL, bool keep = false); +#endif - Being* getTarget() const; + /** + * Triggers whether or not to show the name as a GM name. + * NOTE: This doesn't mean that just anyone can use this. + * If the server doesn't acknowlege you, you won't be shown + * as a GM on other people's clients. + */ + virtual void setGM(); + +#ifdef EATHENA_SUPPORT + void stopAttack(); +#endif /** * Overridden to do nothing. The attacks of the local player are * displayed as soon as the player attacks, not when the server says * the player does. + * + * @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() {} /** + * Returns the current target of the player. Returns 0 if no being is + * currently targeted. + */ + Being* getTarget() const; + + + /** * Sets the target being of the player. */ - void setTarget(Being* target) { mTarget = target; } + void setTarget(Being* target); /** * Sets a new destination for this being to walk to. */ - void setDestination(Uint16 x, Uint16 y); +#ifdef TMWSERV_SUPPORT + void setDestination(int x, int y); +#else + virtual void setDestination(Uint16 x, Uint16 y); +#endif /** * Sets a new direction to keep walking in. @@ -267,6 +348,11 @@ class LocalPlayer : public Player */ bool withinAttackRange(Being *target); +#ifdef EATHENA_SUPPORT + void raiseAttribute(Attribute attr); + void raiseSkill(Uint16 skillId); +#else + /** * Stops the player dead in his tracks */ @@ -281,23 +367,61 @@ class LocalPlayer : public Player * Uses a correction point to lower an attribute */ void lowerAttribute(size_t attr); +#endif void toggleSit(); void emote(Uint8 emotion); void revive(); - int getHP() const - { return mHP; } +#ifdef EATHENA_SUPPORT + /** + * 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. + */ + void setXp(int xp); + + /** + * Returns the amount of experience points. + */ + int getXp() const { return mXp; } + + Uint32 mCharId; /**< Used only during character selection. */ + + Uint32 mJobXp; + Uint32 mJobLevel; + Uint32 mXpForNextLevel, mJobXpForNextLevel; + Uint16 mMp, mMaxMp; - int getMaxHP() const - { return mMaxHP; } + Uint16 mAttackRange; - void setHP(int value) - { mHP = value; } + Uint8 mAttr[6]; + Uint8 mAttrUp[6]; - void setMaxHP(int value) - { mMaxHP = value; } + Sint16 ATK, MATK, DEF, MDEF, HIT, FLEE; + Sint16 ATK_BONUS, MATK_BONUS, DEF_BONUS, MDEF_BONUS, FLEE_BONUS; + + Uint16 mStatPoint, mSkillPoint; + Uint16 mStatsPointsToAttribute; +#endif + + int getHp() const + { return mHp; } + + int getMaxHp() const + { return mMaxHp; } + + void setHp(int value) + { mHp = value; } + + void setMaxHp(int value) + { mMaxHp = value; } int getLevel() const { return mLevel; } @@ -305,11 +429,13 @@ class LocalPlayer : public Player void setLevel(int value) { mLevel = value; } +#ifdef TMWSERV_SUPPORT void setLevelProgress(int percent) { mLevelProgress = percent; } int getLevelProgress() const { return mLevelProgress; } +#endif int getMoney() const { return mMoney; } @@ -320,9 +446,16 @@ class LocalPlayer : public Player int getTotalWeight() const { return mTotalWeight; } + void setTotalWeight(int value) + { mTotalWeight = value; } + int getMaxWeight() const { return mMaxWeight; } + void setMaxWeight(int value) + { mMaxWeight = value; } + +#ifdef TMWSERV_SUPPORT int getAttributeBase(int num) const { return mAttributeBase[num]; } @@ -357,14 +490,31 @@ class LocalPlayer : public Player static const SkillInfo& getSkillInfo(int skill); std::pair<int, int> getExperience(int skill); +#endif + bool mUpdateName; /** Whether or not the name settings have changed */ + + bool mMapInitialized; /** Whether or not the map is available yet */ + + float mLastAttackTime; /**< Used to synchronize the charge dialog */ - Inventory *mInventory; const std::auto_ptr<Equipment> mEquipment; protected: + virtual void + handleStatusEffect(StatusEffect *effect, int effectId); + void walk(unsigned char dir); +#ifdef EATHENA_SUPPORT + Network *mNetwork; + int mXp; /**< Experience points. */ + bool mInStorage; /**< Whether storage is currently accessible */ + int mTargetTime; /** How long the being has been targeted **/ + int mLastTarget; /** Time stamp of last targeting action, -1 if none. */ +#endif + +#ifdef TMWSERV_SUPPORT // Character status: std::vector<int> mAttributeBase; std::vector<int> mAttributeEffective; @@ -372,29 +522,56 @@ class LocalPlayer : public Player std::vector<int> mExpNext; int mCharacterPoints; int mCorrectionPoints; - int mLevel; int mLevelProgress; +#endif + int mLevel; int mMoney; int mTotalWeight; int mMaxWeight; - int mHP; - int mMaxHP; + int mHp; + int mMaxHp; Being *mTarget; FloorItem *mPickUpTarget; bool mTrading; bool mGoingToTarget; - int mLastAction; /**< Time stamp of the last action, -1 if none. */ - int mWalkingDir; /**< The direction the player is walking in. */ - int mDestX; /**< X coordinate of destination. */ - int mDestY; /**< Y coordinate of destination. */ + bool mKeepAttacking; /** Whether or not to continue to attack */ + int mLastAction; /**< Time stamp of the last action, -1 if none. */ + int mWalkingDir; /**< The direction the player is walking in. */ + int mDestX; /**< X coordinate of destination. */ + int mDestY; /**< Y coordinate of destination. */ +#ifdef TMWSERV_SUPPORT int mLocalWalkTime; /**< Timestamp used to control keyboard walk messages flooding */ +#endif + + std::vector<int> mStatusEffectIcons; + Inventory *mInventory; +#ifdef EATHENA_SUPPORT + Inventory *mStorage; +#endif + + // Load the target cursors into memory + void initTargetCursor(); + + /** + * Helper function for loading target cursors + */ + void loadTargetCursor(std::string filename, int width, int height, + bool outRange, Being::TargetCursorSize size); + + /** Images of the target cursor. */ + ImageSet *mTargetCursorImages[2][NUM_TC]; + + /** Animated target cursors. */ + SimpleAnimation *mTargetCursor[2][NUM_TC]; + +#ifdef TMWSERV_SUPPORT std::list<std::string> mExpMessages; /**< Queued exp messages*/ int mExpMessageTime; - +#endif }; extern LocalPlayer *player_node; diff --git a/src/lockedarray.h b/src/lockedarray.h index 8e525191..c4c83ea9 100644 --- a/src/lockedarray.h +++ b/src/lockedarray.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_LOCKEDARRAY_H -#define _TMW_LOCKEDARRAY_H +#ifndef LOCKEDARRAY_H +#define LOCKEDARRAY_H #include <algorithm> diff --git a/src/log.cpp b/src/log.cpp index 96630a96..b0024f80 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,26 +1,24 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <cstdarg> -#include <cstdlib> #include <iostream> #include <sstream> @@ -1,28 +1,27 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LOG_H #define _LOG_H -#include <iosfwd> #include <fstream> class ChatWindow; diff --git a/src/logindata.h b/src/logindata.h index c386f490..ae89eb5f 100644 --- a/src/logindata.h +++ b/src/logindata.h @@ -1,26 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_LOGINDATA_H -#define _TMW_LOGINDATA_H +#ifndef LOGINDATA_H +#define LOGINDATA_H + +#include <string> #include <string> @@ -31,10 +33,19 @@ struct LoginData std::string newPassword; std::string hostname; std::string updateHost; +#ifdef TMWSERV_SUPPORT std::string email; std::string newEmail; +#endif short port; +#ifdef EATHENA_SUPPORT + int account_ID; + int session_ID1; + int session_ID2; + char sex; +#endif + bool remember; /**< Whether to store the username and host. */ bool registerLogin; /**< Whether an account is being registered. */ @@ -45,10 +56,19 @@ struct LoginData newPassword.clear(); hostname.clear(); updateHost.clear(); +#ifdef TMWSERV_SUPPORT email.clear(); newEmail.clear(); +#endif port = 0; + +#ifdef EATHENA_SUPPORT + account_ID = 0; + session_ID1 = 0; + session_ID2 = 0; + sex = 0; +#endif }; }; -#endif // _TMW_LOGINDATA_H +#endif // LOGINDATA_H diff --git a/src/main.cpp b/src/main.cpp index 39a0fb37..7d623f69 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,26 +1,24 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "main.h" - #include <getopt.h> #include <iostream> #include <physfs.h> @@ -33,68 +31,123 @@ #include <libxml/parser.h> -#ifdef WIN32 -#include <SDL_syswm.h> -#endif -#ifndef WIN32 -#include <cerrno> -#include <sys/stat.h> -#endif -#if defined __APPLE__ -#include <CoreFoundation/CFBundle.h> -#endif +#include <SDL/SDL_ttf.h> #include "configuration.h" -#include "keyboardconfig.h" +#include "emoteshortcut.h" #include "game.h" #include "graphics.h" #include "itemshortcut.h" -#include "lockedarray.h" +#include "keyboardconfig.h" #include "localplayer.h" +#include "lockedarray.h" #include "log.h" #include "logindata.h" +#include "main.h" #ifdef USE_OPENGL #include "openglgraphics.h" #endif +#include "player_relations.h" +#include "serverinfo.h" #include "sound.h" +#include "units.h" +#include "gui/button.h" +#ifdef EATHENA_SUPPORT +#include "gui/char_server.h" +#endif #include "gui/char_select.h" -#include "gui/connection.h" +#include "gui/color.h" #include "gui/gui.h" #include "gui/login.h" #include "gui/ok_dialog.h" #include "gui/progressbar.h" -#include "gui/quitdialog.h" #include "gui/register.h" #include "gui/sdlinput.h" +#include "gui/setup.h" +#ifdef TMWSERV_SUPPORT +#include "gui/connection.h" +#include "gui/quitdialog.h" #include "gui/serverdialog.h" -#include "gui/textfield.h" +#endif #include "gui/updatewindow.h" +#ifdef TMWSERV_SUPPORT #include "net/charserverhandler.h" #include "net/connection.h" #include "net/loginhandler.h" -#include "net/logouthandler.h" #include "net/network.h" +#else +#include "net/ea/charserverhandler.h" +#include "net/ea/loginhandler.h" +#include "net/ea/network.h" +#include "net/ea/maploginhandler.h" +#include "net/messageout.h" +#endif +#include "net/logouthandler.h" +#ifdef TMWSERV_SUPPORT #include "net/accountserver/accountserver.h" #include "net/accountserver/account.h" #include "net/chatserver/chatserver.h" #include "net/gameserver/gameserver.h" +#endif +#include "resources/colordb.h" +#include "resources/emotedb.h" #include "resources/image.h" #include "resources/itemdb.h" #include "resources/monsterdb.h" #include "resources/npcdb.h" #include "resources/resourcemanager.h" +#ifdef TMWSERV_SUPPORT #include "utils/dtor.h" +#endif #include "utils/gettext.h" -#include "utils/tostring.h" +#include "utils/stringutils.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 +{ + Window *setupWindow = 0; + + struct SetupListener : public gcn::ActionListener + { + /** + * Called when receiving actions from widget. + */ + void action(const gcn::ActionEvent &event); + } listener; +} + +#ifdef TMWSERV_SUPPORT std::string token; //used to store magic_token +#else +// Account infos +char n_server, n_character; + +// TODO Anyone knows a good location for this? Or a way to make it non-global? +class SERVER_INFO; +SERVER_INFO **server_info; +#endif Graphics *graphics; @@ -109,24 +162,34 @@ Configuration branding; /**< XML branding information reader */ Logger *logger; /**< Log object */ KeyboardConfig keyboard; +#ifdef TMWSERV_SUPPORT Net::Connection *gameServerConnection = 0; Net::Connection *chatServerConnection = 0; +Net::Connection *accountServerConnection = 0; +#endif CharServerHandler charServerHandler; LoginData loginData; +#ifdef TMWSERV_SUPPORT LoginHandler loginHandler; LogoutHandler logoutHandler; +#endif LockedArray<LocalPlayer*> charInfo(maxSlot + 1); +Color *textColor; + // This anonymous namespace hides whatever is inside from other modules. namespace { -Net::Connection *accountServerConnection = 0; - std::string homeDir; std::string updateHost; std::string updatesDir; +#ifdef EATHENA_SUPPORT +LoginHandler loginHandler; +MapLoginHandler mapLoginHandler; +#endif + /** * A structure holding the values of various options that can be passed from * the command line. @@ -140,12 +203,14 @@ struct Options printHelp(false), printVersion(false), skipUpdate(false), + chooseDefault(false), serverPort(0) {}; bool printHelp; bool printVersion; bool skipUpdate; + bool chooseDefault; std::string username; std::string password; std::string character; @@ -157,18 +222,19 @@ struct Options short serverPort; }; -} // anonymous namespace - /** * Parse the update host and determine the updates directory * Then verify that the directory exists (creating if needed). */ void setUpdatesDir() { + std::stringstream updates; + // If updatesHost is currently empty, fill it from config file - if (updateHost.empty()) { + if (updateHost.empty()) + { updateHost = - config.getValue("updatehost", "http://updates.themanaworld.org"); + config.getValue("updatehost", "http://updates.themanaworld.org/"); } // Remove any trailing slash at the end of the update host @@ -178,29 +244,59 @@ void setUpdatesDir() // Parse out any "http://" or "ftp://", and set the updates directory size_t pos; pos = updateHost.find("://"); - if (pos != updateHost.npos) { - if (pos + 3 < updateHost.length()) { - updatesDir = - "updates/" + updateHost.substr(pos + 3); - } else { + if (pos != updateHost.npos) + { + if (pos + 3 < updateHost.length()) + { + updates << "updates/" << updateHost.substr(pos + 3) + << "/" << loginData.port; + updatesDir = updates.str(); + } + else + { logger->log("Error: Invalid update host: %s", updateHost.c_str()); - errorMessage = "Invalid update host: " + updateHost; + errorMessage = _("Invalid update host: ") + updateHost; state = STATE_ERROR; } - } else { + } + else + { logger->log("Warning: no protocol was specified for the update host"); - updatesDir = "updates/" + updateHost; + updates << "updates/" << updateHost << "/" << loginData.port; + updatesDir = updates.str(); } ResourceManager *resman = ResourceManager::getInstance(); // Verify that the updates directory exists. Create if necessary. - if (!resman->isDirectory("/" + updatesDir)) { - if (!resman->mkdir("/" + updatesDir)) { + if (!resman->isDirectory("/" + updatesDir)) + { + if (!resman->mkdir("/" + updatesDir)) + { +#if defined WIN32 + std::string newDir = homeDir + "\\" + updatesDir; + std::string::size_type loc = newDir.find("/", 0); + + while (loc != std::string::npos) + { + newDir.replace(loc, 1, "\\"); + loc = newDir.find("/", loc); + } + + if (!CreateDirectory(newDir.c_str(), 0) && + GetLastError() != ERROR_ALREADY_EXISTS) + { + logger->log("Error: %s can't be made, but doesn't exist!", + newDir.c_str()); + errorMessage = _("Error creating updates directory!"); + state = STATE_ERROR; + } +#else logger->log("Error: %s/%s can't be made, but doesn't exist!", - homeDir.c_str(), updatesDir.c_str()); - errorMessage = "Error creating updates directory!"; + homeDir.c_str(), updatesDir.c_str()); + errorMessage = _("Error creating updates directory!"); state = STATE_ERROR; +#endif } } } @@ -231,7 +327,7 @@ void initHomeDir() #endif { std::cout << homeDir - << " can't be created, but it doesn't exist! Exiting." + << _(" can't be created, but it doesn't exist! Exiting.") << std::endl; exit(1); } @@ -247,7 +343,11 @@ void initConfiguration(const Options &options) std::string defaultHost = branding.getValue("defaultServer", "server.themanaworld.org"); config.setValue("host", defaultHost); +#ifdef TWMSERV_SUPPORT int defaultPort = (int)branding.getValue("defaultPort", 9601); +#else + int defaultPort = (int)branding.getValue("defaultPort", 6901); +#endif config.setValue("port", defaultPort); config.setValue("hwaccel", 0); #if (defined __APPLE__ || defined WIN32) && defined USE_OPENGL @@ -270,24 +370,24 @@ void initConfiguration(const Options &options) // Checking if the configuration file exists... otherwise create it with // default options. - FILE *tmwFile = 0; + FILE *configFile = 0; std::string configPath = options.configPath; if (configPath.empty()) configPath = homeDir + "/config.xml"; - tmwFile = fopen(configPath.c_str(), "r"); + configFile = fopen(configPath.c_str(), "r"); // If we can't read it, it doesn't exist ! - if (tmwFile == NULL) { + if (configFile == NULL) { // We reopen the file in write mode and we create it - tmwFile = fopen(configPath.c_str(), "wt"); + configFile = fopen(configPath.c_str(), "wt"); } - if (tmwFile == NULL) { + if (configFile == NULL) { std::cout << "Can't create " << configPath << ". " << "Using Defaults." << std::endl; } else { - fclose(tmwFile); + fclose(configFile); config.init(configPath); } } @@ -341,7 +441,7 @@ void initEngine(const Options &options) strncat(path, "/data", PATH_MAX - 1); resman->addToSearchPath(path, true); #else - resman->addToSearchPath(TMW_DATADIR "data", true); + resman->addToSearchPath(PKG_DATADIR "data", true); #endif #ifdef WIN32 @@ -368,23 +468,23 @@ void initEngine(const Options &options) Image::setLoadAsOpenGL(useOpenGL); // Create the graphics context - graphics = useOpenGL ? new OpenGLGraphics() : new Graphics(); + graphics = useOpenGL ? new OpenGLGraphics : new Graphics; #else // Create the graphics context - graphics = new Graphics(); + graphics = new Graphics; #endif - int width = (int) config.getValue("screenwidth", defaultScreenWidth); - int height = (int) config.getValue("screenheight", defaultScreenHeight); - int bpp = 0; - bool fullscreen = ((int) config.getValue("screen", 0) == 1); - bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1); + const int width = (int) config.getValue("screenwidth", defaultScreenWidth); + const int height = (int) config.getValue("screenheight", defaultScreenHeight); + const int bpp = 0; + const bool fullscreen = ((int) config.getValue("screen", 0) == 1); + const bool hwaccel = ((int) config.getValue("hwaccel", 0) == 1); // Try to set the desired video mode if (!graphics->setVideoMode(width, height, bpp, fullscreen, hwaccel)) { - std::cerr << "Couldn't set " - << width << "x" << height << "x" << bpp << " video mode: " + std::cerr << _("Couldn't set ") + << width << "x" << height << "x" << bpp << _(" video mode: ") << SDL_GetError() << std::endl; exit(1); } @@ -393,10 +493,17 @@ void initEngine(const Options &options) graphics->_beginDraw(); // Initialize the item shortcuts. - itemShortcut = new ItemShortcut(); + itemShortcut = new ItemShortcut; + + // Initialize the emote shortcuts. + emoteShortcut = new EmoteShortcut; gui = new Gui(graphics); +#ifdef TMWSERV_SUPPORT state = STATE_CHOOSE_SERVER; /**< Initial game state */ +#else + state = STATE_LOGIN; /**< Initial game state */ +#endif // Initialize sound engine try { @@ -416,6 +523,9 @@ void initEngine(const Options &options) // Initialize keyboard keyboard.init(); + + // Initialise player relations + player_relations.init(); } /** Clear the engine */ @@ -423,6 +533,7 @@ void exit_engine() { // Before config.write() since it writes the shortcuts to the config delete itemShortcut; + delete emoteShortcut; config.write(); @@ -436,6 +547,8 @@ void exit_engine() sound.close(); // Unload XML databases + ColorDB::unload(); + EmoteDB::unload(); ItemDB::unload(); MonsterDB::unload(); NPCDB::unload(); @@ -445,73 +558,82 @@ void exit_engine() void printHelp() { - std::cout << - "tmw\n\n" - "Options:\n" - " -h --help : Display this help\n" - " -v --version : Display the version\n" - " -u --skipupdate : Skip the update process\n" - " -d --data : Directory to load game data from\n" - " -U --username : Login with this username\n" - " -P --password : Login with this password\n" - " -s --server : Login Server name or IP\n" - " -o --port : Login Server Port\n" - " -c --character : Login with this character\n" - " -C --configfile : Configuration file to use\n" - " -H --updatehost : Use this update host\n"; + std::cout + << _("tmw") << std::endl << std::endl + << _("Options: ") << std::endl + << _(" -C --configfile : Configuration file to use") << std::endl + << _(" -d --data : Directory to load game data from") << std::endl + << _(" -D --default : Bypass the login process with default settings") + << std::endl + << _(" -h --help : Display this help") << std::endl + << _(" -S --homedir : Directory to use as home directory") << std::endl + << _(" -H --updatehost : Use this update host") << std::endl + << _(" -P --password : Login with this password") << std::endl + << _(" -c --character : Login with this character") << std::endl + << _(" -o --port : Login Server Port") << std::endl + << _(" -s --server : Login Server name or IP") << std::endl + << _(" -u --skipupdate : Skip the update downloads") << std::endl + << _(" -U --username : Login with this username") << std::endl + << _(" -v --version : Display the version") << std::endl; } void printVersion() { #ifdef PACKAGE_VERSION - std::cout << "The Mana World version " << PACKAGE_VERSION << std::endl; + std::cout << _("The Mana World version ") << PACKAGE_VERSION << std::endl; #else - std::cout << "The Mana World version " << - "(local build?, PACKAGE_VERSION is not defined)" << std::endl; + std::cout << _("The Mana World version ") << + _("(local build?, PACKAGE_VERSION is not defined)") << std::endl; #endif } void parseOptions(int argc, char *argv[], Options &options) { - const char *optstring = "hvud:U:P:Dc:s:o:C:H:"; + const char *optstring = "hvud:U:P:Dc:s:o:C:H:S:"; const struct option long_options[] = { - { "help", no_argument, 0, 'h' }, - { "version", no_argument, 0, 'v' }, - { "skipupdate", no_argument, 0, 'u' }, + { "configfile", required_argument, 0, 'C' }, { "data", required_argument, 0, 'd' }, - { "username", required_argument, 0, 'U' }, + { "default", no_argument, 0, 'D' }, { "password", required_argument, 0, 'P' }, - { "server", required_argument, 0, 's' }, - { "port", required_argument, 0, 'o' }, { "character", required_argument, 0, 'c' }, - { "configfile", required_argument, 0, 'C' }, + { "help", no_argument, 0, 'h' }, + { "homedir", required_argument, 0, 'S' }, { "updatehost", required_argument, 0, 'H' }, + { "port", required_argument, 0, 'o' }, + { "server", required_argument, 0, 's' }, + { "skipupdate", no_argument, 0, 'u' }, + { "username", required_argument, 0, 'U' }, + { "version", no_argument, 0, 'v' }, { 0 } }; while (optind < argc) { + int result = getopt_long(argc, argv, optstring, long_options, NULL); if (result == -1) break; switch (result) { + case 'C': + options.configPath = optarg; + break; + case 'd': + options.dataPath = optarg; + break; + case 'D': + options.chooseDefault = true; + break; default: // Unknown option case 'h': options.printHelp = true; break; - case 'v': - options.printVersion = true; - break; - case 'u': - options.skipUpdate = true; - break; - case 'd': - options.dataPath = optarg; + case 'H': + options.updateHost = optarg; break; - case 'U': - options.username = optarg; + case 'c': + options.character = optarg; break; case 'P': options.password = optarg; @@ -522,14 +644,17 @@ void parseOptions(int argc, char *argv[], Options &options) case 'o': options.serverPort = (short)atoi(optarg); break; - case 'c': - options.character = optarg; + case 'u': + options.skipUpdate = true; break; - case 'C': - options.configPath = optarg; + case 'U': + options.username = optarg; break; - case 'H': - options.updateHost = optarg; + case 'v': + options.printVersion = true; + break; + case 'S': + homeDir = optarg; break; } } @@ -555,17 +680,19 @@ void loadUpdates() } } - -namespace { - struct ErrorListener : public gcn::ActionListener { void action(const gcn::ActionEvent &event) { +#ifdef TMWSERV_SUPPORT state = STATE_CHOOSE_SERVER; +#else + state = loginData.registerLogin ? STATE_REGISTER : STATE_LOGIN; +#endif } } errorListener; +#ifdef TMWSERV_SUPPORT struct AccountListener : public gcn::ActionListener { void action(const gcn::ActionEvent &event) @@ -581,29 +708,65 @@ struct LoginListener : public gcn::ActionListener state = STATE_LOGIN; } } loginListener; - -} // anonymous namespace +#endif // TODO Find some nice place for these functions +#ifdef TMWSERV_SUPPORT void accountLogin(LoginData *loginData) +#else +void accountLogin(Network *network, LoginData *loginData) +#endif { +#ifdef EATHENA_SUPPORT + logger->log("Trying to connect to account server..."); +#endif logger->log("Username is %s", loginData->username.c_str()); - +#ifdef EATHENA_SUPPORT + network->connect(loginData->hostname, loginData->port); + network->registerHandler(&loginHandler); +#endif loginHandler.setLoginData(loginData); +#ifdef TMWSERV_SUPPORT Net::registerHandler(&loginHandler); charServerHandler.setCharInfo(&charInfo); Net::registerHandler(&charServerHandler); +#endif // Send login infos +#ifdef TMWSERV_SUPPORT Net::AccountServer::login(accountServerConnection, 0, // client version loginData->username, loginData->password); +#else + MessageOut outMsg(network); + outMsg.writeInt16(0x0064); + outMsg.writeInt32(0); // client version + outMsg.writeString(loginData->username, 24); + outMsg.writeString(loginData->password, 24); + + /* + * eAthena calls the last byte "client version 2", but it isn't used at + * at all. We're retasking it, with bit 0 to indicate whether the client + * can handle the 0x63 "update host" packet. Clients prior to 0.0.25 send + * 0 here. + */ + outMsg.writeInt8(0x01); +#endif // Clear the password, avoids auto login when returning to login loginData->password = ""; +#ifdef EATHENA_SUPPORT + // Remove _M or _F from username after a login for registration purpose + if (loginData->registerLogin) + { + loginData->username = + loginData->username.substr(0, loginData->username.length() - 2); + } +#endif + // TODO This is not the best place to save the config, but at least better // than the login gui window if (loginData->remember) @@ -614,6 +777,66 @@ void accountLogin(LoginData *loginData) config.setValue("remember", loginData->remember); } +#ifdef EATHENA_SUPPORT + +static void positionDialog(Window *dialog, int screenWidth, int screenHeight) +{ + dialog->setPosition( + (screenWidth - dialog->getWidth()) / 2, + (screenHeight - dialog->getHeight()) / 2); +} + +void charLogin(Network *network, LoginData *loginData) +{ + logger->log("Trying to connect to char server..."); + network->connect(loginData->hostname, loginData->port); + network->registerHandler(&charServerHandler); + charServerHandler.setCharInfo(&charInfo); + charServerHandler.setLoginData(loginData); + + // Send login infos + MessageOut outMsg(network); + outMsg.writeInt16(0x0065); + outMsg.writeInt32(loginData->account_ID); + outMsg.writeInt32(loginData->session_ID1); + outMsg.writeInt32(loginData->session_ID2); + // [Fate] The next word is unused by the old char server, so we squeeze in + // tmw client version information + outMsg.writeInt16(CLIENT_PROTOCOL_VERSION); + outMsg.writeInt8(loginData->sex); + + // We get 4 useless bytes before the real answer comes in + network->skip(4); +} + +void mapLogin(Network *network, LoginData *loginData) +{ + logger->log("Memorizing selected character %s", + player_node->getName().c_str()); + config.setValue("lastCharacter", player_node->getName()); + + MessageOut outMsg(network); + + logger->log("Trying to connect to map server..."); + logger->log("Map: %s", map_path.c_str()); + + network->connect(loginData->hostname, loginData->port); + network->registerHandler(&mapLoginHandler); + + // Send login infos + outMsg.writeInt16(0x0072); + outMsg.writeInt32(loginData->account_ID); + outMsg.writeInt32(player_node->mCharId); + outMsg.writeInt32(loginData->session_ID1); + outMsg.writeInt32(loginData->session_ID2); + outMsg.writeInt8(loginData->sex); + + // We get 4 useless bytes before the real answer comes in + network->skip(4); +} + +#else + void accountRegister(LoginData *loginData) { logger->log("Username is %s", loginData->username.c_str()); @@ -748,6 +971,8 @@ void reconnectAccount(const std::string& passToken) Net::AccountServer::reconnectAccount(accountServerConnection, passToken); } +#endif + void xmlNullLogger(void *ctx, const char *msg, ...) { // Does nothing, that's the whole point of it @@ -764,479 +989,785 @@ void initXML() xmlSetGenericErrorFunc(NULL, xmlNullLogger); } +} // namespace + extern "C" char const *_nl_locale_name_default(void); /** Main */ int main(int argc, char *argv[]) { - try + // Parse command line options + Options options; + parseOptions(argc, argv, options); + if (options.printHelp) { - // Parse command line options - Options options; - parseOptions(argc, argv, options); - if (options.printHelp) - { - printHelp(); - return 0; - } - else if (options.printVersion) - { - printVersion(); - return 0; - } + printHelp(); + return 0; + } + else if (options.printVersion) + { + printVersion(); + return 0; + } #if ENABLE_NLS #ifdef WIN32 - putenv(("LANG=" + std::string(_nl_locale_name_default())).c_str()); + putenv(("LANG=" + std::string(_nl_locale_name_default())).c_str()); + // mingw doesn't like LOCALEDIR to be defined for some reason + bindtextdomain("tmw", "translations/"); +#else + bindtextdomain("tmw", LOCALEDIR); #endif - setlocale(LC_MESSAGES, ""); - bindtextdomain("tmw", LOCALEDIR); - bind_textdomain_codeset("tmw", "UTF-8"); - textdomain("tmw"); + setlocale(LC_MESSAGES, ""); + bind_textdomain_codeset("tmw", "UTF-8"); + textdomain("tmw"); #endif - // Initialize PhysicsFS - PHYSFS_init(argv[0]); + // Initialize PhysicsFS + PHYSFS_init(argv[0]); - initXML(); + initXML(); - // load branding information - branding.init("data/branding.xml"); + // load branding information + branding.init("data/branding.xml"); - initHomeDir(); - // Configure logger - logger = new Logger(); - logger->setLogFile(homeDir + std::string("/tmw.log")); - logger->setLogToStandardOut(config.getValue("logToStandardOut", 0)); + initHomeDir(); + // Configure logger + logger = new Logger(); + logger->setLogFile(homeDir + std::string("/tmw.log")); + logger->setLogToStandardOut(config.getValue("logToStandardOut", 0)); - // Log the tmw version + // Log the tmw version #ifdef PACKAGE_VERSION - logger->log("The Mana World v%s", PACKAGE_VERSION); + logger->log("The Mana World v%s", PACKAGE_VERSION); #else - logger->log("The Mana World - version not defined"); + logger->log("The Mana World - version not defined"); #endif - initConfiguration(options); + initConfiguration(options); - initEngine(options); + initEngine(options); - Game *game = NULL; - Window *currentDialog = NULL; - QuitDialog* quitDialog = NULL; - Image *login_wallpaper = NULL; + // Needs to be created in main, as the updater uses it + textColor = new Color; - gcn::Container *top = static_cast<gcn::Container*>(gui->getTop()); -#ifdef PACKAGE_VERSION - gcn::Label *versionLabel = new gcn::Label(PACKAGE_VERSION); - top->add(versionLabel, 25, 2); + Game *game = NULL; + Window *currentDialog = NULL; +#ifdef TMWSERV_SUPPORT + QuitDialog* quitDialog = NULL; #endif + Image *login_wallpaper = NULL; + setupWindow = new Setup; - sound.playMusic(branding.getValue("loginMusic", "")); - - // Server choice - if (options.serverName.empty()) { - loginData.hostname = config.getValue("MostUsedServerName0", + gcn::Container *top = static_cast<gcn::Container*>(gui->getTop()); +#ifdef PACKAGE_VERSION + gcn::Label *versionLabel = new gcn::Label(PACKAGE_VERSION); + top->add(versionLabel, 25, 2); +#endif + ProgressBar *progressBar = new ProgressBar(0.0f, 100, 20, 168, 116, 31); + gcn::Label *progressLabel = new gcn::Label(); + top->add(progressBar, 5, top->getHeight() - 5 - progressBar->getHeight()); + top->add(progressLabel, 15 + progressBar->getWidth(), + progressBar->getY() + 4); + progressBar->setVisible(false); + gcn::Button *setup = new Button(_("Setup"), "Setup", &listener); + setup->setPosition(top->getWidth() - setup->getWidth() - 3, 3); + top->add(setup); + + sound.playMusic(branding.getValue("loginMusic", "")); + + // Server choice + if (options.serverName.empty()) { + loginData.hostname = config.getValue("MostUsedServerName0", branding.getValue("defaultServer", "server.themanaworld.org").c_str()); - } - else { - loginData.hostname = options.serverName; - } - if (options.serverPort == 0) { - loginData.port = (short)config.getValue("MostUsedServerPort0", - branding.getValue("defaultPort", 9601)); - } else { - loginData.port = options.serverPort; - } + } + else { + loginData.hostname = options.serverName; + } + if (options.serverPort == 0) { + loginData.port = (short)config.getValue("MostUsedServerPort0", + branding.getValue("defaultPort", 9601)); + } else { + loginData.port = options.serverPort; + } - loginData.username = options.username; - if (loginData.username.empty()) { - if (config.getValue("remember", 0)) { - loginData.username = config.getValue("username", ""); - } - } - if (!options.password.empty()) { - loginData.password = options.password; + loginData.username = options.username; + if (loginData.username.empty()) { + if (config.getValue("remember", 0)) { + loginData.username = config.getValue("username", ""); } + } + if (!options.password.empty()) { + loginData.password = options.password; + } - loginData.remember = config.getValue("remember", 0); - loginData.registerLogin = false; +#ifdef EATHENA_SUPPORT + loginData.hostname = config.getValue("host", "server.themanaworld.org"); + loginData.port = (short)config.getValue("port", 6901); +#endif + loginData.remember = config.getValue("remember", 0); + loginData.registerLogin = false; + +#ifdef TMWSERV_SUPPORT + Net::initialize(); + accountServerConnection = Net::getConnection(); + gameServerConnection = Net::getConnection(); + chatServerConnection = Net::getConnection(); +#else + SDLNet_Init(); + Network *network = new Network; +#endif + + // Set the most appropriate wallpaper, based on screen width + int screenWidth = (int) config.getValue("screenwidth", defaultScreenWidth); +#ifdef EATHENA_SUPPORT + int screenHeight = static_cast<int>(config.getValue("screenheight", + defaultScreenHeight)); +#endif + std::string wallpaperName; + + wallpaperName = "graphics/images/login_wallpaper.png"; + if (screenWidth >= 1024 && screenWidth < 1280) + wallpaperName = "graphics/images/login_wallpaper_1024x768.png"; + else if (screenWidth >= 1280 && screenWidth < 1440) + wallpaperName = "graphics/images/login_wallpaper_1280x960.png"; + else if (screenWidth >= 1440 && screenWidth < 1600) + wallpaperName = "graphics/images/login_wallpaper_1440x1080.png"; + else if (screenWidth >= 1600) + wallpaperName = "graphics/images/login_wallpaper_1600x1200.png"; - Net::initialize(); - accountServerConnection = Net::getConnection(); - gameServerConnection = Net::getConnection(); - chatServerConnection = Net::getConnection(); + if (!ResourceManager::getInstance()->exists(wallpaperName)) + wallpaperName = "graphics/images/login_wallpaper.png"; - unsigned int oldstate = !state; // We start with a status change. + login_wallpaper = ResourceManager::getInstance()->getImage(wallpaperName); - SDL_Event event; - while (state != STATE_FORCE_QUIT) + if (!login_wallpaper) + logger->log("Couldn't load %s as wallpaper", wallpaperName.c_str()); + + unsigned int oldstate = !state; // We start with a status change. + + SDL_Event event; +#ifdef TMWSERV_SUPPORT + while (state != STATE_FORCE_QUIT) +#else + while (state != STATE_EXIT) +#endif + { + // Handle SDL events + while (SDL_PollEvent(&event)) { - // Handle SDL events - while (SDL_PollEvent(&event)) + switch (event.type) { - switch (event.type) - { - case SDL_QUIT: - state = STATE_FORCE_QUIT; - break; - - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_ESCAPE) + case SDL_QUIT: +#ifdef TMWSERV_SUPPORT + state = STATE_FORCE_QUIT; +#else + state = STATE_EXIT; +#endif + break; + + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) + { +#ifdef TMWSERV_SUPPORT + if (!quitDialog) { - if (!quitDialog) - { - quitDialog = new QuitDialog(NULL, &quitDialog); - } - else - { - quitDialog->requestMoveToTop(); - } + quitDialog = new QuitDialog(NULL, &quitDialog); } - break; - } - - guiInput->pushInput(event); + else + { + quitDialog->requestMoveToTop(); + } +#else + state = STATE_EXIT; +#endif + } + break; } - Net::flush(); - gui->logic(); + guiInput->pushInput(event); + } - if (!login_wallpaper) - { - std::string wallpaperFile = branding.getValue( - "loginWallpaper", "graphics/images/login_wallpaper.png"); - login_wallpaper = ResourceManager::getInstance()-> - getImage(wallpaperFile); - if (!login_wallpaper) - { - logger->error(wallpaperFile); - } - } +#ifdef TMWSERV_SUPPORT + Net::flush(); +#else + network->flush(); + network->dispatchMessages(); +#endif + gui->logic(); - if (graphics->getWidth() > login_wallpaper->getWidth() || - graphics->getHeight() > login_wallpaper->getHeight()) - { - graphics->setColor(gcn::Color(64, 64, 64)); - graphics->fillRectangle(gcn::Rectangle( - 0, 0, graphics->getWidth(), graphics->getHeight())); - } - graphics->drawImage(login_wallpaper, - (graphics->getWidth() - login_wallpaper->getWidth()) / 2, - (graphics->getHeight() - login_wallpaper->getHeight()) / 2); - gui->draw(); - graphics->updateScreen(); - - // TODO: Add connect timeouts - if (state == STATE_CONNECT_ACCOUNT && - accountServerConnection->isConnected()) - { - if (options.skipUpdate) { - state = STATE_LOADDATA; - } else { - state = STATE_UPDATE; - } - } - else if (state == STATE_CONNECT_GAME && - gameServerConnection->isConnected() && - chatServerConnection->isConnected()) - { - accountServerConnection->disconnect(); - Net::clearHandlers(); +#ifdef EATHENA_SUPPORT + if (network->getState() == Network::NET_ERROR) + { + state = STATE_ERROR; - state = STATE_GAME; + if (!network->getError().empty()) { + errorMessage = network->getError(); + } else { + errorMessage = _("Got disconnected from server!"); } - else if (state == STATE_RECONNECT_ACCOUNT && - accountServerConnection->isConnected()) - { - reconnectAccount(token); - state = STATE_WAIT; + } +#endif + + if (progressBar->isVisible()) + { + progressBar->setProgress(progressBar->getProgress() + 0.005f); + if (progressBar->getProgress() == 1.0f) + progressBar->setProgress(0.0f); + } + + if (graphics->getWidth() > login_wallpaper->getWidth() || + graphics->getHeight() > login_wallpaper->getHeight()) + { + graphics->setColor(gcn::Color(64, 64, 64)); + graphics->fillRectangle(gcn::Rectangle( + 0, 0, graphics->getWidth(), graphics->getHeight())); + } + graphics->drawImage(login_wallpaper, + (graphics->getWidth() - login_wallpaper->getWidth()) / 2, + (graphics->getHeight() - login_wallpaper->getHeight()) / 2); + gui->draw(); + graphics->updateScreen(); + +#ifdef TMWSERV_SUPPORT + // TODO: Add connect timeouts + if (state == STATE_CONNECT_ACCOUNT && + accountServerConnection->isConnected()) + { + if (options.skipUpdate) { + state = STATE_LOADDATA; + } else { + state = STATE_UPDATE; } + } + else if (state == STATE_CONNECT_GAME && + gameServerConnection->isConnected() && + chatServerConnection->isConnected()) + { + accountServerConnection->disconnect(); + Net::clearHandlers(); - if (state != oldstate) { - // Load updates after exiting the update state - if (oldstate == STATE_UPDATE) - { - loadUpdates(); - // Reload the wallpaper in case that it was updated - login_wallpaper->decRef(); - login_wallpaper = ResourceManager::getInstance()->getImage( + state = STATE_GAME; + } + else if (state == STATE_RECONNECT_ACCOUNT && + accountServerConnection->isConnected()) + { + reconnectAccount(token); + state = STATE_WAIT; + } +#endif + +#ifdef TMWSERV_SUPPORT + if (state != oldstate) { + // Load updates after exiting the update state + if (oldstate == STATE_UPDATE) + { + loadUpdates(); + // Reload the wallpaper in case that it was updated + login_wallpaper->decRef(); + login_wallpaper = ResourceManager::getInstance()->getImage( branding.getValue("loginWallpaper", "graphics/images/login_wallpaper.png")); - } - - oldstate = state; - - // Get rid of the dialog of the previous state - if (currentDialog) { - delete currentDialog; - currentDialog = NULL; - } - // State has changed, while the quitDialog was active, it might - // not be correct anymore - if (quitDialog) { - quitDialog->scheduleDelete(); - } - - switch (state) { - case STATE_CHOOSE_SERVER: - logger->log("State: CHOOSE_SERVER"); - - // Allow changing this using a server choice dialog - // We show the dialog box only if the command-line - // options weren't set. - if (options.serverName.empty() && options.serverPort == 0) { - currentDialog = new ServerDialog(&loginData); - } else { - state = STATE_CONNECT_ACCOUNT; - - // Reset options so that cancelling or connect - // timeout will show the server dialog. - options.serverName.clear(); - options.serverPort = 0; - } - break; - - case STATE_CONNECT_ACCOUNT: - logger->log("State: CONNECT_ACCOUNT"); - logger->log("Trying to connect to account server..."); - accountServerConnection->connect(loginData.hostname, - loginData.port); - currentDialog = new ConnectionDialog( - STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); - break; - - case STATE_UPDATE: - // Determine which source to use for the update host - if (!options.updateHost.empty()) - updateHost = options.updateHost; - else - updateHost = loginData.updateHost; + } - setUpdatesDir(); - logger->log("State: UPDATE"); - currentDialog = new UpdaterWindow(updateHost, - homeDir + "/" + updatesDir); - break; - - case STATE_LOGIN: - logger->log("State: LOGIN"); - if (options.username.empty() - || options.password.empty()) { - currentDialog = new LoginDialog(&loginData); - } else { - state = STATE_LOGIN_ATTEMPT; - // Clear the password so that when login fails, the - // dialog will show up next time. - options.password.clear(); - } - break; + oldstate = state; - case STATE_LOADDATA: - logger->log("State: LOADDATA"); + // Get rid of the dialog of the previous state + if (currentDialog) { + delete currentDialog; + currentDialog = NULL; + } + // State has changed, while the quitDialog was active, it might + // not be correct anymore + if (quitDialog) { + quitDialog->scheduleDelete(); + } - // Add customdata directory - ResourceManager::getInstance()->searchAndAddArchives( + switch (state) { + case STATE_CHOOSE_SERVER: + logger->log("State: CHOOSE_SERVER"); + + // Allow changing this using a server choice dialog + // We show the dialog box only if the command-line + // options weren't set. + if (options.serverName.empty() && options.serverPort == 0) { + currentDialog = new ServerDialog(&loginData); + } else { + state = STATE_CONNECT_ACCOUNT; + + // Reset options so that cancelling or connect + // timeout will show the server dialog. + options.serverName.clear(); + options.serverPort = 0; + } + break; + + case STATE_CONNECT_ACCOUNT: + logger->log("State: CONNECT_ACCOUNT"); + logger->log("Trying to connect to account server..."); + accountServerConnection->connect(loginData.hostname, + loginData.port); + currentDialog = new ConnectionDialog( + STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); + break; + + case STATE_UPDATE: + // Determine which source to use for the update host + if (!options.updateHost.empty()) + updateHost = options.updateHost; + else + updateHost = loginData.updateHost; + + setUpdatesDir(); + logger->log("State: UPDATE"); + currentDialog = new UpdaterWindow(updateHost, + homeDir + "/" + updatesDir); + break; + + case STATE_LOGIN: + logger->log("State: LOGIN"); + if (options.username.empty() + || options.password.empty()) { + currentDialog = new LoginDialog(&loginData); + } else { + state = STATE_LOGIN_ATTEMPT; + // Clear the password so that when login fails, the + // dialog will show up next time. + options.password.clear(); + } + break; + + case STATE_LOADDATA: + logger->log("State: LOADDATA"); + + // Add customdata directory + ResourceManager::getInstance()->searchAndAddArchives( "customdata/", "zip", false); - // Load XML databases - ItemDB::load(); - MonsterDB::load(); - NPCDB::load(); - state = STATE_LOGIN; - break; - - case STATE_LOGIN_ATTEMPT: - accountLogin(&loginData); - break; - - case STATE_LOGIN_ERROR: - logger->log("State: LOGIN ERROR"); - currentDialog = new OkDialog("Error ", errorMessage); - currentDialog->addActionListener(&loginListener); - currentDialog = NULL; // OkDialog deletes itself - break; - - case STATE_SWITCH_ACCOUNTSERVER: - logger->log("State: SWITCH_ACCOUNTSERVER"); - - gameServerConnection->disconnect(); - chatServerConnection->disconnect(); - accountServerConnection->disconnect(); - - state = STATE_CHOOSE_SERVER; - break; - - case STATE_SWITCH_ACCOUNTSERVER_ATTEMPT: - logger->log("State: SWITCH_ACCOUNTSERVER_ATTEMPT"); - switchAccountServer(); - - state = STATE_SWITCH_ACCOUNTSERVER; - break; - - case STATE_REGISTER: - logger->log("State: REGISTER"); - currentDialog = new RegisterDialog(&loginData); - break; - - case STATE_REGISTER_ATTEMPT: - accountRegister(&loginData); - break; - - case STATE_CHAR_SELECT: - logger->log("State: CHAR_SELECT"); - currentDialog = - new CharSelectDialog(&charInfo, &loginData); - - if (((CharSelectDialog*) currentDialog)-> - selectByName(options.character)) { - ((CharSelectDialog*) currentDialog)->action( - gcn::ActionEvent(NULL, "ok")); - } else { - ((CharSelectDialog*) currentDialog)->selectByName( - config.getValue("lastCharacter", "")); - } - - break; - - case STATE_CHANGEEMAIL_ATTEMPT: - logger->log("State: CHANGE EMAIL ATTEMPT"); - accountChangeEmail(&loginData); - break; - - case STATE_CHANGEEMAIL: - logger->log("State: CHANGE EMAIL"); - currentDialog = new OkDialog("Email Address change", - "Email Address changed successfully!"); - currentDialog->addActionListener(&accountListener); - currentDialog = NULL; // OkDialog deletes itself - loginData.email = loginData.newEmail; - loginData.newEmail = ""; - break; - - case STATE_CHANGEPASSWORD_ATTEMPT: - logger->log("State: CHANGE PASSWORD ATTEMPT"); - accountChangePassword(&loginData); - break; - - case STATE_CHANGEPASSWORD: - logger->log("State: CHANGE PASSWORD"); - currentDialog = new OkDialog("Password change", - "Password changed successfully!"); - currentDialog->addActionListener(&accountListener); - currentDialog = NULL; // OkDialog deletes itself - loginData.password = loginData.newPassword; - loginData.newPassword = ""; - break; - - case STATE_UNREGISTER_ATTEMPT: - logger->log("State: UNREGISTER ATTEMPT"); - accountUnRegister(&loginData); - break; - - case STATE_UNREGISTER: - logger->log("State: UNREGISTER"); - accountServerConnection->disconnect(); - currentDialog = new OkDialog("Unregister successful", - "Farewell, come back any time ...."); - loginData.clear(); - //The errorlistener sets the state to STATE_CHOOSE_SERVER - currentDialog->addActionListener(&errorListener); - currentDialog = NULL; // OkDialog deletes itself - break; - - case STATE_ACCOUNTCHANGE_ERROR: - logger->log("State: ACCOUNT CHANGE ERROR"); - currentDialog = new OkDialog("Error ", errorMessage); - currentDialog->addActionListener(&accountListener); - currentDialog = NULL; // OkDialog deletes itself - break; - - - case STATE_ERROR: - logger->log("State: ERROR"); - currentDialog = new OkDialog("Error", errorMessage); - currentDialog->addActionListener(&errorListener); - currentDialog = NULL; // OkDialog deletes itself - gameServerConnection->disconnect(); - chatServerConnection->disconnect(); - Net::clearHandlers(); - break; - - case STATE_CONNECT_GAME: - logger->log("State: CONNECT_GAME"); - currentDialog = new ConnectionDialog(STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); - break; - - case STATE_GAME: - logger->log("Memorizing selected character %s", - player_node->getName().c_str()); - config.setValue("lastCharacter", player_node->getName()); - - Net::GameServer::connect(gameServerConnection, token); - Net::ChatServer::connect(chatServerConnection, token); - sound.fadeOutMusic(1000); + // Load XML databases + ColorDB::load(); + ItemDB::load(); + MonsterDB::load(); + NPCDB::load(); + EmoteDB::load(); + Units::loadUnits(); + + state = STATE_LOGIN; + break; + + case STATE_LOGIN_ATTEMPT: + accountLogin(&loginData); + break; + + case STATE_LOGIN_ERROR: + logger->log("State: LOGIN ERROR"); + currentDialog = new OkDialog("Error ", errorMessage); + currentDialog->addActionListener(&loginListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + case STATE_SWITCH_ACCOUNTSERVER: + logger->log("State: SWITCH_ACCOUNTSERVER"); + + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + accountServerConnection->disconnect(); + + state = STATE_CHOOSE_SERVER; + break; + + case STATE_SWITCH_ACCOUNTSERVER_ATTEMPT: + logger->log("State: SWITCH_ACCOUNTSERVER_ATTEMPT"); + switchAccountServer(); + + state = STATE_SWITCH_ACCOUNTSERVER; + break; + + case STATE_REGISTER: + logger->log("State: REGISTER"); + currentDialog = new RegisterDialog(&loginData); + break; + + case STATE_REGISTER_ATTEMPT: + accountRegister(&loginData); + break; + + case STATE_CHAR_SELECT: + logger->log("State: CHAR_SELECT"); + currentDialog = + new CharSelectDialog(&charInfo, &loginData); + + if (((CharSelectDialog*) currentDialog)-> + selectByName(options.character)) { + ((CharSelectDialog*) currentDialog)->action( + gcn::ActionEvent(NULL, "ok")); + } else { + ((CharSelectDialog*) currentDialog)->selectByName( + config.getValue("lastCharacter", "")); + } + + break; + + case STATE_CHANGEEMAIL_ATTEMPT: + logger->log("State: CHANGE EMAIL ATTEMPT"); + accountChangeEmail(&loginData); + break; + + case STATE_CHANGEEMAIL: + logger->log("State: CHANGE EMAIL"); + currentDialog = new OkDialog("Email Address change", + "Email Address changed successfully!"); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + loginData.email = loginData.newEmail; + loginData.newEmail = ""; + break; + + case STATE_CHANGEPASSWORD_ATTEMPT: + logger->log("State: CHANGE PASSWORD ATTEMPT"); + accountChangePassword(&loginData); + break; + + case STATE_CHANGEPASSWORD: + logger->log("State: CHANGE PASSWORD"); + currentDialog = new OkDialog("Password change", + "Password changed successfully!"); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + loginData.password = loginData.newPassword; + loginData.newPassword = ""; + break; + + case STATE_UNREGISTER_ATTEMPT: + logger->log("State: UNREGISTER ATTEMPT"); + accountUnRegister(&loginData); + break; + + case STATE_UNREGISTER: + logger->log("State: UNREGISTER"); + accountServerConnection->disconnect(); + currentDialog = new OkDialog("Unregister successful", + "Farewell, come back any time ...."); + loginData.clear(); + //The errorlistener sets the state to STATE_CHOOSE_SERVER + currentDialog->addActionListener(&errorListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + case STATE_ACCOUNTCHANGE_ERROR: + logger->log("State: ACCOUNT CHANGE ERROR"); + currentDialog = new OkDialog("Error ", errorMessage); + currentDialog->addActionListener(&accountListener); + currentDialog = NULL; // OkDialog deletes itself + break; + + + case STATE_ERROR: + logger->log("State: ERROR"); + currentDialog = new OkDialog("Error", errorMessage); + currentDialog->addActionListener(&errorListener); + currentDialog = NULL; // OkDialog deletes itself + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + Net::clearHandlers(); + break; + + case STATE_CONNECT_GAME: + logger->log("State: CONNECT_GAME"); + currentDialog = new ConnectionDialog(STATE_SWITCH_ACCOUNTSERVER_ATTEMPT); + break; + + case STATE_GAME: + logger->log("Memorizing selected character %s", + player_node->getName().c_str()); + config.setValue("lastCharacter", player_node->getName()); + + Net::GameServer::connect(gameServerConnection, token); + Net::ChatServer::connect(chatServerConnection, token); + sound.fadeOutMusic(1000); #ifdef PACKAGE_VERSION - delete versionLabel; - versionLabel = NULL; + delete versionLabel; + versionLabel = NULL; #endif - currentDialog = NULL; - - logger->log("State: GAME"); - game = new Game; - game->logic(); - delete game; - - // If the quitdialog didn't set the next state - if (state == STATE_GAME) - { - state = STATE_EXIT; - } - break; + currentDialog = NULL; - case STATE_SWITCH_CHARACTER: - logger->log("State: SWITCH_CHARACTER"); - switchCharacter(&token); - break; + logger->log("State: GAME"); + game = new Game; + game->logic(); + delete game; + + // If the quitdialog didn't set the next state + if (state == STATE_GAME) + { + state = STATE_EXIT; + } + break; + + case STATE_SWITCH_CHARACTER: + logger->log("State: SWITCH_CHARACTER"); + switchCharacter(&token); + break; + + case STATE_RECONNECT_ACCOUNT: + logger->log("State: RECONNECT_ACCOUNT"); + + // Done with game & chat + gameServerConnection->disconnect(); + chatServerConnection->disconnect(); + + accountServerConnection->connect( + loginData.hostname, + loginData.port); + break; + + case STATE_WAIT: + break; + + case STATE_EXIT: + logger->log("State: EXIT"); + logoutThenExit(); + break; + + default: + state = STATE_FORCE_QUIT; + break; + } + } - case STATE_RECONNECT_ACCOUNT: - logger->log("State: RECONNECT_ACCOUNT"); +#else // no TMWSERV_SUPPORT - // Done with game & chat - gameServerConnection->disconnect(); - chatServerConnection->disconnect(); + if (state != oldstate) { + switch (oldstate) + { + case STATE_UPDATE: + loadUpdates(); + // Reload the wallpaper in case that it was updated + login_wallpaper->decRef(); + login_wallpaper = ResourceManager::getInstance()-> + getImage(wallpaperName); + // Load units + Units::loadUnits(); + break; + + // Those states don't cause a network disconnect + case STATE_LOADDATA: + break; + + case STATE_ACCOUNT: + case STATE_CHAR_CONNECT: + case STATE_CONNECTING: + progressBar->setVisible(false); + progressLabel->setCaption(""); + break; + + default: + network->disconnect(); + network->clearHandlers(); + break; + } - accountServerConnection->connect( - loginData.hostname, - loginData.port); - break; + oldstate = state; - case STATE_WAIT: - break; + if (currentDialog && state != STATE_ACCOUNT && + state != STATE_CHAR_CONNECT) { + delete currentDialog; + currentDialog = NULL; + } - case STATE_EXIT: - logger->log("State: EXIT"); - logoutThenExit(); - break; + switch (state) { + case STATE_LOADDATA: + logger->log("State: LOADDATA"); + + // Add customdata directory + ResourceManager::getInstance()->searchAndAddArchives( + "customdata/", + "zip", + false); + + // Load XML databases + ColorDB::load(); + ItemDB::load(); + MonsterDB::load(); + NPCDB::load(); + EmoteDB::load(); + + state = STATE_CHAR_CONNECT; + break; + + case STATE_LOGIN: + logger->log("State: LOGIN"); + + if (!loginData.password.empty()) { + loginData.registerLogin = false; + state = STATE_ACCOUNT; + } else { + currentDialog = new LoginDialog(&loginData); + positionDialog(currentDialog, screenWidth, + screenHeight); + } + break; + + case STATE_REGISTER: + logger->log("State: REGISTER"); + currentDialog = new RegisterDialog(&loginData); + positionDialog(currentDialog, screenWidth, screenHeight); + break; + + case STATE_CHAR_SERVER: + 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 = STATE_UPDATE; + } + else + { + int nextState = (options.skipUpdate) ? + STATE_LOADDATA : STATE_UPDATE; + currentDialog = new ServerSelectDialog(&loginData, + nextState); + positionDialog(currentDialog, screenWidth, + screenHeight); + if (options.chooseDefault + || !options.character.empty()) + { + ((ServerSelectDialog*) currentDialog)->action( + gcn::ActionEvent(NULL, "ok")); + } + } + break; + case STATE_CHAR_SELECT: + logger->log("State: CHAR_SELECT"); + currentDialog = new CharSelectDialog(network, &charInfo, + (loginData.sex == 0) ? + GENDER_FEMALE : GENDER_MALE); + positionDialog(currentDialog, screenWidth, screenHeight); + + if (((CharSelectDialog*) currentDialog)-> + selectByName(options.character)) + options.chooseDefault = true; + else + ((CharSelectDialog*) currentDialog)->selectByName( + config.getValue("lastCharacter", "")); + + if (options.chooseDefault) + ((CharSelectDialog*) currentDialog)->action( + gcn::ActionEvent(NULL, "ok")); + + break; + + case STATE_GAME: + sound.fadeOutMusic(1000); - default: - state = STATE_FORCE_QUIT; - break; - } +#ifdef PACKAGE_VERSION + delete versionLabel; + versionLabel = NULL; +#endif + delete progressBar; + delete progressLabel; + delete setup; + delete setupWindow; + progressBar = NULL; + progressLabel = NULL; + currentDialog = NULL; + setup = NULL; + setupWindow = NULL; + login_wallpaper->decRef(); + login_wallpaper = NULL; + + logger->log("State: GAME"); + game = new Game(network); + game->logic(); + delete game; + state = STATE_EXIT; + break; + + case STATE_UPDATE: + // Determine which source to use for the update host + if (!options.updateHost.empty()) + updateHost = options.updateHost; + else + updateHost = loginData.updateHost; + + setUpdatesDir(); + logger->log("State: UPDATE"); + + if (options.skipUpdate) { + state = STATE_LOADDATA; + } else { + currentDialog = new UpdaterWindow(updateHost, + homeDir + "/" + updatesDir); + positionDialog(currentDialog, screenWidth, + screenHeight); + } + break; + + case STATE_ERROR: + logger->log("State: ERROR"); + currentDialog = new OkDialog(_("Error"), errorMessage); + positionDialog(currentDialog, screenWidth, screenHeight); + currentDialog->addActionListener(&errorListener); + currentDialog = NULL; // OkDialog deletes itself + network->disconnect(); + network->clearHandlers(); + break; + + case STATE_CONNECTING: + logger->log("State: CONNECTING"); + progressBar->setVisible(true); + progressLabel->setCaption( + _("Connecting to map server...")); + progressLabel->adjustSize(); + mapLogin(network, &loginData); + break; + + case STATE_CHAR_CONNECT: + progressBar->setVisible(true); + progressLabel->setCaption( + _("Connecting to character server...")); + progressLabel->adjustSize(); + charLogin(network, &loginData); + break; + + case STATE_ACCOUNT: + progressBar->setVisible(true); + progressLabel->setCaption( + _("Connecting to account server...")); + progressLabel->adjustSize(); + accountLogin(network, &loginData); + break; + + default: + state = STATE_EXIT; + break; } } +#endif + /* + * This loop can really stress the CPU, for no reason since it's + * just constantly redrawing the wallpaper. Added the following + * usleep to limit it to 20 FPS during the login sequence + */ + usleep(50000); + } + delete textColor; #ifdef PACKAGE_VERSION - delete versionLabel; + delete versionLabel; #endif - } - catch (...) - { - logger->log("Exception"); - } + delete progressBar; + delete progressLabel; + delete setup; + delete setupWindow; +#ifdef TMWSERV_SUPPORT if (accountServerConnection) accountServerConnection->disconnect(); if (gameServerConnection) @@ -1248,6 +1779,10 @@ int main(int argc, char *argv[]) delete gameServerConnection; delete chatServerConnection; Net::finalize(); +#else + delete network; + SDLNet_Quit(); +#endif logger->log("Quitting"); exit_engine(); @@ -1256,3 +1791,22 @@ int main(int argc, char *argv[]) return 0; } + +void SetupListener::action(const gcn::ActionEvent &event) +{ + Window *window = NULL; + + if (event.getId() == "Setup") + { + window = setupWindow; + } + + if (window) + { + window->setVisible(!window->isVisible()); + if (window->isVisible()) + { + window->requestMoveToTop(); + } + } +} @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MAIN_H -#define _TMW_MAIN_H +#ifndef MAIN_H +#define MAIN_H /** * \mainpage @@ -57,28 +57,33 @@ #include "../config.h" #elif defined WIN32 #include "winver.h" +#elif defined __APPLE__ +#define PACKAGE_VERSION "0.1.0" #endif -#ifndef TMW_DATADIR -#define TMW_DATADIR "" +#ifndef PKG_DATADIR +#define PKG_DATADIR "" #endif /* * Client different States */ enum { - STATE_CHOOSE_SERVER, - STATE_CONNECT_ACCOUNT, - STATE_UPDATE, + STATE_EXIT, STATE_LOADDATA, STATE_LOGIN, + STATE_REGISTER, + STATE_CHAR_SELECT, + STATE_GAME, + STATE_ERROR, + STATE_UPDATE, +#ifdef TMWSERV_SUPPORT + STATE_CHOOSE_SERVER, + STATE_CONNECT_ACCOUNT, STATE_LOGIN_ATTEMPT, STATE_LOGIN_ERROR, - STATE_REGISTER, STATE_REGISTER_ATTEMPT, STATE_ACCOUNTCHANGE_ERROR, - STATE_ERROR, - STATE_CHAR_SELECT, STATE_CHANGEEMAIL_ATTEMPT, STATE_CHANGEEMAIL, STATE_CHANGEPASSWORD_ATTEMPT, @@ -91,10 +96,16 @@ enum { STATE_SWITCH_ACCOUNTSERVER, STATE_LOGOUT_ATTEMPT, STATE_CONNECT_GAME, - STATE_GAME, STATE_WAIT, - STATE_EXIT, STATE_FORCE_QUIT +#else + STATE_ACCOUNT, + STATE_CHAR_CONNECT, + STATE_CHAR_SERVER, + STATE_CHAR_NEW, + STATE_CHAR_DEL, + STATE_CONNECTING +#endif }; /* length definitions for several char[]s in order @@ -120,7 +131,12 @@ const short defaultMusicVolume = 60; // Defines the number of usable player slots const short maxSlot = 2; +#ifdef TMWSERV_SUPPORT extern std::string token; +#else +extern char n_server, n_character; +#endif + extern unsigned char state; extern std::string errorMessage; diff --git a/src/map.cpp b/src/map.cpp index 5c2290d6..e7646fd2 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,43 +1,42 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "map.h" - #include <queue> -#include <cassert> #include "beingmanager.h" #include "configuration.h" #include "game.h" #include "graphics.h" +#include "map.h" #include "particle.h" +#include "simpleanimation.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" +#include "utils/stringutils.h" extern volatile int tick_time; @@ -63,6 +62,38 @@ struct Location MetaTile *tile; }; +TileAnimation::TileAnimation(Animation *ani): + mLastImage(NULL) +{ + mAnimation = new SimpleAnimation(ani); +} + +TileAnimation::~TileAnimation() +{ + delete mAnimation; +} + +void TileAnimation::update() +{ + if (!mAnimation) + return; + + //update animation + mAnimation->update(1); + + // exchange images + Image *img = mAnimation->getCurrentImage(); + if (img != mLastImage) + { + for (std::list<std::pair<MapLayer*, int> >::iterator i = + mAffected.begin(); i != mAffected.end(); i++) + { + i->first->setTile(i->second, img); + } + mLastImage = img; + } +} + MapLayer::MapLayer(int x, int y, int width, int height, bool isFringeLayer): mX(x), mY(y), mWidth(width), mHeight(height), @@ -80,7 +111,7 @@ MapLayer::~MapLayer() void MapLayer::setTile(int x, int y, Image *img) { - mTiles[x + y * mWidth] = img; + setTile(x + y * mWidth, img); } Image* MapLayer::getTile(int x, int y) const @@ -110,8 +141,14 @@ void MapLayer::draw(Graphics *graphics, { // If drawing the fringe layer, make sure all sprites above this row of // tiles have been drawn - if (mIsFringeLayer) { - while (si != sprites.end() && (*si)->getPixelY() <= y * 32) { + if (mIsFringeLayer) + { +#ifdef TMWSERV_SUPPORT + while (si != sprites.end() && (*si)->getPixelY() <= y * 32) +#else + while (si != sprites.end() && (*si)->getPixelY() <= y * 32 - 32) +#endif + { (*si)->draw(graphics, -scrollX, -scrollY); si++; } @@ -120,7 +157,8 @@ void MapLayer::draw(Graphics *graphics, for (int x = startX; x < endX; x++) { Image *img = getTile(x, y); - if (img) { + if (img) + { const int px = (x + mX) * 32 - scrollX; const int py = (y + mY) * 32 - scrollY + 32 - img->getHeight(); graphics->drawImage(img, px, py); @@ -165,6 +203,7 @@ Map::~Map() delete_all(mLayers); delete_all(mTilesets); delete_all(mOverlays); + delete_all(mTileAnimations); } void Map::initializeOverlays() @@ -211,6 +250,17 @@ bool spriteCompare(const Sprite *a, const Sprite *b) return a->getPixelY() < b->getPixelY(); } +void Map::update() +{ + //update animated tiles + for (std::map<int, TileAnimation*>::iterator iAni = mTileAnimations.begin(); + iAni != mTileAnimations.end(); + iAni++) + { + iAni->second->update(); + } +} + void Map::draw(Graphics *graphics, int scrollX, int scrollY) { int endPixelY = graphics->getHeight() + scrollY + mTileHeight - 1; @@ -226,8 +276,10 @@ void Map::draw(Graphics *graphics, int scrollX, int scrollY) // Make sure sprites are sorted mSprites.sort(spriteCompare); + // draw the game world Layers::const_iterator layeri = mLayers.begin(); - for (; layeri != mLayers.end(); ++layeri) { + for (; layeri != mLayers.end(); ++layeri) + { (*layeri)->draw(graphics, startX, startY, endX, endY, scrollX, scrollY, @@ -354,10 +406,8 @@ Tileset* Map::getTilesetWithGid(int gid) const void Map::blockTile(int x, int y, BlockType type) { - if (type == BLOCKTYPE_NONE || x < 0 || y < 0 || x >= mWidth || y >= mHeight) - { + if (type == BLOCKTYPE_NONE || !contains(x, y)) return; - } int tileNum = x + y * mWidth; @@ -384,10 +434,8 @@ void Map::blockTile(int x, int y, BlockType type) bool Map::getWalk(int x, int y, char walkmask) const { // You can't walk outside of the map - if (x < 0 || y < 0 || x >= mWidth || y >= mHeight) - { + if (!contains(x, y)) return false; - } // Check if the tile is walkable return !(mMetaTiles[x + y * mWidth].blockmask & walkmask); @@ -419,7 +467,7 @@ static int const basicCost = 100; Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char walkmask, int maxCost) { // Path to be built up (empty by default) - std::list<Position> path; + Path path; // Declare open list, a list with open tiles sorted on F cost std::priority_queue<Location> openList; @@ -439,20 +487,19 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w // Keep trying new open tiles until no more tiles to try or target found while (!openList.empty() && !foundPath) { - // Take the location with the lowest F cost from the open list, and - // add it to the closed list. + // Take the location with the lowest F cost from the open list. Location curr = openList.top(); openList.pop(); // If the tile is already on the closed list, this means it has already // been processed with a shorter path to the start point (lower G cost) - if (curr.tile->whichList == onClosedList) + if (curr.tile->whichList == mOnClosedList) { continue; } // Put the current tile on the closed list - curr.tile->whichList = onClosedList; + curr.tile->whichList = mOnClosedList; // Check the adjacent tiles for (int dy = -1; dy <= 1; dy++) @@ -465,8 +512,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w // Skip if if we're checking the same tile we're leaving from, // or if the new location falls outside of the map boundaries - if ((dx == 0 && dy == 0) || - (x < 0 || y < 0 || x >= mWidth || y >= mHeight)) + if ((dx == 0 && dy == 0) || !contains(x, y)) { continue; } @@ -474,7 +520,9 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w MetaTile *newTile = getMetaTile(x, y); // Skip if the tile is on the closed list or is not walkable - if (newTile->whichList == onClosedList || newTile->blockmask & walkmask) + // unless its the destination tile + if (newTile->whichList == mOnClosedList || + ((newTile->blockmask & walkmask) && !(x == destX && y == destY))) { continue; } @@ -510,6 +558,13 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w ++Gcost; } + // It costs extra to walk through a being (needs to be enough + // to make it more attractive to walk around). + if (!getWalk(x, y, BLOCKMASK_CHARACTER | BLOCKMASK_MONSTER)) + { + Gcost += 3 * basicCost; + } + // Skip if Gcost becomes too much // Warning: probably not entirely accurate if (Gcost > maxCost * basicCost) @@ -517,7 +572,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w continue; } - if (newTile->whichList != onOpenList) + if (newTile->whichList != mOnOpenList) { // Found a new tile (not on open nor on closed list) @@ -539,7 +594,7 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w if (x != destX || y != destY) { // Add this tile to the open list - newTile->whichList = onOpenList; + newTile->whichList = mOnOpenList; openList.push(Location(x, y, newTile)); } else { @@ -568,8 +623,8 @@ Path Map::findPath(int startX, int startY, int destX, int destY, unsigned char w // Two new values to indicate whether a tile is on the open or closed list, // this way we don't have to clear all the values between each pathfinding. - onClosedList += 2; - onOpenList += 2; + mOnClosedList += 2; + mOnOpenList += 2; // If a path has been found, iterate backwards using the parent locations // to extract it. @@ -604,11 +659,25 @@ 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)) + { + for (std::list<ParticleEffectData>::iterator i = particleEffects.begin(); + i != particleEffects.end(); + i++ + ) + { + particleEngine->addEffect(i->file, i->x, i->y); + } + } +} + +TileAnimation* Map::getAnimationForGid(int gid) +{ + std::map<int, TileAnimation*>::iterator i = mTileAnimations.find(gid); + if (i == mTileAnimations.end()) { - particleEngine->addEffect(i->file, i->x, i->y); + return NULL; + } else { + return i->second; } } @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MAP_H_ -#define _TMW_MAP_H_ +#ifndef MAP_H +#define MAP_H #include <list> #include <vector> @@ -28,11 +28,13 @@ #include "position.h" #include "properties.h" +class Animation; class AmbientOverlay; class Graphics; class Image; class MapLayer; class Particle; +class SimpleAnimation; class Sprite; class Tileset; @@ -64,6 +66,23 @@ struct MetaTile }; /** + * Animation cycle of a tile image which changes the map accordingly. + */ +class TileAnimation +{ + public: + TileAnimation(Animation *ani); + ~TileAnimation(); + void update(); + void addAffectedTile(MapLayer *layer, int index) + { mAffected.push_back(std::make_pair(layer, index)); } + private: + std::list<std::pair<MapLayer*, int> > mAffected; + SimpleAnimation *mAnimation; + Image *mLastImage; +}; + +/** * A map layer. Stores a grid of tiles and their offset, and implements layer * rendering. */ @@ -88,6 +107,11 @@ class MapLayer void setTile(int x, int y, Image *img); /** + * Set tile image with x + y * width already known. + */ + void setTile(int index, Image *img) { mTiles[index] = img; } + + /** * Get tile image, with x and y in layer coordinates. */ Image *getTile(int x, int y) const; @@ -145,6 +169,11 @@ class Map : public Properties void initializeOverlays(); /** + * Updates animations. Called every game tick. + */ + void update(); + + /** * Draws the map to the given graphics output. This method draws all * layers, sprites and overlay effects. * @@ -172,8 +201,7 @@ class Map : public Properties /** * Finds the tile set that a tile with the given global id is part of. */ - Tileset* - getTilesetWithGid(int gid) const; + Tileset* getTilesetWithGid(int gid) const; /** * Get tile reference. @@ -194,26 +222,22 @@ class Map : public Properties /** * Returns the width of this map. */ - int - getWidth() const { return mWidth; } + int getWidth() const { return mWidth; } /** * Returns the height of this map. */ - int - getHeight() const { return mHeight; } + int getHeight() const { return mHeight; } /** * Returns the tile width of this map. */ - int - getTileWidth() const { return mTileWidth; } + int getTileWidth() const { return mTileWidth; } /** * Returns the tile height used by this map. */ - int - getTileHeight() const { return mTileHeight; } + int getTileHeight() const { return mTileHeight; } /** * Find a path from one location to the next. @@ -224,14 +248,12 @@ class Map : public Properties /** * Adds a sprite to the map. */ - SpriteIterator - addSprite(Sprite *sprite); + SpriteIterator addSprite(Sprite *sprite); /** * Removes a sprite from the map. */ - void - removeSprite(SpriteIterator iterator); + void removeSprite(SpriteIterator iterator); /** * Adds a particle effect @@ -241,16 +263,25 @@ class Map : public Properties /** * Initializes all added particle effects */ - void - initializeParticleEffects(Particle* particleEngine); + void initializeParticleEffects(Particle* particleEngine); + + /** + * Adds a tile animation to the map + */ + void addAnimation(int gid, TileAnimation *animation) + { mTileAnimations[gid] = animation; } + + /** + * Gets the tile animation for a specific gid + */ + TileAnimation *getAnimationForGid(int gid); private: /** * Draws the overlay graphic to the given graphics output. */ - void - drawOverlay(Graphics *graphics, float scrollX, float scrollY, - int detail); + void drawOverlay(Graphics *graphics, float scrollX, float scrollY, + int detail); /** * Tells whether the given coordinates fall within the map boundaries. @@ -265,9 +296,6 @@ class Map : public Properties static const unsigned char BLOCKMASK_MONSTER = 0x02; // = bin 0000 0010 int *mOccupation[NB_BLOCKTYPES]; - // Pathfinding members - int onClosedList, onOpenList; - int mWidth, mHeight; int mTileWidth, mTileHeight; int mMaxTileHeight; @@ -292,6 +320,8 @@ class Map : public Properties int y; }; std::list<ParticleEffectData> particleEffects; + + std::map<int, TileAnimation*> mTileAnimations; }; #endif diff --git a/src/monster.cpp b/src/monster.cpp index c472a21b..deabd7a8 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1,44 +1,48 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "monster.h" - #include "animatedsprite.h" #include "game.h" +#include "localplayer.h" +#include "monster.h" #include "particle.h" #include "sound.h" +#include "text.h" #include "resources/monsterdb.h" +#include "resources/monsterinfo.h" -#include "utils/tostring.h" +static const int NAME_X_OFFSET = 16; +static const int NAME_Y_OFFSET = 16; - -Monster::Monster(Uint16 id, Uint16 job, Map *map): - Being(id, job, map) +Monster::Monster(Uint32 id, Uint16 job, Map *map): + Being(id, job, map), + mText(0) { const MonsterInfo& info = getInfo(); // 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++) @@ -56,27 +60,48 @@ Monster::Monster(Uint16 id, Uint16 job, Map *map): mSprites[c] = AnimatedSprite::load("graphics/sprites/error.xml"); } - const std::list<std::string> &particleEffects = info.getParticleEffects(); - for (std::list<std::string>::const_iterator i = particleEffects.begin(); - i != particleEffects.end(); - i++) + if (mParticleEffects) { - controlParticle(particleEngine->addEffect((*i), 0, 0)); + const std::list<std::string> &particleEffects = info.getParticleEffects(); + for ( std::list<std::string>::const_iterator i = particleEffects.begin(); + i != particleEffects.end(); i++ + ) + { + controlParticle(particleEngine->addEffect((*i), 0, 0)); + } } + + mNameColor = 0xff2020; } Monster::~Monster() { + delete mText; +} + +#ifdef EATHENA_SUPPORT +void Monster::logic() +{ + if (mAction != STAND) + { + mFrame = (get_elapsed_time(mWalkTime) * 4) / getWalkSpeed(); + + if (mFrame >= 4 && mAction != DEAD) + { + nextStep(); + } + } + + Being::logic(); } +#endif -Being::Type -Monster::getType() const +Being::Type Monster::getType() const { return MONSTER; } -void -Monster::setAction(Action action, int attackType) +void Monster::setAction(Action action, int attackType) { SpriteAction currentAction = ACTION_INVALID; int rotation = 0; @@ -93,10 +118,11 @@ Monster::setAction(Action action, int attackType) break; case ATTACK: currentAction = getInfo().getAttackAction(attackType); + mSprites[BASE_SPRITE]->reset(); //attack particle effect particleEffect = getInfo().getAttackParticleEffect(attackType); - if (particleEffect != "") + if (!particleEffect.empty() && mParticleEffects) { switch (mDirection) { @@ -106,21 +132,21 @@ Monster::setAction(Action action, int attackType) case RIGHT: rotation = 270; break; default: break; } - mSprites[BASE_SPRITE]->reset(); - Particle *p; - p = particleEngine->addEffect( + Particle *p; + p = particleEngine->addEffect( particleEffect, 0, 0, rotation); - controlParticle(p); + controlParticle(p); } break; case STAND: - currentAction = ACTION_STAND; - break; + currentAction = ACTION_STAND; + break; case HURT: - // Not implemented yet - break; - default: - break; + // Not implemented yet + break; + case SIT: + // Also not implemented yet + break; } if (currentAction != ACTION_INVALID) @@ -136,8 +162,9 @@ Monster::setAction(Action action, int attackType) } } -void -Monster::handleAttack() +#ifdef TMWSERV_SUPPORT + +void Monster::handleAttack() { Being::handleAttack(); @@ -149,21 +176,62 @@ Monster::handleAttack() sound.playSfx(mi.getSound(MONSTER_EVENT_HIT)); } -void -Monster::takeDamage(int amount) +#else + +void Monster::handleAttack(Being *victim, int damage) +{ + Being::handleAttack(victim, damage); + + const MonsterInfo &mi = getInfo(); + sound.playSfx(mi.getSound((damage > 0) ? + MONSTER_EVENT_HIT : MONSTER_EVENT_MISS)); +} + +#endif + +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 { +#ifdef TMWSERV_SUPPORT return MonsterDB::get(mJob); +#else + return MonsterDB::get(mJob - 1002); +#endif +} + +void Monster::showName(bool show) +{ + if (mText) + { + delete mText; + } + if (show) + { + mText = new Text(getInfo().getName(), mPx + NAME_X_OFFSET, + mPy + NAME_Y_OFFSET - getHeight(), + gcn::Graphics::CENTER, gcn::Color(255, 64, 64)); + } + else + { + mText = 0; + } +} + +void Monster::updateCoords() +{ + if (mText) + { + mText->adviseXY(mPx + NAME_X_OFFSET, + mPy + NAME_Y_OFFSET - getHeight()); + } } diff --git a/src/monster.h b/src/monster.h index 5b6fcf61..5251d37e 100644 --- a/src/monster.h +++ b/src/monster.h @@ -1,39 +1,44 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MONSTER_H -#define _TMW_MONSTER_H +#ifndef MONSTER_H +#define MONSTER_H #include "being.h" class MonsterInfo; +class Text; class Monster : public Being { public: - Monster(Uint16 id, Uint16 job, Map *map); + Monster(Uint32 id, Uint16 job, Map *map); - virtual ~Monster(); + ~Monster(); - virtual void setAction(Action action, int attackType); +#ifdef EATHENA_SUPPORT + virtual void logic(); +#endif + + virtual void setAction(Action action, int attackType = 0); virtual Type getType() const; @@ -43,8 +48,15 @@ class Monster : public Being /** * Handles an attack of another being by this monster. Plays a hit or * miss sound when appropriate. + * + * @param victim The attacked being. + * @param damage The amount of damage dealt (0 means miss). */ +#ifdef TMWSERV_SUPPORT virtual void handleAttack(); +#else + virtual void handleAttack(Being *victim, int damage); +#endif /** * Puts a damage bubble above this monster and plays the hurt sound @@ -56,8 +68,12 @@ class Monster : public Being /** * Returns the MonsterInfo, with static data about this monster. */ - const MonsterInfo& - getInfo() const; + const MonsterInfo& getInfo() const; + + /** + * Determine whether the mob should show it's name + */ + void showName(bool show); /** * Gets the way the monster is blocked by other objects @@ -71,6 +87,17 @@ class Monster : public Being */ virtual Map::BlockType getBlockType() const { return Map::BLOCKTYPE_MONSTER; } + + /** + * Update the text when the monster moves + */ + void updateCoords(); + + private: + /** + * holds a text object when the mod displays it's name, 0 otherwise + */ + Text *mText; }; #endif diff --git a/src/net/accountserver/internal.h b/src/net/accountserver/internal.h index 35f986cd..b3d64582 100644 --- a/src/net/accountserver/internal.h +++ b/src/net/accountserver/internal.h @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/net/buysellhandler.cpp b/src/net/buysellhandler.cpp index 596ac434..a551f213 100644 --- a/src/net/buysellhandler.cpp +++ b/src/net/buysellhandler.cpp @@ -61,17 +61,6 @@ void BuySellHandler::handleMessage(MessageIn &msg) switch (msg.getId()) { -#if 0 - case SMSG_NPC_BUY_SELL_CHOICE: - buyDialog->setVisible(false); - buyDialog->reset(); - sellDialog->setVisible(false); - sellDialog->reset(); - buySellDialog->setVisible(true); - current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg.readInt32())); - break; -#endif - case GPMSG_NPC_BUY: buyDialog->reset(); buyDialog->setMoney(player_node->getMoney()); diff --git a/src/net/buysellhandler.h b/src/net/buysellhandler.h index 52e9b2f7..719b76d9 100644 --- a/src/net/buysellhandler.h +++ b/src/net/buysellhandler.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NET_BUYSELLHANDLER_H -#define _TMW_NET_BUYSELLHANDLER_H +#ifndef NET_BUYSELLHANDLER_H +#define NET_BUYSELLHANDLER_H #include "messagehandler.h" diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index bde856a5..5905dba0 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -209,7 +209,7 @@ LocalPlayer* CharServerHandler::readPlayerData(MessageIn &msg, int &slot) { LocalPlayer *tempPlayer = new LocalPlayer; slot = msg.readInt8(); // character slot - tempPlayer->mName = msg.readString(); + tempPlayer->setName(msg.readString()); tempPlayer->setGender(msg.readInt8() == GENDER_MALE ? GENDER_MALE : GENDER_FEMALE); int hs = msg.readInt8(), hc = msg.readInt8(); tempPlayer->setHairStyle(hs, hc); diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp index d81a8b7d..90af899a 100644 --- a/src/net/chathandler.cpp +++ b/src/net/chathandler.cpp @@ -37,8 +37,6 @@ #include "../gui/chat.h" #include "../gui/guildwindow.h" -#include "../utils/tostring.h" - extern Being *player_node; ChatHandler::ChatHandler() diff --git a/src/net/chathandler.h b/src/net/chathandler.h index aeaf5368..a9e9bd99 100644 --- a/src/net/chathandler.h +++ b/src/net/chathandler.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NET_CHATHANDLER_H -#define _TMW_NET_CHATHANDLER_H +#ifndef NET_CHATHANDLER_H +#define NET_CHATHANDLER_H #include "messagehandler.h" diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp new file mode 100644 index 00000000..1edc6079 --- /dev/null +++ b/src/net/ea/beinghandler.cpp @@ -0,0 +1,542 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <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 "../../npc.h" +#include "../../player_relations.h" + +const int EMOTION_TIME = 150; /**< Duration of emotion icon */ + +BeingHandler::BeingHandler(bool enableSync): + mSync(enableSync) +{ + static const Uint16 _messages[] = { + SMSG_BEING_VISIBLE, + SMSG_BEING_MOVE, + SMSG_BEING_MOVE2, + SMSG_BEING_REMOVE, + SMSG_BEING_ACTION, + SMSG_BEING_SELFEFFECT, + SMSG_BEING_EMOTION, + SMSG_BEING_CHANGE_LOOKS, + SMSG_BEING_CHANGE_LOOKS2, + SMSG_BEING_NAME_RESPONSE, + SMSG_PLAYER_UPDATE_1, + SMSG_PLAYER_UPDATE_2, + SMSG_PLAYER_MOVE, + SMSG_PLAYER_STOP, + SMSG_PLAYER_MOVE_TO_ATTACK, + 0x0119, + 0x0196, + 0 + }; + handledMessages = _messages; +} + +void BeingHandler::handleMessage(MessageIn &msg) +{ + Uint32 id; + Uint16 job, speed; + Uint16 headTop, headMid, headBottom; + Uint16 shoes, gloves; + Uint16 weapon, shield; + Uint16 gmstatus; + Sint16 param1; + int stunMode; + Uint32 statusEffects; + Sint8 type; + Uint16 status; + Being *srcBeing, *dstBeing; + int hairStyle, hairColor, flag; + + switch (msg.getId()) + { + case SMSG_BEING_VISIBLE: + case SMSG_BEING_MOVE: + // Information about a being in range + id = msg.readInt32(); + speed = msg.readInt16(); + stunMode = msg.readInt16(); // opt1 + statusEffects = msg.readInt16(); // opt2 + statusEffects |= ((Uint32)msg.readInt16()) << 16; // option + job = msg.readInt16(); // class + + dstBeing = beingManager->findBeing(id); + + if (!dstBeing) + { + // Being with id >= 110000000 and job 0 are better + // known as ghosts, so don't create those. + if (job == 0 && id >= 110000000) + { + break; + } + + dstBeing = beingManager->createBeing(id, job); + } + else if (msg.getId() == 0x0078) + { + dstBeing->clearPath(); + dstBeing->mFrame = 0; + dstBeing->mWalkTime = tick_time; + dstBeing->setAction(Being::STAND); + } + + + // Prevent division by 0 when calculating frame + if (speed == 0) { speed = 150; } + + dstBeing->setWalkSpeed(speed); + dstBeing->mJob = job; + hairStyle = msg.readInt16(); + dstBeing->setSprite(Being::WEAPON_SPRITE, msg.readInt16()); + headBottom = msg.readInt16(); + + if (msg.getId() == SMSG_BEING_MOVE) + { + msg.readInt32(); // server tick + } + + dstBeing->setSprite(Being::SHIELD_SPRITE, msg.readInt16()); + 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 + msg.readInt16(); // guild + msg.readInt16(); // unknown + msg.readInt16(); // unknown + msg.readInt16(); // manner + dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 + msg.readInt8(); // karma + dstBeing->setGender( + (msg.readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE); + + // Set these after the gender, as the sprites may be gender-specific + dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom); + dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid); + dstBeing->setSprite(Being::HAT_SPRITE, headTop); + dstBeing->setSprite(Being::SHOE_SPRITE, shoes); + dstBeing->setSprite(Being::GLOVES_SPRITE, gloves); + dstBeing->setHairStyle(hairStyle, hairColor); + + if (msg.getId() == SMSG_BEING_MOVE) + { + Uint16 srcX, srcY, dstX, dstY; + msg.readCoordinatePair(srcX, srcY, dstX, dstY); + dstBeing->setAction(Being::STAND); + dstBeing->mX = srcX; + dstBeing->mY = srcY; + dstBeing->setDestination(dstX, dstY); + } + else + { + Uint8 dir; + msg.readCoordinates(dstBeing->mX, dstBeing->mY, dir); + dstBeing->setDirection(dir); + } + + msg.readInt8(); // unknown + msg.readInt8(); // unknown + msg.readInt8(); // unknown / sit + + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + break; + + case SMSG_BEING_MOVE2: + /* + * A simplified movement packet, used by the + * later versions of eAthena for both mobs and + * players + */ + dstBeing = beingManager->findBeing(msg.readInt32()); + + Uint16 srcX, srcY, dstX, dstY; + msg.readCoordinatePair(srcX, srcY, dstX, dstY); + msg.readInt32(); // Server tick + + /* + * This packet doesn't have enough info to actually + * create a new being, so if the being isn't found, + * we'll just pretend the packet didn't happen + */ + + if (dstBeing) { + dstBeing->setAction(Being::STAND); + dstBeing->mX = srcX; + dstBeing->mY = srcY; + dstBeing->setDestination(dstX, dstY); + } + + break; + + case SMSG_BEING_REMOVE: + // A being should be removed or has died + dstBeing = beingManager->findBeing(msg.readInt32()); + + 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->handleDeath(); + + if (msg.readInt8() == 1) + dstBeing->setAction(Being::DEAD); + else + beingManager->destroyBeing(dstBeing); + + break; + + case SMSG_BEING_ACTION: + srcBeing = beingManager->findBeing(msg.readInt32()); + dstBeing = beingManager->findBeing(msg.readInt32()); + msg.readInt32(); // server tick + msg.readInt32(); // src speed + msg.readInt32(); // dst speed + param1 = msg.readInt16(); + msg.readInt16(); // param 2 + type = msg.readInt8(); + msg.readInt16(); // param 3 + + switch (type) + { + case 0x0a: // Critical Damage + if (dstBeing) + dstBeing->showCrit(); + case 0x00: // Damage + if (dstBeing) + dstBeing->takeDamage(param1); + if (srcBeing) + srcBeing->handleAttack(dstBeing, param1); + break; + + case 0x02: // Sit + if (srcBeing) + { + srcBeing->mFrame = 0; + srcBeing->setAction(Being::SIT); + } + break; + + case 0x03: // Stand up + if (srcBeing) + { + srcBeing->mFrame = 0; + srcBeing->setAction(Being::STAND); + } + break; + } + break; + + case SMSG_BEING_SELFEFFECT: { + id = (Uint32)msg.readInt32(); + if (!beingManager->findBeing(id)) + break; + + int effectType = msg.readInt32(); + Being* being = beingManager->findBeing(id); + + effectManager->trigger(effectType, being); + + break; + } + + case SMSG_BEING_EMOTION: + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) + { + break; + } + + if (player_relations.hasPermission(dstBeing, PlayerRelation::EMOTE)) + dstBeing->setEmote(msg.readInt8(), EMOTION_TIME); + + break; + + case SMSG_BEING_CHANGE_LOOKS: + case SMSG_BEING_CHANGE_LOOKS2: + { + /* + * SMSG_BEING_CHANGE_LOOKS (0x00c3) and + * SMSG_BEING_CHANGE_LOOKS2 (0x01d7) do basically the same + * thing. The difference is that ...LOOKS carries a single + * 8 bit value, where ...LOOKS2 carries two 16 bit values. + * + * If type = 2, then the first 16 bit value is the weapon ID, + * and the second 16 bit value is the shield ID. If no + * shield is equipped, or type is not 2, then the second + * 16 bit value will be 0. + */ + + if (!(dstBeing = beingManager->findBeing(msg.readInt32()))) + { + break; + } + + int type = msg.readInt8(); + int id = 0; + int id2 = 0; + + if (msg.getId() == SMSG_BEING_CHANGE_LOOKS) { + id = msg.readInt8(); + } else { // SMSG_BEING_CHANGE_LOOKS2 + id = msg.readInt16(); + id2 = msg.readInt16(); + } + + switch (type) { + case 1: // eAthena LOOK_HAIR + dstBeing->setHairStyle(id, -1); + break; + case 2: // Weapon ID in id, Shield ID in id2 + dstBeing->setSprite(Being::WEAPON_SPRITE, id); + dstBeing->setSprite(Being::SHIELD_SPRITE, id2); + break; + case 3: // Change lower headgear for eAthena, pants for us + dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, id); + break; + case 4: // Change upper headgear for eAthena, hat for us + dstBeing->setSprite(Being::HAT_SPRITE, id); + break; + case 5: // Change middle headgear for eathena, armor for us + dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, id); + break; + case 6: // eAthena LOOK_HAIR_COLOR + dstBeing->setHairStyle(-1, id); + break; + case 8: // eAthena LOOK_SHIELD + dstBeing->setSprite(Being::SHIELD_SPRITE, id); + break; + case 9: // eAthena LOOK_SHOES + dstBeing->setSprite(Being::SHOE_SPRITE, id); + break; + case 10: // LOOK_GLOVES + dstBeing->setSprite(Being::GLOVES_SPRITE, id); + break; + case 11: // LOOK_CAPE + dstBeing->setSprite(Being::CAPE_SPRITE, id); + break; + case 12: + dstBeing->setSprite(Being::MISC1_SPRITE, id); + break; + case 13: + dstBeing->setSprite(Being::MISC2_SPRITE, id); + break; + default: + logger->log("SMSG_BEING_CHANGE_LOOKS: unsupported type: " + "%d, id: %d", type, id); + break; + } + } + break; + + case SMSG_BEING_NAME_RESPONSE: + if ((dstBeing = beingManager->findBeing(msg.readInt32()))) + { + dstBeing->setName(msg.readString(24)); + } + break; + + case SMSG_PLAYER_UPDATE_1: + case SMSG_PLAYER_UPDATE_2: + case SMSG_PLAYER_MOVE: + // An update about a player, potentially including movement. + id = msg.readInt32(); + speed = msg.readInt16(); + stunMode = msg.readInt16(); // opt1; Aethyra use this as cape + statusEffects = msg.readInt16(); // opt2; Aethyra use this as misc1 + statusEffects |= ((Uint32) msg.readInt16()) + << 16; // status.options; Aethyra uses this as misc2 + job = msg.readInt16(); + + dstBeing = beingManager->findBeing(id); + + if (!dstBeing) + { + dstBeing = beingManager->createBeing(id, job); + } + + dstBeing->setWalkSpeed(speed); + dstBeing->mJob = job; + hairStyle = msg.readInt16(); + weapon = msg.readInt16(); + shield = msg.readInt16(); + headBottom = msg.readInt16(); + + if (msg.getId() == SMSG_PLAYER_MOVE) + { + msg.readInt32(); // server tick + } + + 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 + msg.readInt32(); // guild + msg.readInt16(); // emblem + msg.readInt16(); // manner + dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 + msg.readInt8(); // karma + dstBeing->setGender( + (msg.readInt8() == 0) ? GENDER_FEMALE : GENDER_MALE); + + // Set these after the gender, as the sprites may be gender-specific + dstBeing->setSprite(Being::WEAPON_SPRITE, weapon); + dstBeing->setSprite(Being::SHIELD_SPRITE, shield); + dstBeing->setSprite(Being::BOTTOMCLOTHES_SPRITE, headBottom); + dstBeing->setSprite(Being::TOPCLOTHES_SPRITE, headMid); + dstBeing->setSprite(Being::HAT_SPRITE, headTop); + //dstBeing->setSprite(Being::CAPE_SPRITE, cape); + //dstBeing->setSprite(Being::MISC1_SPRITE, misc1); + //dstBeing->setSprite(Being::MISC2_SPRITE, misc2); + dstBeing->setHairStyle(hairStyle, hairColor); + + if (msg.getId() == SMSG_PLAYER_MOVE) + { + Uint16 srcX, srcY, dstX, dstY; + msg.readCoordinatePair(srcX, srcY, dstX, dstY); + dstBeing->mX = srcX; + dstBeing->mY = srcY; + dstBeing->setDestination(dstX, dstY); + } + else + { + Uint8 dir; + msg.readCoordinates(dstBeing->mX, dstBeing->mY, dir); + dstBeing->setDirection(dir); + } + + gmstatus = msg.readInt16(); + if (gmstatus & 0x80) + dstBeing->setGM(); + + if (msg.getId() == SMSG_PLAYER_UPDATE_1) + { + 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) + { + msg.readInt8(); // unknown + } + + msg.readInt8(); // Lv + msg.readInt8(); // unknown + + dstBeing->mWalkTime = tick_time; + dstBeing->mFrame = 0; + + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + break; + + 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. + */ + + id = msg.readInt32(); + if (mSync || id != player_node->getId()) { + dstBeing = beingManager->findBeing(id); + if (dstBeing) { + dstBeing->mX = msg.readInt16(); + dstBeing->mY = msg.readInt16(); + if (dstBeing->mAction == Being::WALK) { + dstBeing->mFrame = 0; + dstBeing->setAction(Being::STAND); + } + } + } + break; + + 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... + */ + break; + + case 0x0119: + // Change in players' flags + id = msg.readInt32(); + dstBeing = beingManager->findBeing(id); + stunMode = msg.readInt16(); + statusEffects = msg.readInt16(); + statusEffects |= ((Uint32) msg.readInt16()) << 16; + msg.readInt8(); + + if (dstBeing) { + dstBeing->setStunMode(stunMode); + dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); + dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + } + break; + + case 0x0196: + // Status change + status = msg.readInt16(); + id = msg.readInt32(); + flag = msg.readInt8(); // 0: stop, 1: start + + dstBeing = beingManager->findBeing(id); + if (dstBeing) + dstBeing->setStatusEffect(status, flag); + break; + } +} diff --git a/src/net/ea/beinghandler.h b/src/net/ea/beinghandler.h new file mode 100644 index 00000000..16a7c8d6 --- /dev/null +++ b/src/net/ea/beinghandler.h @@ -0,0 +1,39 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_BEINGHANDLER_H +#define NET_BEINGHANDLER_H + +#include "../messagehandler.h" + +class BeingHandler : public MessageHandler +{ + public: + BeingHandler(bool enableSync); + + void handleMessage(MessageIn &msg); + + private: + // Should we honor server "Stop Walking" packets + bool mSync; +}; + +#endif diff --git a/src/net/ea/buysellhandler.cpp b/src/net/ea/buysellhandler.cpp new file mode 100644 index 00000000..480c71b8 --- /dev/null +++ b/src/net/ea/buysellhandler.cpp @@ -0,0 +1,133 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <SDL_types.h> + +#include "buysellhandler.h" +#include "../messagein.h" +#include "protocol.h" + +#include "../../beingmanager.h" +#include "../../inventory.h" +#include "../../item.h" +#include "../../localplayer.h" +#include "../../npc.h" + +#include "../../gui/buy.h" +#include "../../gui/chat.h" +#include "../../gui/sell.h" + +#include "../../utils/gettext.h" + +extern BuyDialog *buyDialog; +extern Window *buySellDialog; +extern SellDialog *sellDialog; + +BuySellHandler::BuySellHandler() +{ + static const Uint16 _messages[] = { + SMSG_NPC_BUY_SELL_CHOICE, + SMSG_NPC_BUY, + SMSG_NPC_SELL, + SMSG_NPC_BUY_RESPONSE, + SMSG_NPC_SELL_RESPONSE, + 0 + }; + handledMessages = _messages; +} + +void BuySellHandler::handleMessage(MessageIn &msg) +{ + int n_items; + switch (msg.getId()) + { + case SMSG_NPC_BUY_SELL_CHOICE: + buyDialog->setVisible(false); + buyDialog->reset(); + sellDialog->setVisible(false); + sellDialog->reset(); + buySellDialog->setVisible(true); + current_npc = dynamic_cast<NPC*>(beingManager->findBeing(msg.readInt32())); + break; + + case SMSG_NPC_BUY: + msg.readInt16(); // length + n_items = (msg.getLength() - 4) / 11; + buyDialog->reset(); + buyDialog->setMoney(player_node->getMoney()); + buyDialog->setVisible(true); + + for (int k = 0; k < n_items; k++) + { + Sint32 value = msg.readInt32(); + msg.readInt32(); // DCvalue + msg.readInt8(); // type + Sint16 itemId = msg.readInt16(); + buyDialog->addItem(itemId, 0, value); + } + break; + + case SMSG_NPC_SELL: + msg.readInt16(); // length + n_items = (msg.getLength() - 4) / 10; + if (n_items > 0) { + sellDialog->setMoney(player_node->getMoney()); + sellDialog->reset(); + sellDialog->setVisible(true); + + for (int k = 0; k < n_items; k++) + { + Sint16 index = msg.readInt16(); + Sint32 value = msg.readInt32(); + msg.readInt32(); // OCvalue + + Item *item = player_node->getInventory()->getItem(index); + if (item && !(item->isEquipped())) { + sellDialog->addItem(item, value); + } + } + } + else { + chatWindow->chatLog(_("Nothing to sell"), BY_SERVER); + if (current_npc) current_npc->handleDeath(); + } + break; + + case SMSG_NPC_BUY_RESPONSE: + if (msg.readInt8() == 0) { + chatWindow->chatLog(_("Thanks for buying"), BY_SERVER); + } else { + // Reset player money since buy dialog already assumed purchase + // would go fine + buyDialog->setMoney(player_node->getMoney()); + chatWindow->chatLog(_("Unable to buy"), BY_SERVER); + } + break; + + case SMSG_NPC_SELL_RESPONSE: + if (msg.readInt8() == 0) { + chatWindow->chatLog(_("Thanks for selling"), BY_SERVER); + } else { + chatWindow->chatLog(_("Unable to sell"), BY_SERVER); + } + break; + } +} diff --git a/src/net/ea/buysellhandler.h b/src/net/ea/buysellhandler.h new file mode 100644 index 00000000..5bf58d8e --- /dev/null +++ b/src/net/ea/buysellhandler.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_BUYSELLHANDLER_H +#define NET_BUYSELLHANDLER_H + +#include "../messagehandler.h" + +class BuySellHandler : public MessageHandler +{ + public: + BuySellHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif diff --git a/src/net/ea/charserverhandler.cpp b/src/net/ea/charserverhandler.cpp new file mode 100644 index 00000000..0fef3de7 --- /dev/null +++ b/src/net/ea/charserverhandler.cpp @@ -0,0 +1,235 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "charserverhandler.h" +#include "../messagein.h" +#include "protocol.h" + +#include "../../game.h" +#include "../../localplayer.h" +#include "../../log.h" +#include "../../logindata.h" +#include "../../main.h" + +#include "../../gui/char_select.h" +#include "../../gui/ok_dialog.h" + +#include "../../utils/gettext.h" +#include "../../utils/stringutils.h" + +CharServerHandler::CharServerHandler(): + mCharCreateDialog(0) +{ + static const Uint16 _messages[] = { + SMSG_CONNECTION_PROBLEM, + 0x006b, + 0x006c, + 0x006d, + 0x006e, + 0x006f, + 0x0070, + 0x0071, + 0 + }; + handledMessages = _messages; +} + +void CharServerHandler::handleMessage(MessageIn &msg) +{ + int slot, flags, code; + LocalPlayer *tempPlayer; + + logger->log("CharServerHandler: Packet ID: %x, Length: %d", + msg.getId(), msg.getLength()); + switch (msg.getId()) + { + case SMSG_CONNECTION_PROBLEM: + code = msg.readInt8(); + logger->log("Connection problem: %i", code); + + switch (code) { + case 0: + errorMessage = _("Authentication failed"); + break; + case 1: + errorMessage = _("Map server(s) offline"); + break; + case 2: + errorMessage = _("This account is already logged in"); + break; + case 3: + errorMessage = _("Speed hack detected"); + break; + case 8: + errorMessage = _("Duplicated login"); + break; + default: + errorMessage = _("Unknown connection error"); + break; + } + state = STATE_ERROR; + break; + + case 0x006b: + msg.skip(2); // Length word + flags = msg.readInt32(); // Aethyra extensions flags + logger->log("Server flags are: %x", flags); + msg.skip(16); // Unused + + // Derive number of characters from message length + n_character = (msg.getLength() - 24) / 106; + + for (int i = 0; i < n_character; i++) + { + tempPlayer = readPlayerData(msg, slot); + mCharInfo->select(slot); + mCharInfo->setEntry(tempPlayer); + logger->log("CharServer: Player: %s (%d)", + tempPlayer->getName().c_str(), slot); + } + + state = STATE_CHAR_SELECT; + break; + + case 0x006c: + switch (msg.readInt8()) { + case 0: + errorMessage = _("Access denied"); + break; + case 1: + errorMessage = _("Cannot use this ID"); + break; + default: + errorMessage = _("Unknown failure to select character"); + break; + } + mCharInfo->unlock(); + break; + + case 0x006d: + tempPlayer = readPlayerData(msg, slot); + mCharInfo->unlock(); + mCharInfo->select(slot); + mCharInfo->setEntry(tempPlayer); + n_character++; + + // Close the character create dialog + if (mCharCreateDialog) + { + mCharCreateDialog->scheduleDelete(); + mCharCreateDialog = 0; + } + break; + + case 0x006e: + new OkDialog(_("Error"), _("Failed to create character. Most likely" + " the name is already taken.")); + + if (mCharCreateDialog) + mCharCreateDialog->unlock(); + break; + + case 0x006f: + delete mCharInfo->getEntry(); + mCharInfo->setEntry(0); + mCharInfo->unlock(); + n_character--; + new OkDialog(_("Info"), _("Player deleted")); + break; + + case 0x0070: + mCharInfo->unlock(); + new OkDialog(_("Error"), _("Failed to delete character.")); + break; + + case 0x0071: + player_node = mCharInfo->getEntry(); + slot = mCharInfo->getPos(); + msg.skip(4); // CharID, must be the same as player_node->charID + map_path = msg.readString(16); + mLoginData->hostname = ipToString(msg.readInt32()); + mLoginData->port = msg.readInt16(); + mCharInfo->unlock(); + mCharInfo->select(0); + // Clear unselected players infos + do + { + LocalPlayer *tmp = mCharInfo->getEntry(); + if (tmp != player_node) + { + delete tmp; + mCharInfo->setEntry(0); + } + mCharInfo->next(); + } while (mCharInfo->getPos()); + + mCharInfo->select(slot); + state = STATE_CONNECTING; + break; + } +} + +LocalPlayer *CharServerHandler::readPlayerData(MessageIn &msg, int &slot) +{ + LocalPlayer *tempPlayer = new LocalPlayer(mLoginData->account_ID, 0, NULL); + tempPlayer->setGender( + (mLoginData->sex == 0) ? GENDER_FEMALE : GENDER_MALE); + + tempPlayer->mCharId = msg.readInt32(); + tempPlayer->setXp(msg.readInt32()); + tempPlayer->setMoney(msg.readInt32()); + tempPlayer->mJobXp = msg.readInt32(); + tempPlayer->mJobLevel = msg.readInt32(); + tempPlayer->setSprite(Being::SHOE_SPRITE, msg.readInt16()); + tempPlayer->setSprite(Being::GLOVES_SPRITE, msg.readInt16()); + tempPlayer->setSprite(Being::CAPE_SPRITE, msg.readInt16()); + tempPlayer->setSprite(Being::MISC1_SPRITE, msg.readInt16()); + msg.readInt32(); // option + msg.readInt32(); // karma + msg.readInt32(); // manner + msg.skip(2); // unknown + tempPlayer->setHp(msg.readInt16()); + tempPlayer->setMaxHp(msg.readInt16()); + tempPlayer->mMp = msg.readInt16(); + tempPlayer->mMaxMp = msg.readInt16(); + msg.readInt16(); // speed + msg.readInt16(); // class + int hairStyle = msg.readInt16(); + Uint16 weapon = msg.readInt16(); + tempPlayer->setSprite(Being::WEAPON_SPRITE, weapon); + tempPlayer->setLevel(msg.readInt16()); + msg.readInt16(); // skill point + tempPlayer->setSprite(Being::BOTTOMCLOTHES_SPRITE, msg.readInt16()); // head bottom + tempPlayer->setSprite(Being::SHIELD_SPRITE, msg.readInt16()); + tempPlayer->setSprite(Being::HAT_SPRITE, msg.readInt16()); // head option top + tempPlayer->setSprite(Being::TOPCLOTHES_SPRITE, msg.readInt16()); // head option mid + int hairColor = msg.readInt16(); + tempPlayer->setHairStyle(hairStyle, hairColor); + tempPlayer->setSprite(Being::MISC2_SPRITE, msg.readInt16()); + tempPlayer->setName(msg.readString(24)); + for (int i = 0; i < 6; i++) { + tempPlayer->mAttr[i] = msg.readInt8(); + } + slot = msg.readInt8(); // character slot + msg.readInt8(); // unknown + + return tempPlayer; +} diff --git a/src/net/ea/charserverhandler.h b/src/net/ea/charserverhandler.h new file mode 100644 index 00000000..237f5e49 --- /dev/null +++ b/src/net/ea/charserverhandler.h @@ -0,0 +1,65 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_CHARSERVERHANDLER_H +#define NET_CHARSERVERHANDLER_H + +#include "../messagehandler.h" + +#include "../../lockedarray.h" + +class CharCreateDialog; +class LocalPlayer; +class LoginData; + +/** + * Deals with incoming messages from the character server. + */ +class CharServerHandler : public MessageHandler +{ + public: + CharServerHandler(); + + void handleMessage(MessageIn &msg); + + void setCharInfo(LockedArray<LocalPlayer*> *charInfo) + { mCharInfo = charInfo; } + + void setLoginData(LoginData *loginData) + { mLoginData = loginData; } + + /** + * Sets the character create dialog. The handler will clean up this + * dialog when a new character is succesfully created, and will unlock + * the dialog when a new character failed to be created. + */ + void setCharCreateDialog(CharCreateDialog *window) + { mCharCreateDialog = window; } + + protected: + LoginData *mLoginData; + LockedArray<LocalPlayer*> *mCharInfo; + CharCreateDialog *mCharCreateDialog; + + LocalPlayer* readPlayerData(MessageIn &msg, int &slot); +}; + +#endif diff --git a/src/net/ea/chathandler.cpp b/src/net/ea/chathandler.cpp new file mode 100644 index 00000000..0293f987 --- /dev/null +++ b/src/net/ea/chathandler.cpp @@ -0,0 +1,175 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <SDL_types.h> +#include <string> + +#include "chathandler.h" +#include "../messagein.h" +#include "protocol.h" + +#include "../../being.h" +#include "../../beingmanager.h" +#include "../../game.h" +#include "../../player_relations.h" + +#include "../../gui/chat.h" + +#include "../../utils/gettext.h" +#include "../../utils/stringutils.h" + +extern Being *player_node; + +#define SERVER_NAME "Server" + +ChatHandler::ChatHandler() +{ + static const Uint16 _messages[] = { + SMSG_BEING_CHAT, + SMSG_PLAYER_CHAT, + SMSG_WHISPER, + SMSG_WHISPER_RESPONSE, + SMSG_GM_CHAT, + SMSG_WHO_ANSWER, + 0x10c, // MVP + 0 + }; + handledMessages = _messages; +} + +void ChatHandler::handleMessage(MessageIn &msg) +{ + Being *being; + std::string chatMsg; + std::string nick; + Sint16 chatMsgLength; + + switch (msg.getId()) + { + case SMSG_WHISPER_RESPONSE: + switch (msg.readInt8()) + { + case 0x00: + // comment out since we'll local echo in chat.cpp instead, then only report failures + //chatWindow->chatLog("Whisper sent", BY_SERVER); + break; + case 0x01: + chatWindow->chatLog(_("Whisper could not be sent, user is offline"), BY_SERVER); + break; + case 0x02: + chatWindow->chatLog(_("Whisper could not be sent, ignored by user"), BY_SERVER); + break; + } + break; + + // Received whisper + case SMSG_WHISPER: + chatMsgLength = msg.readInt16() - 28; + nick = msg.readString(24); + + if (chatMsgLength <= 0) + break; + + chatMsg = msg.readString(chatMsgLength); + if (nick != SERVER_NAME) + chatMsg = nick + " : " + chatMsg; + + if (nick == SERVER_NAME) + chatWindow->chatLog(chatMsg, BY_SERVER); + else { + if (player_relations.hasPermission(nick, PlayerRelation::WHISPER)) + chatWindow->chatLog(chatMsg, ACT_WHISPER); + } + + break; + + // Received speech from being + case SMSG_BEING_CHAT: { + chatMsgLength = msg.readInt16() - 8; + being = beingManager->findBeing(msg.readInt32()); + + if (!being || chatMsgLength <= 0) + { + break; + } + + chatMsg = msg.readString(chatMsgLength); + + std::string::size_type pos = chatMsg.find(" : ", 0); + std::string sender_name = ((pos == std::string::npos) + ? "" + : chatMsg.substr(0, pos)); + + // We use getIgnorePlayer instead of ignoringPlayer here because ignorePlayer' side + // effects are triggered right below for Being::IGNORE_SPEECH_FLOAT. + if (player_relations.checkPermissionSilently(sender_name, PlayerRelation::SPEECH_LOG)) + chatWindow->chatLog(chatMsg, BY_OTHER); + + chatMsg.erase(0, pos + 3); + trim(chatMsg); + + if (player_relations.hasPermission(sender_name, PlayerRelation::SPEECH_FLOAT)) + being->setSpeech(chatMsg, SPEECH_TIME); + break; + } + + case SMSG_PLAYER_CHAT: + case SMSG_GM_CHAT: { + chatMsgLength = msg.readInt16() - 4; + + if (chatMsgLength <= 0) + { + break; + } + + chatMsg = msg.readString(chatMsgLength); + std::string::size_type pos = chatMsg.find(" : ", 0); + + if (msg.getId() == SMSG_PLAYER_CHAT) + { + chatWindow->chatLog(chatMsg, BY_PLAYER); + + if (pos != std::string::npos) + chatMsg.erase(0, pos + 3); + + trim(chatMsg); + + player_node->setSpeech(chatMsg, SPEECH_TIME); + } + else + { + chatWindow->chatLog(chatMsg, BY_GM); + } + break; + } + + case SMSG_WHO_ANSWER: + chatWindow->chatLog("Online users: " + toString(msg.readInt32()), + BY_SERVER); + break; + + case 0x010c: + // Display MVP player + msg.readInt32(); // id + chatWindow->chatLog("MVP player", BY_SERVER); + break; + } +} diff --git a/src/gui/hbox.h b/src/net/ea/chathandler.h index 4b241383..8207b1d5 100644 --- a/src/gui/hbox.h +++ b/src/net/ea/chathandler.h @@ -1,33 +1,35 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef HBOX_H -#define HBOX_H +#ifndef NET_CHATHANDLER_H +#define NET_CHATHANDLER_H -#include "box.h" +#include "../messagehandler.h" -class HBox : public Box +class ChatHandler : public MessageHandler { - public: - void draw(gcn::Graphics *); + public: + ChatHandler(); + + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/ea/equipmenthandler.cpp b/src/net/ea/equipmenthandler.cpp new file mode 100644 index 00000000..19063daf --- /dev/null +++ b/src/net/ea/equipmenthandler.cpp @@ -0,0 +1,190 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "equipmenthandler.h" +#include "../messagein.h" +#include "protocol.h" + +#include "../../equipment.h" +#include "../../inventory.h" +#include "../../item.h" +#include "../../localplayer.h" +#include "../../log.h" + +#include "../../gui/chat.h" + +#include "../../utils/gettext.h" + +EquipmentHandler::EquipmentHandler() +{ + static const Uint16 _messages[] = { + SMSG_PLAYER_EQUIPMENT, + SMSG_PLAYER_EQUIP, + SMSG_PLAYER_UNEQUIP, + SMSG_PLAYER_ARROW_EQUIP, + SMSG_PLAYER_ATTACK_RANGE, + 0 + }; + handledMessages = _messages; +} + +void EquipmentHandler::handleMessage(MessageIn &msg) +{ + Sint32 itemCount; + Sint16 index, equipPoint, itemId; + Sint8 type; + int mask, position; + Item *item; + Inventory *inventory = player_node->getInventory(); + + switch (msg.getId()) + { + case SMSG_PLAYER_EQUIPMENT: + msg.readInt16(); // length + itemCount = (msg.getLength() - 4) / 20; + + for (int loop = 0; loop < itemCount; loop++) + { + index = msg.readInt16(); + itemId = msg.readInt16(); + msg.readInt8(); // type + msg.readInt8(); // identify flag + msg.readInt16(); // equip type + equipPoint = msg.readInt16(); + msg.readInt8(); // attribute + msg.readInt8(); // refine + msg.skip(8); // card + + inventory->setItem(index, itemId, 1, true); + + if (equipPoint) + { + mask = 1; + position = 0; + while (!(equipPoint & mask)) + { + mask <<= 1; + position++; + } + item = inventory->getItem(index); + player_node->mEquipment->setEquipment(position, index); + } + } + break; + + case SMSG_PLAYER_EQUIP: + index = msg.readInt16(); + equipPoint = msg.readInt16(); + type = msg.readInt8(); + + logger->log("Equipping: %i %i %i", index, equipPoint, type); + + if (!type) { + chatWindow->chatLog(_("Unable to equip."), BY_SERVER); + break; + } + + if (!equipPoint) { + // No point given, no point in searching + break; + } + + /* + * 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)) { + mask <<= 1; + position++; + } + logger->log("Position %i", position); + + item = player_node->getInventory()->getItem(player_node->mEquipment->getEquipment(position)); + + // Unequip any existing equipped item in this position + if (item) { + item->setEquipped(false); + } + + item = inventory->getItem(index); + player_node->mEquipment->setEquipment(position, index); + break; + + case SMSG_PLAYER_UNEQUIP: + index = msg.readInt16(); + equipPoint = msg.readInt16(); + type = msg.readInt8(); + + if (!type) { + chatWindow->chatLog(_("Unable to unequip."), BY_SERVER); + break; + } + + if (!equipPoint) { + // No point given, no point in searching + break; + } + + mask = 1; + position = 0; + while (!(equipPoint & mask)) { + mask <<= 1; + position++; + } + + item = inventory->getItem(index); + if (!item) + break; + + item->setEquipped(false); + + 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); + break; + + case SMSG_PLAYER_ATTACK_RANGE: + player_node->setAttackRange(msg.readInt16()); + break; + + case SMSG_PLAYER_ARROW_EQUIP: + index = msg.readInt16(); + + if (index <= 1) + break; + + item = inventory->getItem(index); + + if (item) { + item->setEquipped(true); + player_node->mEquipment->setArrows(index); + logger->log("Arrows equipped: %i", index); + } + break; + } +} diff --git a/src/net/ea/equipmenthandler.h b/src/net/ea/equipmenthandler.h new file mode 100644 index 00000000..fe4a7ecc --- /dev/null +++ b/src/net/ea/equipmenthandler.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_EQUIPMENTHANDLER_H +#define NET_EQUIPMENTHANDLER_H + +#include "../messagehandler.h" + +class EquipmentHandler : public MessageHandler +{ + public: + EquipmentHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif diff --git a/src/net/ea/inventoryhandler.cpp b/src/net/ea/inventoryhandler.cpp new file mode 100644 index 00000000..71eee291 --- /dev/null +++ b/src/net/ea/inventoryhandler.cpp @@ -0,0 +1,227 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <SDL_types.h> + +#include "inventoryhandler.h" +#include "../messagein.h" +#include "protocol.h" + +#include "../../inventory.h" +#include "../../item.h" +#include "../../itemshortcut.h" +#include "../../localplayer.h" +#include "../../log.h" + +#include "../../gui/chat.h" + +#include "../../resources/iteminfo.h" + +#include "../../utils/gettext.h" +#include "../../utils/strprintf.h" +#include "../../utils/stringutils.h" + +InventoryHandler::InventoryHandler() +{ + static const Uint16 _messages[] = { + SMSG_PLAYER_INVENTORY, + SMSG_PLAYER_INVENTORY_ADD, + 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; +} + +void InventoryHandler::handleMessage(MessageIn &msg) +{ + Sint32 number; + 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: + 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++) { + index = msg.readInt16(); + itemId = msg.readInt16(); + 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; + + case SMSG_PLAYER_INVENTORY_ADD: + index = msg.readInt16(); + amount = msg.readInt16(); + itemId = msg.readInt16(); + identified = msg.readInt8(); + msg.readInt8(); // attribute + msg.readInt8(); // refine + for (int i = 0; i < 4; i++) + cards[i] = msg.readInt16(); + equipType = msg.readInt16(); + itemType = msg.readInt8(); + + if (msg.readInt8() > 0) { + chatWindow->chatLog(_("Unable to pick up item"), BY_SERVER); + } else { + const ItemInfo &itemInfo = ItemDB::get(itemId); + const std::string amountStr = + (amount > 1) ? toString(amount) : "a"; + chatWindow->chatLog(strprintf(_("You picked up %s %s"), + amountStr.c_str(), itemInfo.getName().c_str()), BY_SERVER); + + if (Item *item = inventory->getItem(index)) { + item->setId(itemId); + item->increaseQuantity(amount); + } else { + inventory->setItem(index, itemId, amount, equipType != 0); + } + } + break; + + case SMSG_PLAYER_INVENTORY_REMOVE: + index = msg.readInt16(); + amount = msg.readInt16(); + if (Item *item = inventory->getItem(index)) { + item->increaseQuantity(-amount); + if (item->getQuantity() == 0) + inventory->removeItemAt(index); + } + break; + + case SMSG_PLAYER_INVENTORY_USE: + index = msg.readInt16(); + msg.readInt16(); // item id + msg.readInt32(); // id + amount = msg.readInt16(); + msg.readInt8(); // type + + if (Item *item = inventory->getItem(index)) + item->setQuantity(amount); + break; + + case SMSG_ITEM_USE_RESPONSE: + index = msg.readInt16(); + amount = msg.readInt16(); + + if (msg.readInt8() == 0) { + chatWindow->chatLog(_("Failed to use item"), BY_SERVER); + } else { + if (Item *item = inventory->getItem(index)) + item->setQuantity(amount); + } + break; + + case SMSG_PLAYER_STORAGE_STATUS: + /* + * Basic slots used vs total slots info + * We don't really need this information, but this is + * the closest we get to an "Open Storage" packet + * from the server. It always comes after the two + * SMSG_PLAYER_STORAGE_... packets that update + * storage contents. + */ + logger->log("Received SMSG_PLAYER_STORAGE_STATUS"); + player_node->setInStorage(true); + break; + + case SMSG_PLAYER_STORAGE_ADD: + /* + * Move an item into storage + */ + break; + + case SMSG_PLAYER_STORAGE_REMOVE: + /* + * Move an item out of storage + */ + break; + + case SMSG_PLAYER_STORAGE_CLOSE: + /* + * Storage access has been closed + */ + player_node->setInStorage(false); + logger->log("Received SMSG_PLAYER_STORAGE_CLOSE"); + break; + } +} diff --git a/src/net/ea/inventoryhandler.h b/src/net/ea/inventoryhandler.h new file mode 100644 index 00000000..b2e469fa --- /dev/null +++ b/src/net/ea/inventoryhandler.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_INVENTORYHANDLER_H +#define NET_INVENTORYHANDLER_H + +#include "../messagehandler.h" + +class InventoryHandler : public MessageHandler +{ + public: + InventoryHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif diff --git a/src/net/ea/loginhandler.cpp b/src/net/ea/loginhandler.cpp new file mode 100644 index 00000000..3f58f2c0 --- /dev/null +++ b/src/net/ea/loginhandler.cpp @@ -0,0 +1,158 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "loginhandler.h" +#include "../messagein.h" +#include "protocol.h" + +#include "../../log.h" +#include "../../logindata.h" +#include "../../main.h" +#include "../../serverinfo.h" + +#include "../../utils/gettext.h" +#include "../../utils/strprintf.h" +#include "../../utils/stringutils.h" + +extern SERVER_INFO **server_info; + +LoginHandler::LoginHandler() +{ + static const Uint16 _messages[] = { + SMSG_CONNECTION_PROBLEM, + SMSG_UPDATE_HOST, + 0x0069, + 0x006a, + 0 + }; + handledMessages = _messages; +} + +void LoginHandler::handleMessage(MessageIn &msg) +{ + int code; + + switch (msg.getId()) + { + case SMSG_CONNECTION_PROBLEM: + code = msg.readInt8(); + logger->log("Connection problem: %i", code); + + switch (code) { + case 0: + errorMessage = _("Authentication failed"); + break; + case 1: + errorMessage = _("No servers available"); + break; + case 2: + errorMessage = _("This account is already logged in"); + break; + default: + errorMessage = _("Unknown connection error"); + break; + } + state = STATE_ERROR; + break; + + case SMSG_UPDATE_HOST: + int len; + + len = msg.readInt16() - 4; + mUpdateHost = msg.readString(len); + + logger->log("Received update host \"%s\" from login server", + mUpdateHost.c_str()); + break; + + case 0x0069: + // Skip the length word + msg.skip(2); + + n_server = (msg.getLength() - 47) / 32; + server_info = + (SERVER_INFO**) malloc(sizeof(SERVER_INFO*) * n_server); + + mLoginData->session_ID1 = msg.readInt32(); + mLoginData->account_ID = msg.readInt32(); + mLoginData->session_ID2 = msg.readInt32(); + msg.skip(30); // unknown + mLoginData->sex = msg.readInt8(); + + for (int i = 0; i < n_server; i++) + { + server_info[i] = new SERVER_INFO; + + server_info[i]->address = msg.readInt32(); + server_info[i]->port = msg.readInt16(); + server_info[i]->name = msg.readString(20); + server_info[i]->online_users = msg.readInt32(); + server_info[i]->updateHost = mUpdateHost; + msg.skip(2); // unknown + + logger->log("Network: Server: %s (%s:%d)", + server_info[i]->name.c_str(), + ipToString(server_info[i]->address), + server_info[i]->port); + } + state = STATE_CHAR_SERVER; + break; + + case 0x006a: + code = msg.readInt8(); + logger->log("Login::error code: %i", code); + + switch (code) { + case 0: + errorMessage = _("Unregistered ID"); + break; + case 1: + errorMessage = _("Wrong password"); + break; + case 2: + errorMessage = _("Account expired"); + break; + case 3: + errorMessage = _("Rejected from server"); + break; + case 4: + + errorMessage = _("You have been permanently banned from " + "the game. Please contact the GM Team."); + break; + case 6: + errorMessage = strprintf(_("You have been temporarily " + "banned from the game until " + "%s.\n Please contact the GM " + "team via the forums."), + msg.readString(20).c_str()); + break; + case 9: + errorMessage = _("This user name is already taken"); + break; + default: + errorMessage = _("Unknown error"); + break; + } + state = STATE_ERROR; + break; + } +} diff --git a/src/net/ea/loginhandler.h b/src/net/ea/loginhandler.h new file mode 100644 index 00000000..c2ba5083 --- /dev/null +++ b/src/net/ea/loginhandler.h @@ -0,0 +1,45 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_LOGINHANDLER_H +#define NET_LOGINHANDLER_H + +#include <string> + +#include "../messagehandler.h" + +struct LoginData; + +class LoginHandler : public MessageHandler +{ + public: + LoginHandler(); + + void handleMessage(MessageIn &msg); + + void setLoginData(LoginData *loginData) { mLoginData = loginData; }; + + private: + LoginData *mLoginData; + std::string mUpdateHost; +}; + +#endif diff --git a/src/net/ea/maploginhandler.cpp b/src/net/ea/maploginhandler.cpp new file mode 100644 index 00000000..6931024e --- /dev/null +++ b/src/net/ea/maploginhandler.cpp @@ -0,0 +1,76 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "maploginhandler.h" +#include "../messagein.h" +#include "protocol.h" + +#include "../../localplayer.h" +#include "../../log.h" +#include "../../main.h" + +#include "../../utils/gettext.h" + +MapLoginHandler::MapLoginHandler() +{ + static const Uint16 _messages[] = { + SMSG_CONNECTION_PROBLEM, + SMSG_LOGIN_SUCCESS, + 0 + }; + handledMessages = _messages; +} + +void MapLoginHandler::handleMessage(MessageIn &msg) +{ + int code; + unsigned char direction; + + switch (msg.getId()) + { + case SMSG_CONNECTION_PROBLEM: + code = msg.readInt8(); + logger->log("Connection problem: %i", code); + + switch (code) { + case 0: + errorMessage = _("Authentication failed"); + break; + case 2: + errorMessage = _("This account is already logged in"); + break; + default: + errorMessage = _("Unknown connection error"); + break; + } + state = STATE_ERROR; + break; + + case SMSG_LOGIN_SUCCESS: + msg.readInt32(); // server tick + msg.readCoordinates(player_node->mX, player_node->mY, direction); + msg.skip(2); // unknown + logger->log("Protocol: Player start position: (%d, %d), Direction: %d", + player_node->mX, player_node->mY, direction); + state = STATE_GAME; + break; + } +} diff --git a/src/net/ea/maploginhandler.h b/src/net/ea/maploginhandler.h new file mode 100644 index 00000000..1ce5ee79 --- /dev/null +++ b/src/net/ea/maploginhandler.h @@ -0,0 +1,35 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_MAPLOGINHANDLER_H +#define NET_MAPLOGINHANDLER_H + +#include "../messagehandler.h" + +class MapLoginHandler : public MessageHandler +{ + public: + MapLoginHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif diff --git a/src/net/ea/network.cpp b/src/net/ea/network.cpp new file mode 100644 index 00000000..199e94da --- /dev/null +++ b/src/net/ea/network.cpp @@ -0,0 +1,436 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sstream> + +#include "../messagehandler.h" +#include "../messagein.h" +#include "network.h" + +#include "../../log.h" +#include "../../utils/stringutils.h" + +/** Warning: buffers and other variables are shared, + so there can be only one connection active at a time */ + +short packet_lengths[] = { + 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// #0x0040 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -1, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2, + 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6, +// #0x0080 + 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0, + 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6, + 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6, + 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3, +// #0x00C0 + 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27, + 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1, + 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2, + 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10, +// #0x0100 + 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1, + 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16, + 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1, + 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26, +// #0x0140 + 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6, + 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42, + -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182, + 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1, +// #0x0180 + 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6, + 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, 4, 6, 2, 6, + 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4, + 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3, +// #0x01C0 + 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 29, 6, 28, + 8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6, + 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1, + -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10, +// #0x200 + 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const unsigned int BUFFER_SIZE = 65536; + +int networkThread(void *data) +{ + Network *network = static_cast<Network*>(data); + + if (!network->realConnect()) + return -1; + + network->receive(); + + return 0; +} + +Network::Network(): + mSocket(0), + mAddress(), mPort(0), + mInBuffer(new char[BUFFER_SIZE]), + mOutBuffer(new char[BUFFER_SIZE]), + mInSize(0), mOutSize(0), + mToSkip(0), + mState(IDLE), + mWorkerThread(0) +{ + mMutex = SDL_CreateMutex(); +} + +Network::~Network() +{ + clearHandlers(); + + if (mState != IDLE && mState != NET_ERROR) + disconnect(); + + SDL_DestroyMutex(mMutex); + + delete[] mInBuffer; + delete[] mOutBuffer; +} + +bool Network::connect(const std::string &address, short port) +{ + if (mState != IDLE && mState != NET_ERROR) + { + logger->log("Tried to connect an already connected socket!"); + return false; + } + + if (address.empty()) + { + setError("Empty address given to Network::connect()!"); + return false; + } + + logger->log("Network::Connecting to %s:%i", address.c_str(), port); + + mAddress = address; + mPort = port; + + // Reset to sane values + mOutSize = 0; + mInSize = 0; + mToSkip = 0; + + mState = CONNECTING; + mWorkerThread = SDL_CreateThread(networkThread, this); + if (!mWorkerThread) + { + setError("Unable to create network worker thread"); + return false; + } + + return true; +} + +void Network::disconnect() +{ + mState = IDLE; + + if (mWorkerThread) + { + SDL_WaitThread(mWorkerThread, NULL); + mWorkerThread = NULL; + } + + if (mSocket) + { + SDLNet_TCP_Close(mSocket); + mSocket = 0; + } +} + +void Network::registerHandler(MessageHandler *handler) +{ + for (const Uint16 *i = handler->handledMessages; *i; i++) + { + mMessageHandlers[*i] = handler; + } + + handler->setNetwork(this); +} + +void Network::unregisterHandler(MessageHandler *handler) +{ + for (const Uint16 *i = handler->handledMessages; *i; i++) + { + mMessageHandlers.erase(*i); + } + + handler->setNetwork(0); +} + +void Network::clearHandlers() +{ + MessageHandlerIterator i; + for (i = mMessageHandlers.begin(); i != mMessageHandlers.end(); i++) + { + i->second->setNetwork(0); + } + mMessageHandlers.clear(); +} + +void Network::dispatchMessages() +{ + while (messageReady()) + { + MessageIn msg = getNextMessage(); + + MessageHandlerIterator iter = mMessageHandlers.find(msg.getId()); + + if (iter != mMessageHandlers.end()) + iter->second->handleMessage(msg); + else + logger->log("Unhandled packet: %x", msg.getId()); + + skip(msg.getLength()); + } +} + +void Network::flush() +{ + if (!mOutSize || mState != CONNECTED) + return; + + int ret; + + + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize); + if (ret < (int)mOutSize) + { + setError("Error in SDLNet_TCP_Send(): " + + std::string(SDLNet_GetError())); + } + mOutSize = 0; + SDL_mutexV(mMutex); +} + +void Network::skip(int len) +{ + SDL_mutexP(mMutex); + mToSkip += len; + if (!mInSize) + { + SDL_mutexV(mMutex); + return; + } + + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + SDL_mutexV(mMutex); +} + +bool Network::messageReady() +{ + int len = -1; + + SDL_mutexP(mMutex); + if (mInSize >= 2) + { + len = packet_lengths[readWord(0)]; + + if (len == -1 && mInSize > 4) + len = readWord(2); + + } + + bool ret = (mInSize >= static_cast<unsigned int>(len)); + SDL_mutexV(mMutex); + + return ret; +} + +MessageIn Network::getNextMessage() +{ + while (!messageReady()) + { + if (mState == NET_ERROR) + break; + } + + SDL_mutexP(mMutex); + int msgId = readWord(0); + int len = packet_lengths[msgId]; + + if (len == -1) + len = readWord(2); + +#ifdef DEBUG + logger->log("Received packet 0x%x of length %d", msgId, len); +#endif + + MessageIn msg(mInBuffer, len); + SDL_mutexV(mMutex); + + return msg; +} + +bool Network::realConnect() +{ + IPaddress ipAddress; + + if (SDLNet_ResolveHost(&ipAddress, mAddress.c_str(), mPort) == -1) + { + std::string error = "Unable to resolve host \"" + mAddress + "\""; + setError(error); + logger->log("SDLNet_ResolveHost: %s", error.c_str()); + return false; + } + + mState = CONNECTING; + + mSocket = SDLNet_TCP_Open(&ipAddress); + if (!mSocket) + { + logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); + setError(SDLNet_GetError()); + return false; + } + + logger->log("Network::Started session with %s:%i", + ipToString(ipAddress.host), ipAddress.port); + + mState = CONNECTED; + + return true; +} + +void Network::receive() +{ + SDLNet_SocketSet set; + + if (!(set = SDLNet_AllocSocketSet(1))) + { + setError("Error in SDLNet_AllocSocketSet(): " + + std::string(SDLNet_GetError())); + return; + } + + if (SDLNet_TCP_AddSocket(set, mSocket) == -1) + { + setError("Error in SDLNet_AddSocket(): " + + std::string(SDLNet_GetError())); + } + + while (mState == CONNECTED) + { + // TODO Try to get this to block all the time while still being able + // to escape the loop + int numReady = SDLNet_CheckSockets(set, ((Uint32)500)); + int ret; + switch (numReady) + { + case -1: + logger->log("Error: SDLNet_CheckSockets"); + // FALLTHROUGH + case 0: + break; + + case 1: + // Receive data from the socket + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, BUFFER_SIZE - mInSize); + + if (!ret) + { + // We got disconnected + mState = IDLE; + logger->log("Disconnected."); + } + else if (ret < 0) + { + setError("Error in SDLNet_TCP_Recv(): " + + std::string(SDLNet_GetError())); + } + else { + mInSize += ret; + if (mToSkip) + { + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + } + } + SDL_mutexV(mMutex); + break; + + default: + // more than one socket is ready.. + // this should not happen since we only listen once socket. + std::stringstream errorStream; + errorStream << "Error in SDLNet_TCP_Recv(), " << numReady + << " sockets are ready: " << SDLNet_GetError(); + setError(errorStream.str()); + break; + } + } + + if (SDLNet_TCP_DelSocket(set, mSocket) == -1) + { + logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); + } + + SDLNet_FreeSocketSet(set); +} + +void Network::setError(const std::string& error) +{ + logger->log("Network error: %s", error.c_str()); + mError = error; + mState = NET_ERROR; +} + +Uint16 Network::readWord(int pos) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return SDL_Swap16((*(Uint16*)(mInBuffer+(pos)))); +#else + return (*(Uint16*)(mInBuffer+(pos))); +#endif +} diff --git a/src/net/ea/network.h b/src/net/ea/network.h new file mode 100644 index 00000000..02fe7538 --- /dev/null +++ b/src/net/ea/network.h @@ -0,0 +1,118 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NETWORK_ +#define NETWORK_ + +#include <map> +#include <SDL_net.h> +#include <SDL_thread.h> +#include <string> + +/** + * Protocol version, reported to the eAthena char and mapserver who can adjust + * the protocol accordingly. + */ +#define CLIENT_PROTOCOL_VERSION 1 + +class MessageHandler; +class MessageIn; + +class Network; + +class Network +{ + public: + friend int networkThread(void *data); + friend class MessageOut; + + Network(); + + ~Network(); + + bool connect(const std::string &address, short port); + + void disconnect(); + + void registerHandler(MessageHandler *handler); + + void unregisterHandler(MessageHandler *handler); + + void clearHandlers(); + + int getState() const { return mState; } + + const std::string& getError() const { return mError; } + + bool isConnected() const { return mState == CONNECTED; } + + int getInSize() const { return mInSize; } + + void skip(int len); + + bool messageReady(); + + MessageIn getNextMessage(); + + void dispatchMessages(); + + void flush(); + + // ERROR replaced by NET_ERROR because already defined in Windows + enum { + IDLE, + CONNECTED, + CONNECTING, + DATA, + NET_ERROR + }; + + protected: + void setError(const std::string& error); + + Uint16 readWord(int pos); + + bool realConnect(); + + void receive(); + + TCPsocket mSocket; + + std::string mAddress; + short mPort; + + char *mInBuffer, *mOutBuffer; + unsigned int mInSize, mOutSize; + + unsigned int mToSkip; + + int mState; + std::string mError; + + SDL_Thread *mWorkerThread; + SDL_mutex *mMutex; + + typedef std::map<Uint16, MessageHandler*> MessageHandlers; + typedef MessageHandlers::iterator MessageHandlerIterator; + MessageHandlers mMessageHandlers; +}; + +#endif diff --git a/src/net/ea/npchandler.cpp b/src/net/ea/npchandler.cpp new file mode 100644 index 00000000..068a3be6 --- /dev/null +++ b/src/net/ea/npchandler.cpp @@ -0,0 +1,111 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../messagein.h" +#include "npchandler.h" +#include "protocol.h" + +#include "../../beingmanager.h" +#include "../../localplayer.h" +#include "../../npc.h" + +#include "../../gui/npc_text.h" +#include "../../gui/npcintegerdialog.h" +#include "../../gui/npclistdialog.h" +#include "../../gui/npcstringdialog.h" + +extern NpcIntegerDialog *npcIntegerDialog; +extern NpcListDialog *npcListDialog; +extern NpcTextDialog *npcTextDialog; +extern NpcStringDialog *npcStringDialog; + +NPCHandler::NPCHandler() +{ + static const Uint16 _messages[] = { + SMSG_NPC_CHOICE, + SMSG_NPC_MESSAGE, + SMSG_NPC_NEXT, + SMSG_NPC_CLOSE, + SMSG_NPC_INT_INPUT, + SMSG_NPC_STR_INPUT, + 0 + }; + handledMessages = _messages; +} + +void NPCHandler::handleMessage(MessageIn &msg) +{ + int id; + + switch (msg.getId()) + { + 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); + break; + + 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: + id = msg.readInt32(); + current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id)); + npcTextDialog->showCloseButton(); + break; + + case SMSG_NPC_NEXT: + // Next button in NPC dialog, currently unused + id = msg.readInt32(); + current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id)); + npcTextDialog->showNextButton(); + break; + + case SMSG_NPC_INT_INPUT: + // Request for an integer + id = msg.readInt32(); + current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id)); + npcIntegerDialog->setRange(0, 2147483647); + npcIntegerDialog->setDefaultValue(0); + npcIntegerDialog->setVisible(true); + npcIntegerDialog->requestFocus(); + break; + + case SMSG_NPC_STR_INPUT: + // Request for a string + id = msg.readInt32(); + current_npc = dynamic_cast<NPC*>(beingManager->findBeing(id)); + npcStringDialog->setValue(""); + npcStringDialog->setVisible(true); + npcStringDialog->requestFocus(); + break; + } +} diff --git a/src/gui/vbox.h b/src/net/ea/npchandler.h index 2072ab24..49df20c3 100644 --- a/src/gui/vbox.h +++ b/src/net/ea/npchandler.h @@ -1,33 +1,35 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef VBOX_H -#define VBOX_H +#ifndef NET_NPCHANDLER_H +#define NET_NPCHANDLER_H -#include "box.h" +#include "../messagehandler.h" -class VBox : public Box +class NPCHandler : public MessageHandler { public: - void draw(gcn::Graphics *); + NPCHandler(); + + void handleMessage(MessageIn &msg); }; #endif diff --git a/src/net/ea/partyhandler.cpp b/src/net/ea/partyhandler.cpp new file mode 100644 index 00000000..d1d3b55e --- /dev/null +++ b/src/net/ea/partyhandler.cpp @@ -0,0 +1,122 @@ +/* + * The Mana World + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <guichan/actionlistener.hpp> + +#include "partyhandler.h" +#include "protocol.h" +#include "../messagein.h" + +#include "../../gui/chat.h" +#include "../../gui/confirm_dialog.h" + +#include "../../beingmanager.h" +#include "../../party.h" + +PartyHandler::PartyHandler(Party *party) : mParty(party) +{ + static const Uint16 _messages[] = { + SMSG_PARTY_CREATE, + SMSG_PARTY_INFO, + SMSG_PARTY_INVITE, + SMSG_PARTY_INVITED, + SMSG_PARTY_SETTINGS, + SMSG_PARTY_MEMBER_INFO, + SMSG_PARTY_LEAVE, + SMSG_PARTY_UPDATE_HP, + SMSG_PARTY_UPDATE_COORDS, + SMSG_PARTY_MESSAGE, + 0 + }; + handledMessages = _messages; +} + +void PartyHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case SMSG_PARTY_CREATE: + mParty->createResponse(msg.readInt8()); + break; + case SMSG_PARTY_INFO: + break; + case SMSG_PARTY_INVITE: + { + std::string nick = msg.readString(24); + int status = msg.readInt8(); + mParty->inviteResponse(nick, status); + break; + } + case SMSG_PARTY_INVITED: + { + int id = msg.readInt32(); + Being *being = beingManager->findBeing(id); + if (!being) + { + break; + } + std::string nick; + int gender = 0; + std::string partyName = ""; + if (being->getType() != Being::PLAYER) + { + nick = ""; + } + else + { + nick = being->getName(); + gender = being->getGender(); + partyName = msg.readString(24); + } + mParty->invitedAsk(nick, gender, partyName); + break; + } + case SMSG_PARTY_SETTINGS: + break; + case SMSG_PARTY_MEMBER_INFO: + break; + case SMSG_PARTY_LEAVE: + { + /*int id = */msg.readInt32(); + std::string nick = msg.readString(24); + /*int fail = */msg.readInt8(); + mParty->leftResponse(nick); + break; + } + case SMSG_PARTY_UPDATE_HP: + break; + case SMSG_PARTY_UPDATE_COORDS: + break; + case SMSG_PARTY_MESSAGE: + { // new block to enable local variables + int msgLength = msg.readInt16() - 8; + if (msgLength <= 0) + { + return; + } + int id = msg.readInt32(); + Being *being = beingManager->findBeing(id); + std::string chatMsg = msg.readString(msgLength); + mParty->receiveChat(being, chatMsg); + } + break; + } +} diff --git a/src/net/ea/partyhandler.h b/src/net/ea/partyhandler.h new file mode 100644 index 00000000..5c10eb21 --- /dev/null +++ b/src/net/ea/partyhandler.h @@ -0,0 +1,39 @@ +/* + * The Mana World + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PARTYHANDLER_H +#define PARTYHANDLER_H + +#include "../messagehandler.h" + +class Party; + +class PartyHandler : public MessageHandler +{ + public: + PartyHandler(Party *party); + + void handleMessage(MessageIn &msg); + private: + Party *mParty; +}; + +#endif diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp new file mode 100644 index 00000000..9f0acbb3 --- /dev/null +++ b/src/net/ea/playerhandler.cpp @@ -0,0 +1,417 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../messagein.h" +#include "playerhandler.h" +#include "protocol.h" + +#include "../../engine.h" +#include "../../localplayer.h" +#include "../../log.h" +#include "../../npc.h" +#include "../../units.h" + +#include "../../gui/buy.h" +#include "../../gui/chat.h" +#include "../../gui/gui.h" +#include "../../gui/npclistdialog.h" +#include "../../gui/npc_text.h" +#include "../../gui/ok_dialog.h" +#include "../../gui/sell.h" +#include "../../gui/skill.h" +#include "../../gui/viewport.h" + +#include "../../utils/stringutils.h" +#include "../../utils/gettext.h" + +// TODO Move somewhere else +OkDialog *weightNotice = NULL; +OkDialog *deathNotice = NULL; + +extern NpcListDialog *npcListDialog; +extern NpcTextDialog *npcTextDialog; +extern BuyDialog *buyDialog; +extern SellDialog *sellDialog; +extern Window *buySellDialog; + +// Max. distance we are willing to scroll after a teleport; +// everything beyond will reset the port hard. +static const int MAP_TELEPORT_SCROLL_DISTANCE = 8; + +/** + * Listener used for handling the overweigth message. + */ +// TODO Move somewhere else +namespace { + struct WeightListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + weightNotice = NULL; + } + } weightListener; +} + +/** + * Listener used for handling death message. + */ +// TODO Move somewhere else +namespace { + struct DeathListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + player_node->revive(); + deathNotice = NULL; + npcListDialog->setVisible(false); + npcTextDialog->setVisible(false); + buyDialog->setVisible(false); + sellDialog->setVisible(false); + buySellDialog->setVisible(false); + if (current_npc) current_npc->handleDeath(); + } + } deathListener; +} + +PlayerHandler::PlayerHandler() +{ + static const Uint16 _messages[] = { + SMSG_WALK_RESPONSE, + SMSG_PLAYER_WARP, + SMSG_PLAYER_STAT_UPDATE_1, + SMSG_PLAYER_STAT_UPDATE_2, + SMSG_PLAYER_STAT_UPDATE_3, + SMSG_PLAYER_STAT_UPDATE_4, + SMSG_PLAYER_STAT_UPDATE_5, + SMSG_PLAYER_STAT_UPDATE_6, + SMSG_PLAYER_ARROW_MESSAGE, + 0 + }; + handledMessages = _messages; +} + +void PlayerHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case SMSG_WALK_RESPONSE: + /* + * This client assumes that all walk messages succeed, + * and that the server will send a correction notice + * otherwise. + */ + break; + + case SMSG_PLAYER_WARP: + { + std::string mapPath = msg.readString(16); + bool nearby; + Uint16 x = msg.readInt16(); + Uint16 y = msg.readInt16(); + + logger->log("Warping to %s (%d, %d)", mapPath.c_str(), x, y); + + /* + * We must clear the local player's target *before* the call + * to changeMap, as it deletes all beings. + */ + player_node->stopAttack(); + + nearby = (engine->getCurrentMapName() == mapPath); + + // Switch the actual map, deleting the previous one if necessary + engine->changeMap(mapPath); + + if (current_npc) current_npc->handleDeath(); + + float scrollOffsetX = 0.0f; + float scrollOffsetY = 0.0f; + + /* Scroll if neccessary */ + if (!nearby + || (abs(x - player_node->mX) > 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; + } + + player_node->setAction(Being::STAND); + player_node->mFrame = 0; + player_node->mX = x; + player_node->mY = y; + + logger->log("Adjust scrolling by %d:%d", + (int)scrollOffsetX, + (int)scrollOffsetY); + + viewport->scrollBy(scrollOffsetX, scrollOffsetY); + } + break; + + case SMSG_PLAYER_STAT_UPDATE_1: + { + Sint16 type = msg.readInt16(); + Uint32 value = msg.readInt32(); + + switch (type) + { + //case 0x0000: + // player_node->setWalkSpeed(msg.readInt32()); + // break; + case 0x0005: player_node->setHp(value); break; + case 0x0006: player_node->setMaxHp(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->setLevel(value); break; + case 0x000c: + player_node->mSkillPoint = value; + skillDialog->update(); + break; + case 0x0018: + if ((int) value >= player_node->getMaxWeight() / 2 && + player_node->getTotalWeight() < + player_node->getMaxWeight() / 2) + { + weightNotice = new OkDialog(_("Message"), + _("You are carrying more than " + "half your weight. You are " + "unable to regain health.")); + weightNotice->addActionListener( + &weightListener); + } + player_node->setTotalWeight(value); + break; + case 0x0019: player_node->setMaxWeight(value); break; + case 0x0029: player_node->ATK = value; break; + case 0x002b: player_node->MATK = value; break; + case 0x002d: player_node->DEF = value; break; + case 0x002e: player_node->DEF_BONUS = value; break; + case 0x002f: player_node->MDEF = value; break; + 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->getHp() == 0 && !deathNotice) + { + static char const *const deadMsg[] = + { + _("You are dead."), + _("We regret to inform you that your character was " + "killed in battle."), + _("You are not that alive anymore."), + _("The cold hands of the grim reaper are grabbing for " + "your soul."), + _("Game Over!"), + _("Insert coin to continue"), + _("No, kids. Your character did not really die. It... " + "err... went to a better place."), + _("Your plan of breaking your enemies weapon by " + "bashing it with your throat failed."), + _("I guess this did not run too well."), + // NetHack reference: + _("Do you want your possessions identified?"), + // Secret of Mana reference: + _("Sadly, no trace of you was ever found..."), + // Final Fantasy VI reference: + _("Annihilated."), + // Earthbound reference: + _("Looks like you got your head handed to you."), + // Leisure Suit Larry 1 reference: + _("You screwed up again, dump your body down the tubes " + "and get you another one."), + // Monty Python references (Dead Parrot sketch mostly): + _("You're not dead yet. You're just resting."), + _("You are no more."), + _("You have ceased to be."), + _("You've expired and gone to meet your maker."), + _("You're a stiff."), + _("Bereft of life, you rest in peace."), + _("If you weren't so animated, you'd be pushing up the " + "daisies."), + _("Your metabolic processes are now history."), + _("You're off the twig."), + _("You've kicked the bucket."), + _("You've shuffled off your mortal coil, run down the " + "curtain and joined the bleedin' choir invisibile."), + _("You are an ex-player."), + _("You're pining for the fjords.") + }; + std::string message(deadMsg[rand()%27]); + + deathNotice = new OkDialog(_("Message"), message); + deathNotice->addActionListener(&deathListener); + player_node->setAction(Being::DEAD); + } + } + break; + + case SMSG_PLAYER_STAT_UPDATE_2: + switch (msg.readInt16()) { + case 0x0001: + player_node->setXp(msg.readInt32()); + break; + case 0x0002: + player_node->mJobXp = msg.readInt32(); + break; + case 0x0014: { + int curGp = player_node->getMoney(); + player_node->setMoney(msg.readInt32()); + if (player_node->getMoney() > curGp) + chatWindow->chatLog(_("You picked up ") + + Units::formatCurrency(player_node->getMoney() + - curGp), BY_SERVER); + } + break; + case 0x0016: + player_node->mXpForNextLevel = msg.readInt32(); + break; + case 0x0017: + player_node->mJobXpForNextLevel = msg.readInt32(); + break; + } + break; + + case SMSG_PLAYER_STAT_UPDATE_3: + { + Sint32 type = msg.readInt32(); + Sint32 base = msg.readInt32(); + Sint32 bonus = msg.readInt32(); + Sint32 total = base + bonus; + + switch (type) { + case 0x000d: player_node->mAttr[LocalPlayer::STR] = total; + break; + case 0x000e: player_node->mAttr[LocalPlayer::AGI] = total; + break; + case 0x000f: player_node->mAttr[LocalPlayer::VIT] = total; + break; + case 0x0010: player_node->mAttr[LocalPlayer::INT] = total; + break; + case 0x0011: player_node->mAttr[LocalPlayer::DEX] = total; + break; + case 0x0012: player_node->mAttr[LocalPlayer::LUK] = total; + break; + } + } + break; + + case SMSG_PLAYER_STAT_UPDATE_4: + { + Sint16 type = msg.readInt16(); + Sint8 fail = msg.readInt8(); + Sint8 value = msg.readInt8(); + + if (fail != 1) + break; + + switch (type) { + case 0x000d: player_node->mAttr[LocalPlayer::STR] = value; + break; + case 0x000e: player_node->mAttr[LocalPlayer::AGI] = value; + break; + case 0x000f: player_node->mAttr[LocalPlayer::VIT] = value; + break; + case 0x0010: player_node->mAttr[LocalPlayer::INT] = value; + break; + case 0x0011: player_node->mAttr[LocalPlayer::DEX] = value; + break; + case 0x0012: player_node->mAttr[LocalPlayer::LUK] = value; + break; + } + } + break; + + // Updates stats and status points + case SMSG_PLAYER_STAT_UPDATE_5: + player_node->mStatsPointsToAttribute = msg.readInt16(); + player_node->mAttr[LocalPlayer::STR] = msg.readInt8(); + player_node->mAttrUp[LocalPlayer::STR] = msg.readInt8(); + player_node->mAttr[LocalPlayer::AGI] = msg.readInt8(); + player_node->mAttrUp[LocalPlayer::AGI] = msg.readInt8(); + player_node->mAttr[LocalPlayer::VIT] = msg.readInt8(); + player_node->mAttrUp[LocalPlayer::VIT] = msg.readInt8(); + player_node->mAttr[LocalPlayer::INT] = msg.readInt8(); + player_node->mAttrUp[LocalPlayer::INT] = msg.readInt8(); + player_node->mAttr[LocalPlayer::DEX] = msg.readInt8(); + player_node->mAttrUp[LocalPlayer::DEX] = msg.readInt8(); + player_node->mAttr[LocalPlayer::LUK] = msg.readInt8(); + player_node->mAttrUp[LocalPlayer::LUK] = msg.readInt8(); + player_node->ATK = msg.readInt16(); // ATK + player_node->ATK_BONUS = msg.readInt16(); // ATK bonus + player_node->MATK = msg.readInt16(); // MATK max + player_node->MATK_BONUS = msg.readInt16(); // MATK min + player_node->DEF = msg.readInt16(); // DEF + player_node->DEF_BONUS = msg.readInt16(); // DEF bonus + player_node->MDEF = msg.readInt16(); // MDEF + player_node->MDEF_BONUS = msg.readInt16(); // MDEF bonus + player_node->HIT = msg.readInt16(); // HIT + player_node->FLEE = msg.readInt16(); // FLEE + player_node->FLEE_BONUS = msg.readInt16(); // FLEE bonus + msg.readInt16(); // critical + msg.readInt16(); // unknown + break; + + case SMSG_PLAYER_STAT_UPDATE_6: + switch (msg.readInt16()) { + case 0x0020: + player_node->mAttrUp[LocalPlayer::STR] = msg.readInt8(); + break; + case 0x0021: + player_node->mAttrUp[LocalPlayer::AGI] = msg.readInt8(); + break; + case 0x0022: + player_node->mAttrUp[LocalPlayer::VIT] = msg.readInt8(); + break; + case 0x0023: + player_node->mAttrUp[LocalPlayer::INT] = msg.readInt8(); + break; + case 0x0024: + player_node->mAttrUp[LocalPlayer::DEX] = msg.readInt8(); + break; + case 0x0025: + player_node->mAttrUp[LocalPlayer::LUK] = msg.readInt8(); + break; + } + break; + + case SMSG_PLAYER_ARROW_MESSAGE: + { + Sint16 type = msg.readInt16(); + + switch (type) { + case 0: + chatWindow->chatLog(_("Equip arrows first"), + BY_SERVER); + break; + default: + logger->log("0x013b: Unhandled message %i", type); + break; + } + } + break; + } +} diff --git a/src/gui/box.cpp b/src/net/ea/playerhandler.h index 59d8c135..f3352289 100644 --- a/src/gui/box.cpp +++ b/src/net/ea/playerhandler.h @@ -1,42 +1,35 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "box.h" +#ifndef NET_PLAYERHANDLER_H +#define NET_PLAYERHANDLER_H -Box::Box(): - padding(0) -{ - setOpaque(false); -} +#include "../messagehandler.h" -Box::~Box() +class PlayerHandler : public MessageHandler { -} + public: + PlayerHandler(); -unsigned int Box::getPadding() -{ - return padding; -} + void handleMessage(MessageIn &msg); +}; -void Box::setPadding(unsigned int p) -{ - padding = p; -} +#endif diff --git a/src/net/ea/protocol.cpp b/src/net/ea/protocol.cpp new file mode 100644 index 00000000..69d69901 --- /dev/null +++ b/src/net/ea/protocol.cpp @@ -0,0 +1,77 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "protocol.h" + +#define LOBYTE(w) ((unsigned char)(w)) +#define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8)) + +void set_coordinates(char *data, + unsigned short x, + unsigned short y, + unsigned char direction) +{ + short temp; + temp = x; + temp <<= 6; + data[0] = 0; + data[1] = 1; + data[2] = 2; + data[0] = HIBYTE(temp); + data[1] = (unsigned char)(temp); + temp = y; + temp <<= 4; + data[1] |= HIBYTE(temp); + data[2] = LOBYTE(temp); + + // Translate direction to eAthena format + switch (direction) + { + case 1: + direction = 0; + break; + case 3: + direction = 1; + break; + case 2: + direction = 2; + break; + case 6: + direction = 3; + break; + case 4: + direction = 4; + break; + case 12: + direction = 5; + break; + case 8: + direction = 6; + break; + case 9: + direction = 7; + break; + default: + // OOPSIE! Impossible or unknown + direction = (unsigned char)-1; + } + data[2] |= direction; +} diff --git a/src/net/ea/protocol.h b/src/net/ea/protocol.h new file mode 100644 index 00000000..55c0d8b6 --- /dev/null +++ b/src/net/ea/protocol.h @@ -0,0 +1,162 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PROTOCOL_H +#define PROTOCOL_H + +/********************************* + * Packets from server to client * + *********************************/ +#define SMSG_LOGIN_SUCCESS 0x0073 /**< Contains starting location */ +#define SMSG_SERVER_PING 0x007f /**< Contains server tick */ +#define SMSG_CONNECTION_PROBLEM 0x0081 +#define SMSG_UPDATE_HOST 0x0063 /**< Custom update host packet */ +#define SMSG_PLAYER_UPDATE_1 0x01d8 +#define SMSG_PLAYER_UPDATE_2 0x01d9 +#define SMSG_PLAYER_MOVE 0x01da /**< A nearby player moves */ +#define SMSG_PLAYER_STOP 0x0088 /**< Stop walking, set position */ +#define SMSG_PLAYER_MOVE_TO_ATTACK 0x0139 /**< Move to within attack range */ +#define SMSG_PLAYER_STAT_UPDATE_1 0x00b0 +#define SMSG_PLAYER_STAT_UPDATE_2 0x00b1 +#define SMSG_PLAYER_STAT_UPDATE_3 0x0141 +#define SMSG_PLAYER_STAT_UPDATE_4 0x00bc +#define SMSG_PLAYER_STAT_UPDATE_5 0x00bd +#define SMSG_PLAYER_STAT_UPDATE_6 0x00be +#define SMSG_WHO_ANSWER 0x00c2 +#define SMSG_PLAYER_WARP 0x0091 /**< Warp player to map/location */ +#define SMSG_PLAYER_INVENTORY 0x01ee +#define SMSG_PLAYER_INVENTORY_ADD 0x00a0 +#define SMSG_PLAYER_INVENTORY_REMOVE 0x00af +#define SMSG_PLAYER_INVENTORY_USE 0x01c8 +#define SMSG_PLAYER_EQUIPMENT 0x00a4 +#define SMSG_PLAYER_EQUIP 0x00aa +#define SMSG_PLAYER_UNEQUIP 0x00ac +#define SMSG_PLAYER_ATTACK_RANGE 0x013a +#define SMSG_PLAYER_ARROW_EQUIP 0x013c +#define SMSG_PLAYER_ARROW_MESSAGE 0x013b +#define SMSG_PLAYER_SKILLS 0x010f +#define SMSG_SKILL_FAILED 0x0110 +#define SMSG_ITEM_USE_RESPONSE 0x00a8 +#define SMSG_ITEM_VISIBLE 0x009d /**< An item is on the floor */ +#define SMSG_ITEM_DROPPED 0x009e /**< An item is dropped */ +#define SMSG_ITEM_REMOVE 0x00a1 /**< An item disappers */ +#define SMSG_BEING_VISIBLE 0x0078 +#define SMSG_BEING_MOVE 0x007b /**< A nearby monster moves */ +#define SMSG_BEING_SPAWN 0x007c /**< A being spawns nearby */ +#define SMSG_BEING_MOVE2 0x0086 /**< New eAthena being moves */ +#define SMSG_BEING_REMOVE 0x0080 +#define SMSG_BEING_CHANGE_LOOKS 0x00c3 +#define SMSG_BEING_CHANGE_LOOKS2 0x01d7 /**< Same as 0x00c3, but 16 bit ID */ +#define SMSG_BEING_SELFEFFECT 0x019b +#define SMSG_BEING_EMOTION 0x00c0 +#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 +#define SMSG_NPC_CHOICE 0x00b7 /**< Display a choice */ +#define SMSG_NPC_BUY_SELL_CHOICE 0x00c4 +#define SMSG_NPC_BUY 0x00c6 +#define SMSG_NPC_SELL 0x00c7 +#define SMSG_NPC_BUY_RESPONSE 0x00ca +#define SMSG_NPC_SELL_RESPONSE 0x00cb +#define SMSG_NPC_INT_INPUT 0x0142 /**< Integer input */ +#define SMSG_NPC_STR_INPUT 0x01d4 /**< String input */ +#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 +#define SMSG_TRADE_ITEM_ADD_RESPONSE 0x01b1 /**< Not standard eAthena! */ +#define SMSG_TRADE_OK 0x00ec +#define SMSG_TRADE_CANCEL 0x00ee +#define SMSG_TRADE_COMPLETE 0x00f0 + +#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 +#define CMSG_MAP_LOADED 0x007d +#define CMSG_NPC_BUY_REQUEST 0x00c8 +#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 +#define CMSG_NPC_INT_RESPONSE 0x0143 +#define CMSG_NPC_STR_RESPONSE 0x01d5 +#define CMSG_SKILL_LEVELUP_REQUEST 0x0112 +#define CMSG_STAT_UPDATE_REQUEST 0x00bb +#define CMSG_TRADE_ITEM_ADD_REQUEST 0x00e8 +#define CMSG_TRADE_CANCEL_REQUEST 0x00ed +#define CMSG_TRADE_ADD_COMPLETE 0x00eb +#define CMSG_TRADE_OK 0x00ef +#define CMSG_NPC_TALK 0x0090 +#define CMSG_TRADE_REQUEST 0x00e4 +#define CMSG_PLAYER_INVENTORY_USE 0x00a7 +#define CMSG_PLAYER_INVENTORY_DROP 0x00a2 +#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); + +#endif diff --git a/src/net/ea/skillhandler.cpp b/src/net/ea/skillhandler.cpp new file mode 100644 index 00000000..6e766008 --- /dev/null +++ b/src/net/ea/skillhandler.cpp @@ -0,0 +1,93 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../messagein.h" +#include "protocol.h" +#include "skillhandler.h" + +#include "../../log.h" + +#include "../../gui/chat.h" +#include "../../gui/skill.h" + +SkillHandler::SkillHandler() +{ + static const Uint16 _messages[] = { + SMSG_PLAYER_SKILLS, + SMSG_SKILL_FAILED, + 0 + }; + handledMessages = _messages; +} + +void SkillHandler::handleMessage(MessageIn &msg) +{ + int skillCount; + + switch (msg.getId()) + { + case SMSG_PLAYER_SKILLS: + msg.readInt16(); // length + skillCount = (msg.getLength() - 4) / 37; + skillDialog->cleanList(); + + for (int k = 0; k < skillCount; k++) + { + Sint16 skillId = msg.readInt16(); + msg.readInt16(); // target type + msg.readInt16(); // unknown + Sint16 level = msg.readInt16(); + Sint16 sp = msg.readInt16(); + msg.readInt16(); // range + std::string skillName = msg.readString(24); + Sint8 up = msg.readInt8(); + + if (level != 0 || up != 0) + { + if (skillDialog->hasSkill(skillId)) { + skillDialog->setSkill(skillId, level, sp); + } + else { + skillDialog->addSkill(skillId, level, sp); + } + } + } + skillDialog->update(); + break; + + case SMSG_SKILL_FAILED: + // Action failed (ex. sit because you have not reached the + // right level) + CHATSKILL action; + action.skill = msg.readInt16(); + action.bskill = msg.readInt16(); + action.unused = msg.readInt16(); // unknown + action.success = msg.readInt8(); + action.reason = msg.readInt8(); + if (action.success != SKILL_FAILED && + action.bskill == BSKILL_EMOTE) + { + logger->log("Action: %d/%d", action.bskill, action.success); + } + chatWindow->chatLog(action); + break; + } +} diff --git a/src/utils/tostring.h b/src/net/ea/skillhandler.h index d2dd941a..57d68f47 100644 --- a/src/utils/tostring.h +++ b/src/net/ea/skillhandler.h @@ -1,35 +1,35 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_UTILS_TOSTRING_H -#define _TMW_UTILS_TOSTRING_H +#ifndef NET_SKILLHANDLER_H +#define NET_SKILLHANDLER_H -#include <sstream> +#include "../messagehandler.h" -template<typename T> -std::string toString(const T &arg) +class SkillHandler : public MessageHandler { - std::stringstream ss; - ss << arg; - return ss.str(); -} + public: + SkillHandler(); + + void handleMessage(MessageIn &msg); +}; #endif diff --git a/src/net/ea/tradehandler.cpp b/src/net/ea/tradehandler.cpp new file mode 100644 index 00000000..6c953a11 --- /dev/null +++ b/src/net/ea/tradehandler.cpp @@ -0,0 +1,220 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "../messagein.h" +#include "protocol.h" +#include "tradehandler.h" + +#include "../../inventory.h" +#include "../../item.h" +#include "../../localplayer.h" +#include "../../player_relations.h" + +#include "../../gui/chat.h" +#include "../../gui/confirm_dialog.h" +#include "../../gui/trade.h" + +#include "../../utils/gettext.h" + +std::string tradePartnerName; + +/** + * Listener for request trade dialogs + */ +namespace { + struct RequestTradeListener : public gcn::ActionListener + { + void action(const gcn::ActionEvent &event) + { + player_node->tradeReply(event.getId() == "yes"); + }; + } listener; +} + +TradeHandler::TradeHandler() +{ + static const Uint16 _messages[] = { + SMSG_TRADE_REQUEST, + SMSG_TRADE_RESPONSE, + SMSG_TRADE_ITEM_ADD, + SMSG_TRADE_ITEM_ADD_RESPONSE, + SMSG_TRADE_OK, + SMSG_TRADE_CANCEL, + SMSG_TRADE_COMPLETE, + 0 + }; + handledMessages = _messages; +} + + +void TradeHandler::handleMessage(MessageIn &msg) +{ + switch (msg.getId()) + { + case SMSG_TRADE_REQUEST: + // If a trade window or request window is already open, send a + // trade cancel to any other trade request. + // + // Note that it would be nice if the server would prevent this + // situation, and that the requesting player would get a + // special message about the player being occupied. + tradePartnerName = msg.readString(24); + + if (player_relations.hasPermission(tradePartnerName, PlayerRelation::TRADE)) + { + if (!player_node->tradeRequestOk()) + { + player_node->tradeReply(false); + break; + } + + player_node->setTrading(true); + ConfirmDialog *dlg; + dlg = new ConfirmDialog(_("Request for trade"), + tradePartnerName + + _(" wants to trade with you, do you accept?")); + dlg->addActionListener(&listener); + } + else + { + player_node->tradeReply(false); + break; + } + break; + + case SMSG_TRADE_RESPONSE: + switch (msg.readInt8()) + { + case 0: // Too far away + chatWindow->chatLog(_("Trading isn't possible. Trade partner is too far away."), + BY_SERVER); + break; + case 1: // Character doesn't exist + chatWindow->chatLog(_("Trading isn't possible. Character doesn't exist."), + BY_SERVER); + break; + case 2: // Invite request check failed... + chatWindow->chatLog(_("Trade cancelled due to an unknown reason."), + BY_SERVER); + break; + case 3: // Trade accepted + tradeWindow->reset(); + tradeWindow->setCaption( + _("Trade: You and ") + tradePartnerName); + tradeWindow->setVisible(true); + break; + case 4: // Trade cancelled + if (player_relations.hasPermission(tradePartnerName, + PlayerRelation::SPEECH_LOG)) + chatWindow->chatLog(_("Trade with ") + tradePartnerName + + _(" cancelled"), BY_SERVER); + // otherwise ignore silently + + tradeWindow->setVisible(false); + player_node->setTrading(false); + break; + default: // Shouldn't happen as well, but to be sure + chatWindow->chatLog(_("Unhandled trade cancel packet"), + BY_SERVER); + break; + } + break; + + case SMSG_TRADE_ITEM_ADD: + { + Sint32 amount = msg.readInt32(); + Sint16 type = msg.readInt16(); + msg.readInt8(); // identified flag + msg.readInt8(); // attribute + msg.readInt8(); // refine + msg.skip(8); // card (4 shorts) + + // TODO: handle also identified, etc + if (type == 0) { + tradeWindow->setMoney(amount); + } else { + tradeWindow->addItem(type, false, amount, false); + } + } + break; + + case SMSG_TRADE_ITEM_ADD_RESPONSE: + // Trade: New Item add response (was 0x00ea, now 01b1) + { + const int index = msg.readInt16(); + Item *item = player_node->getInventory()->getItem(index); + if (!item) + { + tradeWindow->receivedOk(true); + return; + } + Sint16 quantity = msg.readInt16(); + + switch (msg.readInt8()) + { + case 0: + // Successfully added item + if (item->isEquipment() && item->isEquipped()) + { + player_node->unequipItem(item); + } + tradeWindow->addItem(item->getId(), true, quantity, + item->isEquipment()); + item->increaseQuantity(-quantity); + break; + case 1: + // Add item failed - player overweighted + chatWindow->chatLog(_("Failed adding item. Trade partner is over weighted."), + BY_SERVER); + break; + case 2: + // Add item failed - player has no free slot + chatWindow->chatLog(_("Failed adding item. Trade partner has no free slot."), + BY_SERVER); + break; + default: + chatWindow->chatLog(_("Failed adding item for unknown reason."), + BY_SERVER); + break; + } + } + break; + + case SMSG_TRADE_OK: + // 0 means ok from myself, 1 means ok from other; + tradeWindow->receivedOk(msg.readInt8() == 0); + break; + + case SMSG_TRADE_CANCEL: + chatWindow->chatLog(_("Trade canceled."), BY_SERVER); + tradeWindow->setVisible(false); + tradeWindow->reset(); + player_node->setTrading(false); + break; + + case SMSG_TRADE_COMPLETE: + chatWindow->chatLog(_("Trade completed."), BY_SERVER); + tradeWindow->setVisible(false); + tradeWindow->reset(); + player_node->setTrading(false); + break; + } +} diff --git a/src/net/ea/tradehandler.h b/src/net/ea/tradehandler.h new file mode 100644 index 00000000..04335069 --- /dev/null +++ b/src/net/ea/tradehandler.h @@ -0,0 +1,37 @@ +/* + * The Mana World + * Copyright (C) 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NET_TRADEHANDLER_H +#define NET_TRADEHANDLER_H + +#include "../messagehandler.h" + +class Network; + +class TradeHandler : public MessageHandler +{ + public: + TradeHandler(); + + void handleMessage(MessageIn &msg); +}; + +#endif diff --git a/src/net/effecthandler.cpp b/src/net/effecthandler.cpp index f7ff2bf2..8411b9e7 100644 --- a/src/net/effecthandler.cpp +++ b/src/net/effecthandler.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/net/inventoryhandler.h b/src/net/inventoryhandler.h index 1326ea71..9b457abe 100644 --- a/src/net/inventoryhandler.h +++ b/src/net/inventoryhandler.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NET_INVENTORYHANDLER_H -#define _TMW_NET_INVENTORYHANDLER_H +#ifndef NET_INVENTORYHANDLER_H +#define NET_INVENTORYHANDLER_H #include "messagehandler.h" diff --git a/src/net/itemhandler.cpp b/src/net/itemhandler.cpp index af06084f..189c6eb9 100644 --- a/src/net/itemhandler.cpp +++ b/src/net/itemhandler.cpp @@ -1,26 +1,25 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "itemhandler.h" - #include "messagein.h" #include "protocol.h" diff --git a/src/net/itemhandler.h b/src/net/itemhandler.h index e3005a6f..12057bb1 100644 --- a/src/net/itemhandler.h +++ b/src/net/itemhandler.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NET_ITEMHANDLER_H -#define _TMW_NET_ITEMHANDLER_H +#ifndef NET_ITEMHANDLER_H +#define NET_ITEMHANDLER_H #include "messagehandler.h" diff --git a/src/net/messagehandler.cpp b/src/net/messagehandler.cpp index 973c5555..a765d0e8 100644 --- a/src/net/messagehandler.cpp +++ b/src/net/messagehandler.cpp @@ -1,31 +1,54 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "messagehandler.h" - #include <cassert> +#include "messagehandler.h" +#ifdef TMWSERV_SUPPORT #include "network.h" +#else +#include "ea/network.h" +#endif + +MessageHandler::MessageHandler() +#ifdef EATHENA_SUPPORT + : mNetwork(0) +#endif +{ +} MessageHandler::~MessageHandler() { +#ifdef TMWSERV_SUPPORT Net::unregisterHandler(this); +#else + if (mNetwork) + mNetwork->unregisterHandler(this); +#endif +} + +#ifdef EATHENA_SUPPORT +void MessageHandler::setNetwork(Network *network) +{ + assert(!(network && mNetwork)); + mNetwork = network; } +#endif diff --git a/src/net/messagehandler.h b/src/net/messagehandler.h index 74226aa5..261a8351 100644 --- a/src/net/messagehandler.h +++ b/src/net/messagehandler.h @@ -1,30 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NET_MESSAGEHANDLER_H -#define _TMW_NET_MESSAGEHANDLER_H +#ifndef NET_MESSAGEHANDLER_H +#define NET_MESSAGEHANDLER_H #include <SDL_types.h> class MessageIn; +#ifdef EATHENA_SUPPORT +class Network; +#endif /** * \ingroup Network @@ -34,9 +37,17 @@ class MessageHandler public: const Uint16 *handledMessages; + MessageHandler(); virtual ~MessageHandler(); virtual void handleMessage(MessageIn &msg) = 0; + +#ifdef EATHENA_SUPPORT + void setNetwork(Network *network); + + protected: + Network *mNetwork; +#endif }; #endif diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp index 57c268e7..813b440f 100644 --- a/src/net/messagein.cpp +++ b/src/net/messagein.cpp @@ -1,29 +1,38 @@ /* - * The Mana World Server - * Copyright 2004 The Mana World Development Team + * The Mana World + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "messagein.h" -#include <string> - +#ifdef TMWSERV_SUPPORT #include <enet/enet.h> +#else +#include <SDL.h> +#include <SDL_endian.h> +#endif + +#include <cassert> + +#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), @@ -50,9 +59,17 @@ int MessageIn::readInt16() int value = -1; if (mPos + 2 <= mLength) { +#ifdef TMWSERV_SUPPORT uint16_t t; memcpy(&t, mData + mPos, 2); value = (unsigned short) ENET_NET_TO_HOST_16(t); +#else +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + value = SDL_Swap16(*(Sint16*)(mData + mPos)); +#else + value = (*(Sint16*)(mData + mPos)); +#endif +#endif // TMWSERV_SUPPORT } mPos += 2; return value; @@ -63,9 +80,17 @@ int MessageIn::readInt32() int value = -1; if (mPos + 4 <= mLength) { +#ifdef TMWSERV_SUPPORT uint32_t t; memcpy(&t, mData + mPos, 4); value = ENET_NET_TO_HOST_32(t); +#else +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + value = SDL_Swap32(*(Sint32*)(mData + mPos)); +#else + value = (*(Sint32*)(mData + mPos)); +#endif +#endif // TMWSERV_SUPPORT } mPos += 4; return value; @@ -82,6 +107,83 @@ void MessageIn::readCoordinates(Uint16 &x, Uint16 &y) mPos += 3; } +void MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction) +{ + assert(mPos + 3 <= mLength); + + const char *data = mData + mPos; + Sint16 temp; + + temp = MAKEWORD(data[1] & 0x00c0, data[0] & 0x00ff); + x = temp >> 6; + temp = MAKEWORD(data[2] & 0x00f0, data[1] & 0x003f); + y = temp >> 4; + + direction = data[2] & 0x000f; + + // Translate from eAthena format + switch (direction) + { + case 0: + direction = 1; + break; + case 1: + direction = 3; + break; + case 2: + direction = 2; + break; + case 3: + direction = 6; + break; + case 4: + direction = 4; + break; + case 5: + direction = 12; + break; + case 6: + direction = 8; + break; + case 7: + direction = 9; + break; + default: + // OOPSIE! Impossible or unknown + direction = 0; + } + + mPos += 3; +} + +void MessageIn::readCoordinatePair(Uint16 &srcX, Uint16 &srcY, + Uint16 &dstX, Uint16 &dstY) +{ + assert(mPos + 5 <= mLength); + + const char *data = mData + mPos; + Sint16 temp; + + temp = MAKEWORD(data[3], data[2] & 0x000f); + dstX = temp >> 2; + + dstY = MAKEWORD(data[4], data[3] & 0x0003); + + temp = MAKEWORD(data[1], data[0]); + srcX = temp >> 6; + + temp = MAKEWORD(data[2], data[1] & 0x003f); + srcY = temp >> 4; + + mPos += 5; +} + +void MessageIn::skip(unsigned int length) +{ + assert(mPos + length <= mLength); + mPos += length; +} + std::string MessageIn::readString(int length) { // Get string length @@ -89,16 +191,17 @@ std::string MessageIn::readString(int length) length = readInt16(); } - // Make sure the string isn't erroneus + // Make sure the string isn't erroneous if (length < 0 || mPos + length > mLength) { mPos = mLength + 1; return ""; } // Read the string - char const *stringBeg = mData + mPos, - *stringEnd = (char const *)memchr(stringBeg, '\0', length); - std::string readString(stringBeg, stringEnd ? stringEnd - stringBeg : length); + char const *stringBeg = mData + mPos; + char const *stringEnd = (char const *)memchr(stringBeg, '\0', length); + std::string readString(stringBeg, + stringEnd ? stringEnd - stringBeg : length); mPos += length; return readString; } diff --git a/src/net/messagein.h b/src/net/messagein.h index f2390baa..0d0e9981 100644 --- a/src/net/messagein.h +++ b/src/net/messagein.h @@ -1,30 +1,29 @@ /* - * The Mana World Server - * Copyright 2004 The Mana World Development Team + * The Mana World + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _TMWSERV_MESSAGEIN_H_ -#define _TMWSERV_MESSAGEIN_H_ - -#include <string> +#ifndef MESSAGEIN_ +#define MESSAGEIN_ #include <SDL_types.h> +#include <string> /** * Used for parsing an incoming message. @@ -39,40 +38,60 @@ class MessageIn */ MessageIn(const char *data, unsigned int length); - int getId() { return mId; } /**< Returns the message ID. */ + /** + * Returns the message ID. + */ + int getId() const { return mId; } + + /** + * Returns the message length. + */ + unsigned int getLength() const { return mLength; } + + /** + * Returns the length of unread data. + */ + unsigned int getUnreadLength() const { return mLength - mPos; } int readInt8(); /**< Reads a byte. */ int readInt16(); /**< Reads a short. */ int readInt32(); /**< Reads a long. */ /** - * Reads a 3-byte block containing tile-based coordinates. + * Reads a 3-byte block containing tile-based coordinates. Used by + * tmwserv. */ void readCoordinates(Uint16 &x, Uint16 &y); /** - * Reads a string. If a length is not given (-1), it is assumed - * that the length of the string is stored in a short at the - * start of the string. + * Reads a special 3 byte block used by eAthena, containing x and y + * coordinates and direction. */ - std::string readString(int length = -1); + void readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction); /** - * Returns the message length. + * Reads a special 5 byte block used by eAthena, containing a source + * and destination coordinate pair. */ - unsigned int - getLength() const { return mLength; } + void readCoordinatePair(Uint16 &srcX, Uint16 &srcY, + Uint16 &dstX, Uint16 &dstY); /** - * Returns the length of unread data. + * Skips a given number of bytes. */ - unsigned int - getUnreadLength() const { return mLength - mPos; } + void skip(unsigned int length); + + /** + * Reads a string. If a length is not given (-1), it is assumed + * that the length of the string is stored in a short at the + * start of the string. + */ + std::string readString(int length = -1); private: const char* mData; /**< The message data. */ unsigned int mLength; /**< The length of the data. */ - unsigned short mId; /**< The message ID. */ + unsigned short mId; /**< The message ID. */ /** * Actual position in the packet. From 0 to packet->length. diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp index b08332b6..f7ab6b41 100644 --- a/src/net/messageout.cpp +++ b/src/net/messageout.cpp @@ -1,80 +1,113 @@ /* - * The Mana World Server - * Copyright 2004 The Mana World Development Team + * The Mana World + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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 <string> +#include "messageout.h" +#ifdef TMWSERV_SUPPORT #include <enet/enet.h> +#else +#include "ea/network.h" +#include <SDL.h> +#include <SDL_endian.h> +#endif -#include "messageout.h" +#include <cstring> +#include <string> +#ifdef TMWSERV_SUPPORT MessageOut::MessageOut(short id): mData(0), +#else +MessageOut::MessageOut(Network *network): + mNetwork(network), +#endif mDataSize(0), mPos(0) { +#ifdef TMWSERV_SUPPORT writeInt16(id); +#else + mData = mNetwork->mOutBuffer + mNetwork->mOutSize; +#endif } +#ifdef TMWSERV_SUPPORT MessageOut::~MessageOut() { - if (mData) { - free(mData); - } + free(mData); } -void -MessageOut::expand(size_t bytes) +void MessageOut::expand(size_t bytes) { mData = (char*)realloc(mData, bytes); mDataSize = bytes; } +#endif -void -MessageOut::writeInt8(char value) +void MessageOut::writeInt8(Sint8 value) { +#ifdef TMWSERV_SUPPORT expand(mPos + 1); +#else + mNetwork->mOutSize += 1; +#endif mData[mPos] = value; mPos += 1; } -void MessageOut::writeInt16(short value) +void MessageOut::writeInt16(Sint16 value) { +#ifdef TMWSERV_SUPPORT expand(mPos + 2); uint16_t t = ENET_HOST_TO_NET_16(value); memcpy(mData + mPos, &t, 2); +#else +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + (*(Sint16 *)(mData + mPos)) = SDL_Swap16(value); +#else + (*(Sint16 *)(mData + mPos)) = value; +#endif + mNetwork->mOutSize += 2; +#endif // TMWSERV_SUPPORT mPos += 2; } -void -MessageOut::writeInt32(long value) +void MessageOut::writeInt32(Sint32 value) { +#ifdef TMWSERV_SUPPORT expand(mPos + 4); uint32_t t = ENET_HOST_TO_NET_32(value); memcpy(mData + mPos, &t, 4); +#else +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + (*(Sint32 *)(mData + mPos)) = SDL_Swap32(value); +#else + (*(Sint32 *)(mData + mPos)) = value; +#endif + mNetwork->mOutSize += 4; +#endif // TMWSERV_SUPPORT mPos += 4; } -void -MessageOut::writeString(const std::string &string, int length) +void MessageOut::writeString(const std::string &string, int length) { int stringLength = string.length(); if (length < 0) @@ -88,7 +121,11 @@ MessageOut::writeString(const std::string &string, int length) // Make sure the length of the string is no longer than specified stringLength = length; } +#ifdef TMWSERV_SUPPORT expand(mPos + length); +#else + mNetwork->mOutSize += length; +#endif // Write the actual string memcpy(mData + mPos, string.c_str(), stringLength); @@ -101,14 +138,12 @@ MessageOut::writeString(const std::string &string, int length) mPos += length; } -char* -MessageOut::getData() const +char *MessageOut::getData() const { return mData; } -unsigned int -MessageOut::getDataSize() const +unsigned int MessageOut::getDataSize() const { return mDataSize; } diff --git a/src/net/messageout.h b/src/net/messageout.h index 4eadda5f..bc701b92 100644 --- a/src/net/messageout.h +++ b/src/net/messageout.h @@ -1,32 +1,39 @@ /* - * The Mana World Server - * Copyright 2004 The Mana World Development Team + * The Mana World + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _TMWSERV_MESSAGEOUT_H_ -#define _TMWSERV_MESSAGEOUT_H_ +#ifndef MESSAGEOUT_ +#define MESSAGEOUT_ #include <iosfwd> +#include <SDL_types.h> + +#ifdef EATHENA_SUPPORT +class Network; +#endif /** - * Used for building an outgoing message. When finished, the message is sent - * using Net::Connection::send(). + * Used for building an outgoing message. + * + * With tmwserv, the message is sent using Net::Connection::send() when + * finished. * * \ingroup Network */ @@ -36,16 +43,20 @@ class MessageOut /** * Constructor. */ +#ifdef TMWSERV_SUPPORT MessageOut(short id); /** * Destructor. */ ~MessageOut(); +#else + MessageOut(Network *network); +#endif - void writeInt8(char value); /**< Writes a byte. */ - void writeInt16(short value); /**< Writes a short. */ - void writeInt32(long value); /**< Writes a long. */ + void writeInt8(Sint8 value); /**< Writes a byte. */ + void writeInt16(Sint16 value); /**< Writes a short. */ + void writeInt32(Sint32 value); /**< Writes a long. */ /** * Writes a string. If a fixed length is not given (-1), it is stored @@ -64,6 +75,7 @@ class MessageOut unsigned int getDataSize() const; private: +#ifdef TMWSERV_SUPPORT /** * Expand the packet data to be able to hold more data. * @@ -72,6 +84,9 @@ class MessageOut * added. */ void expand(size_t size); +#else + Network *mNetwork; +#endif char *mData; /**< Data building up. */ unsigned int mDataSize; /**< Size of data. */ diff --git a/src/net/npchandler.h b/src/net/npchandler.h index 5560787e..18ab0a05 100644 --- a/src/net/npchandler.h +++ b/src/net/npchandler.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NET_NPCHANDLER_H -#define _TMW_NET_NPCHANDLER_H +#ifndef NET_NPCHANDLER_H +#define NET_NPCHANDLER_H #include "messagehandler.h" diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index beb59250..b4e2f328 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -134,8 +134,8 @@ void PlayerHandler::handleMessage(MessageIn &msg) if (stat == BASE_ATTR_HP) { - player_node->setMaxHP(base); - player_node->setHP(value); + player_node->setMaxHp(base); + player_node->setHp(value); } else if (stat < NB_CHARACTER_ATTRIBUTES) { diff --git a/src/net/playerhandler.h b/src/net/playerhandler.h index 9c5f87cc..fef767da 100644 --- a/src/net/playerhandler.h +++ b/src/net/playerhandler.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NET_PLAYERHANDLER_H -#define _TMW_NET_PLAYERHANDLER_H +#ifndef NET_PLAYERHANDLER_H +#define NET_PLAYERHANDLER_H #include "messagehandler.h" @@ -29,12 +29,10 @@ class PlayerHandler : public MessageHandler public: PlayerHandler(); - void - handleMessage(MessageIn &msg); + void handleMessage(MessageIn &msg); private: - void - handleMapChangeMessage(MessageIn &msg); + void handleMapChangeMessage(MessageIn &msg); }; #endif diff --git a/src/net/tradehandler.h b/src/net/tradehandler.h index 1a0fa695..6ffe17b5 100644 --- a/src/net/tradehandler.h +++ b/src/net/tradehandler.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NET_TRADEHANDLER_H -#define _TMW_NET_TRADEHANDLER_H +#ifndef NET_TRADEHANDLER_H +#define NET_TRADEHANDLER_H #include "messagehandler.h" diff --git a/src/npc.cpp b/src/npc.cpp index 5665ad95..bc25fa5d 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -1,43 +1,59 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "npc.h" - #include "animatedsprite.h" -#include "graphics.h" +#include "npc.h" #include "particle.h" +#include "text.h" -#include "gui/gui.h" -#include "net/messageout.h" +#include "gui/npc_text.h" + +#ifdef TMWSERV_SUPPORT #include "net/gameserver/player.h" +#else +#include "net/messageout.h" +#include "net/ea/protocol.h" +#endif + #include "resources/npcdb.h" +extern NpcTextDialog *npcTextDialog; + NPC *current_npc = 0; -NPC::NPC(Uint16 id, int sprite, Map *map): - Being(id, sprite, map) +static const int NAME_X_OFFSET = 15; +static const int NAME_Y_OFFSET = 30; + +#ifdef TMWSERV_SUPPORT +NPC::NPC(Uint16 id, int job, Map *map): + Player(id, job, map) +#else +NPC::NPC(Uint32 id, Uint16 job, Map *map, Network *network): + Player(id, job, map), + mNetwork(network) +#endif { - NPCInfo info = NPCDB::get(sprite); + NPCInfo info = NPCDB::get(job); - //setup NPC sprites + // Setup NPC sprites int c = BASE_SPRITE; for (std::list<NPCsprite*>::const_iterator i = info.sprites.begin(); i != info.sprites.end(); @@ -51,74 +67,161 @@ NPC::NPC(Uint16 id, int sprite, Map *map): 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, 0); - this->controlParticle(p); + //setup particle effects + for (std::list<std::string>::const_iterator i = info.particles.begin(); + i != info.particles.end(); + i++) + { + Particle *p = particleEngine->addEffect(*i, 0, 0); + this->controlParticle(p); + } } + mName = 0; + + mNameColor = 0x21bbbb; } -Being::Type -NPC::getType() const +NPC::~NPC() { - return Being::NPC; + delete mName; + + if (current_npc == this) handleDeath(); +} + +void NPC::setName(const std::string &name) +{ + const std::string displayName = name.substr(0, name.find('#', 0)); + + delete mName; + mName = new Text(displayName, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET, + gcn::Graphics::CENTER, gcn::Color(200, 200, 255)); + Being::setName(displayName + " (NPC)"); } -void NPC::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) +void NPC::setGender(Gender gender) { - const Vector &pos = getPosition(); - const int px = (int) pos.x + offsetX; - const int py = (int) pos.y + offsetY; + Being::setGender(gender); +} - graphics->setFont(speechFont); - graphics->setColor(gcn::Color(200, 200, 255)); - graphics->drawText(mName, px, py, gcn::Graphics::CENTER); +void NPC::setSprite(int slot, int id, std::string color) +{ + // Fix this later should it not be adequate enough. + Being::setSprite(slot, id, color); +} + +Being::Type NPC::getType() const +{ + return Being::NPC; } -void -NPC::talk() +void NPC::talk() { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::talkToNPC(mId, true); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_TALK); + outMsg.writeInt32(mId); + outMsg.writeInt8(0); +#endif current_npc = this; } -void -NPC::nextDialog() +void NPC::nextDialog() { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::talkToNPC(mId, false); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_NEXT_REQUEST); + outMsg.writeInt32(mId); +#endif } -void -NPC::dialogChoice(int choice) +void NPC::dialogChoice(char choice) { +#ifdef TMWSERV_SUPPORT Net::GameServer::Player::selectFromNPC(mId, choice); +#else + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_LIST_CHOICE); + outMsg.writeInt32(mId); + outMsg.writeInt8(choice); +#endif +} + +void NPC::integerInput(int value) +{ +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_INT_RESPONSE); + outMsg.writeInt32(mId); + outMsg.writeInt32(value); +#endif +} + +void NPC::stringInput(const std::string &value) +{ +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_STR_RESPONSE); + outMsg.writeInt16(value.length() + 9); + outMsg.writeInt32(mId); + outMsg.writeString(value, value.length()); + outMsg.writeInt8(0); +#endif } /* * TODO Unify the buy() and sell() methods, without sacrificing readability of * the code calling the method. buy(bool buySell) would be bad... */ -void -NPC::buy() +void NPC::buy() { // XXX Convert for new server - /* - MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST); outMsg.writeInt32(mId); outMsg.writeInt8(0); - */ +#endif } -void -NPC::sell() +void NPC::sell() { // XXX Convert for new server - /* - MessageOut outMsg(CMSG_NPC_BUY_SELL_REQUEST); +#ifdef EATHENA_SUPPORT + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST); outMsg.writeInt32(mId); outMsg.writeInt8(1); - */ +#endif +} + +void NPC::updateCoords() +{ + if (mName) + { +#ifdef TMWSERV_SUPPORT + const Vector &pos = getPosition(); + const int px = (int) pos.x + NAME_X_OFFSET; + const int py = (int) pos.y + NAME_Y_OFFSET; +#else + const int px = mPx + NAME_X_OFFSET; + const int py = mPy + NAME_Y_OFFSET; +#endif + mName->adviseXY(px, py); + } +} + +void NPC::handleDeath() +{ + printf("NPC::handleDeath\n"); + if (this != current_npc) return; + + if (npcTextDialog->isVisible()) + npcTextDialog->showCloseButton(); + else current_npc = NULL; } @@ -1,50 +1,68 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NPC_H -#define _TMW_NPC_H +#ifndef NPC_H +#define NPC_H -#include "being.h" +#include "player.h" +#ifdef EATHENA_SUPPORT +class Network; +#endif class Graphics; +class Text; -class NPC : public Being +class NPC : public Player { public: +#ifdef TMWSERV_SUPPORT NPC(Uint16 id, int sprite, Map *map); +#else + NPC(Uint32 id, Uint16 job, Map *map, Network *network); +#endif - virtual Type - getType() const; + ~NPC(); - virtual void - drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY); + void setName(const std::string &name); + void setGender(Gender gender); + void setSprite(int slot, int id, std::string color); + + virtual Type getType() const; void talk(); void nextDialog(); - void dialogChoice(int choice); + void dialogChoice(char choice); + void integerInput(int value); + void stringInput(const std::string &value); void buy(); void sell(); /** + * Call this to ease clean up of the current NPC, without causing + * interface problems + */ + void handleDeath(); + + /** * Gets the way an NPC is blocked by other things on the map */ virtual unsigned char getWalkMask() const @@ -56,6 +74,13 @@ class NPC : public Being */ virtual Map::BlockType getBlockType() const { return Map::BLOCKTYPE_CHARACTER; } //blocks like a player character + +#ifdef EATHENA_SUPPORT + Network *mNetwork; +#endif + void updateCoords(); + private: + Text *mName; }; extern NPC *current_npc; diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index 48b10a1f..e7e7b204 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -1,48 +1,41 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "main.h" - -#ifdef USE_OPENGL - -#ifndef GL_TEXTURE_RECTANGLE_ARB -#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 -#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 -#endif +#include <SDL.h> +#include "log.h" #include "openglgraphics.h" -#include <cstring> -#include <SDL.h> +#include "resources/image.h" #ifdef __APPLE__ #include <OpenGL/OpenGL.h> #endif -#include <guichan/exception.hpp> -#include <guichan/image.hpp> - -#include "log.h" +#ifdef USE_OPENGL -#include "resources/image.h" +#ifndef GL_TEXTURE_RECTANGLE_ARB +#define GL_TEXTURE_RECTANGLE_ARB 0x84F5 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 +#endif OpenGLGraphics::OpenGLGraphics(): mAlpha(false), mTexture(false), mColorAlpha(false), diff --git a/src/openglgraphics.h b/src/openglgraphics.h index ea30e019..566d6252 100644 --- a/src/openglgraphics.h +++ b/src/openglgraphics.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_OPENGLGRAPHICS_H -#define _TMW_OPENGLGRAPHICS_H +#ifndef OPENGLGRAPHICS_H +#define OPENGLGRAPHICS_H #include "graphics.h" diff --git a/src/particle.cpp b/src/particle.cpp index c6e242bd..f021f6e5 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -1,34 +1,35 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <algorithm> #include <cmath> -#include "particle.h" +#include <guichan/color.hpp> #include "animationparticle.h" #include "configuration.h" #include "imageparticle.h" #include "log.h" #include "map.h" +#include "particle.h" #include "particleemitter.h" #include "textparticle.h" @@ -188,13 +189,13 @@ bool Particle::update() e++ ) { - Particles newParticles = (*e)->createParticles(); + Particles newParticles = (*e)->createParticles(mLifetimePast); for ( ParticleIterator p = newParticles.begin(); p != newParticles.end(); p++ ) { - (*p)->moveBy(mPos.x, mPos.y, mPos.z); + (*p)->moveBy(mPos); mChildParticles.push_back (*p); } } @@ -231,6 +232,25 @@ bool Particle::update() return true; } +void Particle::moveBy(const Vector &change) +{ + mPos += change; + for (ParticleIterator p = mChildParticles.begin(); + p != mChildParticles.end(); + p++) + { + if ((*p)->doesFollow()) + { + (*p)->moveBy(change); + } + } +} + +void Particle::moveTo(float x, float y) +{ + moveTo(Vector(x, y, mPos.z)); +} + Particle *Particle::addEffect(const std::string &particleEffectFile, int pixelX, int pixelY, int rotation) { @@ -276,17 +296,15 @@ Particle *Particle::addEffect(const std::string &particleEffectFile, } // Read and set the basic properties of the particle - int offsetX = XML::getProperty(effectChildNode, "position-x", 0); - int offsetY = XML::getProperty(effectChildNode, "position-y", 0); - int offsetZ = XML::getProperty(effectChildNode, "position-z", 0); - - int particleX = (int) mPos.x + pixelX + offsetX; - int particleY = (int) mPos.y + pixelY + offsetY; - int particleZ = (int) mPos.z + offsetZ; + float offsetX = XML::getFloatProperty(effectChildNode, "position-x", 0); + float offsetY = XML::getFloatProperty(effectChildNode, "position-y", 0); + float offsetZ = XML::getFloatProperty(effectChildNode, "position-z", 0); + Vector position (mPos.x + (float)pixelX + offsetX, + mPos.y + (float)pixelY + offsetY, + mPos.z + offsetZ); + newParticle->moveTo(position); int lifetime = XML::getProperty(effectChildNode, "lifetime", -1); - - newParticle->setPosition(particleX, particleY, particleZ); newParticle->setLifetime(lifetime); // Look for additional emitters for this particle @@ -312,7 +330,7 @@ Particle *Particle::addTextSplashEffect(const std::string &text, { Particle *newParticle = new TextParticle(mMap, text, colorR, colorG, colorB, font); - newParticle->setPosition(x, y, 0); + newParticle->moveTo(x, y); newParticle->setVelocity(((rand() % 100) - 50) / 200.0f, // X ((rand() % 100) - 50) / 200.0f, // Y ((rand() % 100) / 200.0f) + 4.0f); // Z @@ -332,7 +350,7 @@ Particle *Particle::addTextRiseFadeOutEffect(const std::string &text, int x, int y) { Particle *newParticle = new TextParticle(mMap, text, colorR, colorG, colorB, font); - newParticle->setPosition(x, y, 0); + newParticle->moveTo(x, y); newParticle->setVelocity(0.0f, 0.0f, 0.5f); newParticle->setGravity(0.0015f); newParticle->setLifetime(300); diff --git a/src/particle.h b/src/particle.h index af0caf21..008c343b 100644 --- a/src/particle.h +++ b/src/particle.h @@ -1,32 +1,30 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _PARTICLE_H -#define _PARTICLE_H +#ifndef PARTICLE_H +#define PARTICLE_H #include <list> #include <string> -#include <guichan/color.hpp> - #include "guichanfwd.h" #include "sprite.h" #include "vector.h" @@ -128,14 +126,13 @@ class Particle : public Sprite /** * Sets the position in 3 dimensional space in pixels relative to map. */ - void setPosition(float x, float y, float z) - { mPos.x = x; mPos.y = y; mPos.z = z; } + void moveTo(const Vector &pos) + { moveBy (pos - mPos);} /** * Sets the position in 2 dimensional space in pixels relative to map. */ - void setPosition(float x, float y) - { mPos.x = x; mPos.y = y; } + void moveTo(float x, float y); /** * Returns the particle position. @@ -146,13 +143,7 @@ class Particle : public Sprite /** * Changes the particle position relative */ - void moveBy(float x, float y, float z) - { mPos.x += x; mPos.y += y; mPos.z += z; } - - void moveChildren(Vector change); - - void moveBy (Vector change) - { mPos += change; } + void moveBy (const Vector &change); /** * Sets the time in game ticks until the particle is destroyed. diff --git a/src/particlecontainer.cpp b/src/particlecontainer.cpp new file mode 100644 index 00000000..63f89079 --- /dev/null +++ b/src/particlecontainer.cpp @@ -0,0 +1,174 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <cassert> + +#include "particle.h" +#include "particlecontainer.h" + + +ParticleContainer::ParticleContainer(ParticleContainer *parent, + bool delParent): + mDelParent(delParent), + mNext(parent) +{} + +ParticleContainer::~ParticleContainer() +{ + clearLocally(); + if (mDelParent) + delete mNext; +} + +void ParticleContainer::clear() +{ + clearLocally(); + if (mNext) + mNext->clear(); +} + +void ParticleContainer::moveTo(float x, float y) +{ + if (mNext) + mNext->moveTo(x, y); +} + +// -- particle list ---------------------------------------- + +ParticleList::ParticleList(ParticleContainer *parent, bool delParent): + ParticleContainer(parent, delParent) +{} + +ParticleList::~ParticleList() +{} + +void ParticleList::addLocally(Particle *particle) +{ + if (particle) + { + // The effect may not die without the beings permission or we segfault + particle->disableAutoDelete(); + mElements.push_back(particle); + } +} + +void ParticleList::removeLocally(Particle *particle) +{ + for (std::list<Particle *>::iterator it = mElements.begin(); + it != mElements.end(); it++) + { + if (*it == particle) { + (*it)->kill(); + mElements.erase(it); + } + } +} + +void ParticleList::clearLocally() +{ + for (std::list<Particle *>::iterator it = mElements.begin(); + it != mElements.end(); it++) + (*it)->kill(); + + mElements.clear(); +} + +void ParticleList::moveTo(float x, float y) +{ + ParticleContainer::moveTo(x, y); + + for (std::list<Particle *>::iterator it = mElements.begin(); + it != mElements.end();) + { + (*it)->moveTo(x, y); + if ((*it)->isExtinct()) + { + (*it)->kill(); + it = mElements.erase(it); + } + else + it++; + } +} + +// -- particle vector ---------------------------------------- + +ParticleVector::ParticleVector(ParticleContainer *parent, bool delParent): + ParticleContainer(parent, delParent) +{} + +ParticleVector::~ParticleVector() +{} + +void ParticleVector::setLocally(int index, Particle *particle) +{ + assert(index >= 0); + + delLocally(index); + + if (mIndexedElements.size() <= (unsigned) index) + mIndexedElements.resize(index + 1, NULL); + + if (particle) + particle->disableAutoDelete(); + mIndexedElements[index] = particle; +} + +void ParticleVector::delLocally(int index) +{ + assert(index >= 0); + + if (mIndexedElements.size() <= (unsigned) index) + return; + + Particle *p = mIndexedElements[index]; + if (p) + { + mIndexedElements[index] = NULL; + p->kill(); + } +} + +void ParticleVector::clearLocally() +{ + for (unsigned int i = 0; i < mIndexedElements.size(); i++) + delLocally(i); +} + +void ParticleVector::moveTo(float x, float y) +{ + ParticleContainer::moveTo(x, y); + + for (std::vector<Particle *>::iterator it = mIndexedElements.begin(); + it != mIndexedElements.end(); it++) { + if (*it) + { + (*it)->moveTo(x, y); + + if ((*it)->isExtinct()) + { + (*it)->kill(); + *it = NULL; + } + } + } +} + diff --git a/src/particlecontainer.h b/src/particlecontainer.h new file mode 100644 index 00000000..26539dd7 --- /dev/null +++ b/src/particlecontainer.h @@ -0,0 +1,121 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _PARTICLE_CONTAINER_H +#define _PARTICLE_CONTAINER_H + +#include <list> +#include <vector> + +class Particle; + +/** + * Set of particle effects. May be stacked with other ParticleContainers. All + * operations herein affect such stacked containers, unless the operations end + * in `Locally'. + */ +class ParticleContainer +{ +public: + /** + * Constructs a new particle container and assumes responsibility for + * its parent (for all operations defined herein, except when ending in `Locally') + * + * delParent means that the destructor should also free the parent. + */ + ParticleContainer(ParticleContainer *parent = NULL, bool delParent = true); + virtual ~ParticleContainer(); + + /** + * Kills and removes all particle effects + */ + void clear(); + + /** + * Kills and removes all particle effects (only in this container) + */ + virtual void clearLocally() {}; + + /** + * Sets the positions of all elements + */ + virtual void moveTo(float x, float y); + +protected: + bool mDelParent; /**< Delete mNext in destructor */ + ParticleContainer *mNext; /**< Contained container, if any */ +}; + +/** + * Linked list of particle effects. + */ +class ParticleList : public ParticleContainer +{ +public: + ParticleList(ParticleContainer *parent = NULL, bool delParent = true); + virtual ~ParticleList(); + + /** + * Takes control of and adds a particle + */ + void addLocally(Particle *); + + /** + * `kills' and removes a particle + */ + void removeLocally(Particle *); + + virtual void clearLocally(); + + virtual void moveTo(float x, float y); + +protected: + std::list<Particle *> mElements; /**< Contained particle effects */ +}; + +/** + * Particle container with indexing facilities + */ +class ParticleVector : public ParticleContainer +{ +public: + ParticleVector(ParticleContainer *parent = NULL, bool delParent = true); + virtual ~ParticleVector(); + + /** + * Sets a particle at a specified index. Kills the previous particle + * there, if needed. + */ + virtual void setLocally(int index, Particle *particle); + + /** + * Removes a particle at a specified index + */ + virtual void delLocally(int index); + + virtual void clearLocally(); + virtual void moveTo(float x, float y); + +protected: + std::vector<Particle *> mIndexedElements; +}; + +#endif diff --git a/src/particleemitter.cpp b/src/particleemitter.cpp index d368237c..25e6ade5 100644 --- a/src/particleemitter.cpp +++ b/src/particleemitter.cpp @@ -1,37 +1,35 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "particleemitter.h" +#include <cmath> #include "animationparticle.h" #include "imageparticle.h" #include "log.h" #include "particle.h" +#include "particleemitter.h" -#include "resources/animation.h" #include "resources/image.h" -#include "resources/resourcemanager.h" #include "resources/imageset.h" - -#include <cmath> +#include "resources/resourcemanager.h" #define SIN45 0.707106781f #define DEG_RAD_FACTOR 0.017453293f @@ -43,7 +41,7 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map * mMap = map; mParticleTarget = target; - //initializing default values + // Initializing default values mParticlePosX.set(0.0f); mParticlePosY.set(0.0f); mParticlePosZ.set(0.0f); @@ -72,26 +70,28 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map * if (name == "position-x") { - mParticlePosX = readMinMax(propertyNode, 0.0f); + mParticlePosX = readParticleEmitterProp(propertyNode, 0.0f); } else if (name == "position-y") { - mParticlePosY = readMinMax(propertyNode, 0.0f); + mParticlePosY = readParticleEmitterProp(propertyNode, 0.0f); mParticlePosY.minVal *= SIN45; mParticlePosY.maxVal *= SIN45; + mParticlePosY.changeAmplitude *= SIN45; } else if (name == "position-z") { - mParticlePosZ = readMinMax(propertyNode, 0.0f); + mParticlePosZ = readParticleEmitterProp(propertyNode, 0.0f); mParticlePosZ.minVal *= SIN45; mParticlePosZ.maxVal *= SIN45; + mParticlePosZ.changeAmplitude *= SIN45; } else if (name == "image") { std::string image = XML::getProperty(propertyNode, "value", ""); // Don't leak when multiple images are defined - if (image != "" && !mParticleImage) + if (!image.empty() && !mParticleImage) { ResourceManager *resman = ResourceManager::getInstance(); mParticleImage = resman->getImage(image); @@ -99,69 +99,74 @@ ParticleEmitter::ParticleEmitter(xmlNodePtr emitterNode, Particle *target, Map * } else if (name == "horizontal-angle") { - mParticleAngleHorizontal = readMinMax(propertyNode, 0.0f); - mParticleAngleHorizontal += rotation; - mParticleAngleHorizontal *= DEG_RAD_FACTOR; + 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; } else if (name == "vertical-angle") { - mParticleAngleVertical = readMinMax(propertyNode, 0.0f); - mParticleAngleVertical *= DEG_RAD_FACTOR; + mParticleAngleVertical = readParticleEmitterProp(propertyNode, 0.0f); + mParticleAngleVertical.minVal *= DEG_RAD_FACTOR; + mParticleAngleVertical.maxVal *= DEG_RAD_FACTOR; + mParticleAngleVertical.changeAmplitude *= DEG_RAD_FACTOR; } else if (name == "power") { - mParticlePower = readMinMax(propertyNode, 0.0f); + mParticlePower = readParticleEmitterProp(propertyNode, 0.0f); } else if (name == "gravity") { - mParticleGravity = readMinMax(propertyNode, 0.0f); + mParticleGravity = readParticleEmitterProp(propertyNode, 0.0f); } else if (name == "randomnes" || name == "randomness") // legacy bug { - mParticleRandomness = readMinMax(propertyNode, 0); + mParticleRandomness = readParticleEmitterProp(propertyNode, 0); } else if (name == "bounce") { - mParticleBounce = readMinMax(propertyNode, 0.0f); + mParticleBounce = readParticleEmitterProp(propertyNode, 0.0f); } else if (name == "lifetime") { - mParticleLifetime = readMinMax(propertyNode, 0); + mParticleLifetime = readParticleEmitterProp(propertyNode, 0); mParticleLifetime.minVal += 1; } else if (name == "output") { - mOutput = readMinMax(propertyNode, 0); + mOutput = readParticleEmitterProp(propertyNode, 0); mOutput.maxVal +=1; } else if (name == "output-pause") { - mOutputPause = readMinMax(propertyNode, 0); - mOutputPauseLeft = mOutputPause.value(); + mOutputPause = readParticleEmitterProp(propertyNode, 0); + mOutputPauseLeft = mOutputPause.value(0); } else if (name == "acceleration") { - mParticleAcceleration = readMinMax(propertyNode, 0.0f); + mParticleAcceleration = readParticleEmitterProp(propertyNode, 0.0f); } else if (name == "die-distance") { - mParticleDieDistance = readMinMax(propertyNode, 0.0f); + mParticleDieDistance = readParticleEmitterProp(propertyNode, 0.0f); } else if (name == "momentum") { - mParticleMomentum = readMinMax(propertyNode, 1.0f); + mParticleMomentum = readParticleEmitterProp(propertyNode, 1.0f); } else if (name == "fade-out") { - mParticleFadeOut = readMinMax(propertyNode, 0); + mParticleFadeOut = readParticleEmitterProp(propertyNode, 0); } else if (name == "fade-in") { - mParticleFadeIn = readMinMax(propertyNode, 0); + mParticleFadeIn = readParticleEmitterProp(propertyNode, 0); } else if (name == "alpha") { - mParticleAlpha = readMinMax(propertyNode, 1.0f); + mParticleAlpha = readParticleEmitterProp(propertyNode, 1.0f); } else if (name == "follow-parent") { @@ -296,21 +301,34 @@ ParticleEmitter::~ParticleEmitter() } -template <typename T> MinMax<T> -ParticleEmitter::readMinMax(xmlNodePtr propertyNode, T def) +template <typename T> ParticleEmitterProp<T> +ParticleEmitter::readParticleEmitterProp(xmlNodePtr propertyNode, T def) { - MinMax<T> retval; + ParticleEmitterProp<T> retval; def = (T) XML::getFloatProperty(propertyNode, "value", (double) 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); + } + return retval; } -std::list<Particle *> -ParticleEmitter::createParticles() +std::list<Particle *> ParticleEmitter::createParticles(int tick) { std::list<Particle *> newParticles; @@ -319,9 +337,9 @@ ParticleEmitter::createParticles() mOutputPauseLeft--; return newParticles; } - mOutputPauseLeft = mOutputPause.value(); + mOutputPauseLeft = mOutputPause.value(tick); - for (int i = mOutput.value(); i > 0; i--) + for (int i = mOutput.value(tick); i > 0; i--) { // Limit maximum particles if (Particle::particleCount > Particle::maxCount) break; @@ -341,35 +359,34 @@ ParticleEmitter::createParticles() newParticle = new Particle(mMap); } + Vector position(mParticlePosX.value(tick), + mParticlePosY.value(tick), + mParticlePosZ.value(tick)); + newParticle->moveTo(position); - newParticle->setPosition( - mParticlePosX.value(), - mParticlePosY.value(), - mParticlePosZ.value()); - - float angleH = mParticleAngleHorizontal.value(); - float angleV = mParticleAngleVertical.value(); - float power = mParticlePower.value(); + float angleH = mParticleAngleHorizontal.value(tick); + float angleV = mParticleAngleVertical.value(tick); + float power = mParticlePower.value(tick); newParticle->setVelocity( cos(angleH) * cos(angleV) * power, sin(angleH) * cos(angleV) * power, sin(angleV) * power); - newParticle->setRandomness(mParticleRandomness.value()); - newParticle->setGravity(mParticleGravity.value()); - newParticle->setBounce(mParticleBounce.value()); + newParticle->setRandomness(mParticleRandomness.value(tick)); + newParticle->setGravity(mParticleGravity.value(tick)); + newParticle->setBounce(mParticleBounce.value(tick)); newParticle->setFollow(mParticleFollow); newParticle->setDestination(mParticleTarget, - mParticleAcceleration.value(), - mParticleMomentum.value() + mParticleAcceleration.value(tick), + mParticleMomentum.value(tick) ); - newParticle->setDieDistance(mParticleDieDistance.value()); + newParticle->setDieDistance(mParticleDieDistance.value(tick)); - newParticle->setLifetime(mParticleLifetime.value()); - newParticle->setFadeOut(mParticleFadeOut.value()); - newParticle->setFadeIn(mParticleFadeIn.value()); - newParticle->setAlpha(mParticleAlpha.value()); + newParticle->setLifetime(mParticleLifetime.value(tick)); + newParticle->setFadeOut(mParticleFadeOut.value(tick)); + newParticle->setFadeIn(mParticleFadeIn.value(tick)); + newParticle->setAlpha(mParticleAlpha.value(tick)); for (std::list<ParticleEmitter>::iterator i = mParticleChildEmitters.begin(); i != mParticleChildEmitters.end(); diff --git a/src/particleemitter.h b/src/particleemitter.h index 4dc2f6fb..67b35ae2 100644 --- a/src/particleemitter.h +++ b/src/particleemitter.h @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -25,7 +25,8 @@ #include <list> #include "utils/xml.h" -#include "utils/minmax.h" + +#include "particleemitterprop.h" #include "resources/animation.h" @@ -64,60 +65,59 @@ class ParticleEmitter * Spawns new particles * @return: a list of created particles */ - std::list<Particle *> createParticles(); + std::list<Particle *> createParticles(int tick); /** * Sets the target of the particles that are created */ - void - setTarget(Particle *target) + void setTarget(Particle *target) { mParticleTarget = target; }; private: - template <typename T> MinMax<T> readMinMax(xmlNodePtr propertyNode, T def); + template <typename T> ParticleEmitterProp<T> readParticleEmitterProp(xmlNodePtr propertyNode, T def); /** * initial position of particles: */ - MinMax<float> mParticlePosX, mParticlePosY, mParticlePosZ; + ParticleEmitterProp<float> mParticlePosX, mParticlePosY, mParticlePosZ; /** * initial vector of particles: */ - MinMax<float> mParticleAngleHorizontal, mParticleAngleVertical; + ParticleEmitterProp<float> mParticleAngleHorizontal, mParticleAngleVertical; /** * Initial velocity of particles */ - MinMax<float> mParticlePower; + ParticleEmitterProp<float> mParticlePower; /* * Vector changing of particles: */ - MinMax<float> mParticleGravity; - MinMax<int> mParticleRandomness; - MinMax<float> mParticleBounce; + ParticleEmitterProp<float> mParticleGravity; + ParticleEmitterProp<int> mParticleRandomness; + ParticleEmitterProp<float> mParticleBounce; bool mParticleFollow; /* * Properties of targeting particles: */ Particle *mParticleTarget; - MinMax<float> mParticleAcceleration; - MinMax<float> mParticleDieDistance; - MinMax<float> mParticleMomentum; + ParticleEmitterProp<float> mParticleAcceleration; + ParticleEmitterProp<float> mParticleDieDistance; + ParticleEmitterProp<float> mParticleMomentum; /* * Behavior over time of the particles: */ - MinMax<int> mParticleLifetime; - MinMax<int> mParticleFadeOut; - MinMax<int> mParticleFadeIn; + ParticleEmitterProp<int> mParticleLifetime; + ParticleEmitterProp<int> mParticleFadeOut; + ParticleEmitterProp<int> mParticleFadeIn; Map *mMap; /**< Map the particles are spawned on */ - MinMax<int> mOutput; /**< Number of particles spawned per update */ - MinMax<int> mOutputPause; /**< Pause in frames between two spawns */ + ParticleEmitterProp<int> mOutput; /**< Number of particles spawned per update */ + ParticleEmitterProp<int> mOutputPause; /**< Pause in frames between two spawns */ int mOutputPauseLeft; /* @@ -125,7 +125,7 @@ class ParticleEmitter */ Image *mParticleImage; /**< Particle image, if used */ Animation mParticleAnimation; /**< Filename of particle animation file */ - MinMax<float> mParticleAlpha; /**< Opacity of the graphical representation of the particles */ + ParticleEmitterProp<float> mParticleAlpha; /**< Opacity of the graphical representation of the particles */ /** List of emitters the spawned particles are equipped with */ std::list<ParticleEmitter> mParticleChildEmitters; diff --git a/src/particleemitterprop.h b/src/particleemitterprop.h new file mode 100644 index 00000000..e68ac222 --- /dev/null +++ b/src/particleemitterprop.h @@ -0,0 +1,109 @@ +/* + * The Mana World + * Copyright (C) 2006 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <cmath> + +/** + * Returns a random numeric value that is larger than or equal min and smaller + * than max + */ + +enum ChangeFunc +{ + FUNC_NONE, + FUNC_SINE, + FUNC_SAW, + FUNC_TRIANGLE, + FUNC_SQUARE +}; + +template <typename T> struct ParticleEmitterProp +{ + ParticleEmitterProp(): + changeFunc(FUNC_NONE) + { + } + + void set(T min, T max) + { + minVal=min; maxVal=max; + } + + void set(T val) + { + set(val, val); + } + + void setFunction(ChangeFunc func, T amplitude, int period, int phase) + { + changeFunc = func; + changeAmplitude = amplitude; + changePeriod = period; + changePhase = phase; + } + + T value(int tick) + { + tick += changePhase; + T val = (T) (minVal + (maxVal - minVal) * (rand() / ((double) RAND_MAX + 1))); + + switch (changeFunc) + { + case FUNC_SINE: + val += (T) std::sin(M_PI * 2 * ((double)(tick%changePeriod) / (double)changePeriod)) * changeAmplitude; + break; + case FUNC_SAW: + val += (T) (changeAmplitude * ((double)(tick%changePeriod) / (double)changePeriod)) * 2 - changeAmplitude; + break; + case FUNC_TRIANGLE: + if ((tick%changePeriod) * 2 < changePeriod) + { + val += changeAmplitude - (T)((tick%changePeriod) / (double)changePeriod) * changeAmplitude * 4; + } else { + val += changeAmplitude * -3 + (T)((tick%changePeriod) / (double)changePeriod) * changeAmplitude * 4; + // I have no idea why this works but it does + } + break; + case FUNC_SQUARE: + if ((tick%changePeriod) * 2 < changePeriod) + { + val += changeAmplitude; + } else { + val -= changeAmplitude; + } + break; + case FUNC_NONE: + default: + //nothing + break; + } + + return val; + } + + T minVal; + T maxVal; + + ChangeFunc changeFunc; + T changeAmplitude; + int changePeriod; + int changePhase; +}; diff --git a/src/party.cpp b/src/party.cpp new file mode 100644 index 00000000..d22db55f --- /dev/null +++ b/src/party.cpp @@ -0,0 +1,217 @@ +/* + * The Mana World + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "being.h" +#include "localplayer.h" +#include "party.h" + +#include "gui/chat.h" +#include "gui/confirm_dialog.h" + +#include "net/messageout.h" +#include "net/ea/protocol.h" + +#include "utils/gettext.h" +#include "utils/strprintf.h" + +Party::Party(ChatWindow *chat, Network *network) : + mChat(chat), + mNetwork(network), + mInviteListener(network, &mInParty) +{ +} + +void Party::respond(const std::string &command, const std::string &args) +{ + if (command == "new" || command == "create") + { + create(args); + return; + } + if (command == "leave") + { + leave(args); + return; + } + if (command == "settings") + { + mChat->chatLog(_("Not yet implemented!"), BY_SERVER); + return; + /* + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PARTY_SETTINGS); + outMsg.writeInt16(0); // Experience + outMsg.writeInt16(0); // Item + */ + } + mChat->chatLog(_("Party command not known."), BY_SERVER); +} + +void Party::create(const std::string &party) +{ + if (party.empty()) + { + mChat->chatLog(_("Party name is missing."), BY_SERVER); + return; + } + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PARTY_CREATE); + outMsg.writeString(party.substr(0, 23), 24); + mCreating = true; +} + +void Party::leave(const std::string &args) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PARTY_LEAVE); + mChat->chatLog(_("Left party."), BY_SERVER); + mInParty = false; +} + +void Party::createResponse(bool ok) +{ + if (ok) + { + mChat->chatLog(_("Party successfully created."), BY_SERVER); + mInParty = true; + } + else + { + mChat->chatLog(_("Could not create party."), BY_SERVER); + } +} + +void Party::inviteResponse(const std::string &nick, int status) +{ + switch (status) + { + case 0: + mChat->chatLog(strprintf(_("%s is already a member of a party."), + nick.c_str()), BY_SERVER); + break; + case 1: + mChat->chatLog(strprintf(_("%s refused your invitation."), + nick.c_str()), BY_SERVER); + break; + case 2: + mChat->chatLog(strprintf(_("%s is now a member of your party."), + nick.c_str()), BY_SERVER); + break; + } +} + +void Party::invitedAsk(const std::string &nick, int gender, + const std::string &partyName) +{ + mPartyName = partyName; /* Quick and nasty - needs redoing */ + if (nick.empty()) + { + mChat->chatLog(_("You can\'t have a blank party name!"), BY_SERVER); + return; + } + mCreating = false; + ConfirmDialog *dlg = new ConfirmDialog(_("Invite to party"), + strprintf(_("%s invites you to join" + " the %s party, do you accept?"), + nick.c_str(), partyName.c_str())); + dlg->addActionListener(&mInviteListener); +} + +void Party::InviteListener::action(const gcn::ActionEvent &event) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PARTY_INVITED); + outMsg.writeInt32(player_node->getId()); + bool accept = event.getId() == "yes"; + outMsg.writeInt32(accept ? 1 : 0); + *mInParty = *mInParty || accept; +} + +void Party::leftResponse(const std::string &nick) +{ + mChat->chatLog(strprintf(_("%s has left your party."), nick.c_str()), + BY_SERVER); +} + +void Party::receiveChat(Being *being, const std::string &msg) +{ + if (!being) + { + return; + } + if (being->getType() != Being::PLAYER) + { + mChat->chatLog(_("Party chat received, but being is not a player"), + BY_SERVER); + return; + } + being->setSpeech(msg, SPEECH_TIME); + mChat->chatLog(being->getName() + " : " + msg, BY_PARTY); +} + +void Party::help(const std::string &msg) +{ + if (msg.empty()) + { + mChat->chatLog(_("Command: /party <command> <args>"), BY_SERVER); + mChat->chatLog(_("where <command> can be one of:"), BY_SERVER); + mChat->chatLog(_(" /new"), BY_SERVER); + mChat->chatLog(_(" /create"), BY_SERVER); + mChat->chatLog(_(" /prefix"), BY_SERVER); + mChat->chatLog(_(" /leave"), BY_SERVER); + mChat->chatLog(_("This command implements the partying function."), + BY_SERVER); + mChat->chatLog(_("Type /help party <command> for further help."), + BY_SERVER); + return; + } + if (msg == "new" || msg == "create") + { + mChat->chatLog(_("Command: /party new <party-name>"), BY_SERVER); + mChat->chatLog(_("Command: /party create <party-name>"), BY_SERVER); + mChat->chatLog(_("These commands create a new party <party-name."), + BY_SERVER); + return; + } + if (msg == "prefix") + { + mChat->chatLog(_("Command: /party prefix <prefix-char>"), BY_SERVER); + mChat->chatLog(_("This command sets the party prefix character."), + BY_SERVER); + mChat->chatLog(_("Any message preceded by <prefix-char> is sent to " + "the party instead of everyone."), BY_SERVER); + mChat->chatLog(_("Command: /party prefix"), BY_SERVER); + mChat->chatLog(_("This command reports the current party prefix " + "character."), BY_SERVER); + return; + } + //if (msg == "settings") + //if (msg == "info") + if (msg == "leave") + { + mChat->chatLog(_("Command: /party leave"), BY_SERVER); + mChat->chatLog(_("This command causes the player to leave the party."), + BY_SERVER); + return; + } + mChat->chatLog(_("Unknown /party command."), BY_SERVER); + mChat->chatLog(_("Type /help party for a list of options."), BY_SERVER); +} diff --git a/src/party.h b/src/party.h new file mode 100644 index 00000000..0f58b14b --- /dev/null +++ b/src/party.h @@ -0,0 +1,76 @@ +/* + * The Mana World + * Copyright (C) 2008 Lloyd Bryant <lloyd_bryant@netzero.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PARTY_H +#define PARTY_H + +#include <string> + +#include <guichan/actionlistener.hpp> + +class PartyHandler; +class Being; +class ChatWindow; +class Network; + +class Party +{ + public: + Party(ChatWindow *chat, Network *network); + void respond(const std::string &command, const std::string &args); + + void create(const std::string &party); + void leave(const std::string &args); + + void createResponse(bool ok); + void inviteResponse(const std::string &nick, int status); + void invitedAsk(const std::string &nick, int gender, + const std::string &partyName); + void leftResponse(const std::string &nick); + void receiveChat(Being *being, const std::string &msg); + + void help(const std::string &msg); + + private: + ChatWindow *mChat; + std::string mPartyName; + Network *mNetwork; + bool mInParty; + bool mCreating; /**< Used to give an appropriate response to + failure */ + PartyHandler *handler; + + class InviteListener : public gcn::ActionListener + { + public: + InviteListener(Network *network, bool *inParty) : + mNetwork(network), + mInParty(inParty) + {} + void action(const gcn::ActionEvent &event); + Network *mNetwork; + private: + bool *mInParty; + }; + InviteListener mInviteListener; +}; + +#endif diff --git a/src/player.cpp b/src/player.cpp index 19486d6e..09eec0d1 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1,63 +1,127 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "player.h" - #include "animatedsprite.h" #include "game.h" -#include "graphics.h" +#ifdef TMWSERV_SUPPORT #include "guild.h" -#include "log.h" +#endif +#include "player.h" +#include "text.h" +#include "resources/colordb.h" #include "resources/itemdb.h" -#include "resources/iteminfo.h" #include "utils/strprintf.h" -#include "gui/gui.h" +static const int NAME_X_OFFSET = 15; +static const int NAME_Y_OFFSET = 30; Player::Player(int id, int job, Map *map): Being(id, job, map) { + mName = NULL; } Player::~Player() { + delete mName; } -Being::Type -Player::getType() const +void Player::setName(const std::string &name) { - return PLAYER; + if (mName == NULL) + { + if (mIsGM) + { + mNameColor = 0x009000; + mName = new FlashText("(GM) " + name, mPx + NAME_X_OFFSET, mPy + + NAME_Y_OFFSET, gcn::Graphics::CENTER, + gcn::Color(0, 255, 0)); + } + else + { + mNameColor = 0x202020; + mName = new FlashText(name, mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET, + gcn::Graphics::CENTER, + gcn::Color(255, 255, 255)); + } + Being::setName(name); + } } -void Player::drawName(Graphics *graphics, int offsetX, int offsetY) +#ifdef EATHENA_SUPPORT +void Player::logic() { - const Vector &pos = getPosition(); - const int px = (int) pos.x + offsetX; - const int py = (int) pos.y + offsetY; + switch (mAction) + { + case STAND: + break; + + case SIT: + break; + + case DEAD: + break; + + case HURT: + break; + + case WALK: + mFrame = (get_elapsed_time(mWalkTime) * 6) / getWalkSpeed(); + + if (mFrame >= 6) + nextStep(); + + break; + + case ATTACK: + int frames = 4; + if (mEquippedWeapon && + mEquippedWeapon->getAttackType() == ACTION_ATTACK_BOW) + { + frames = 5; + } + + mFrame = (get_elapsed_time(mWalkTime) * frames) / mAttackSpeed; - graphics->setFont(speechFont); - graphics->setColor(gcn::Color(255, 255, 255)); - graphics->drawText(mName, px, py, gcn::Graphics::CENTER); + if (mFrame >= frames) + nextStep(); + + break; + } + + Being::logic(); +} +#endif + +Being::Type Player::getType() const +{ + return PLAYER; +} + +void Player::flash(int time) +{ + if (mName) + mName->flash(time); } void Player::setGender(Gender gender) @@ -76,22 +140,20 @@ void Player::setGender(Gender gender) for (int i = 1; i < VECTOREND_SPRITE; i++) { if (mSpriteIDs.at(i) != 0) - { setSprite(i, mSpriteIDs.at(i), mSpriteColors.at(i)); - } } } } 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); } @@ -103,6 +165,11 @@ void Player::setSprite(int slot, int id, const std::string &color) { delete mSprites[slot]; mSprites[slot] = NULL; + +#ifdef EATHENA_SUPPORT + if (slot == WEAPON_SPRITE) + mEquippedWeapon = NULL; +#endif } else { @@ -113,8 +180,9 @@ void Player::setSprite(int slot, int id, const std::string &color) { if (!color.empty()) filename += "|" + color; - equipmentSprite = - AnimatedSprite::load("graphics/sprites/" + filename); + + equipmentSprite = AnimatedSprite::load("graphics/sprites/" + + filename); } if (equipmentSprite) @@ -132,6 +200,14 @@ void Player::setSprite(int slot, int id, const std::string &color) Being::setSprite(slot, id, color); } +void Player::updateCoords() +{ + if (mName) + mName->adviseXY(mPx + NAME_X_OFFSET, mPy + NAME_Y_OFFSET); +} + +#ifdef TMWSERV_SUPPORT + Guild* Player::addGuild(short guildId, short rights) { Guild *guild = new Guild(guildId, rights); @@ -181,4 +257,4 @@ void Player::setInParty(bool value) mInParty = value; } - +#endif diff --git a/src/player.h b/src/player.h index 6880ca20..1904c6d9 100644 --- a/src/player.h +++ b/src/player.h @@ -1,32 +1,35 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_PLAYER_H -#define _TMW_PLAYER_H +#ifndef PLAYER_H +#define PLAYER_H #include "being.h" +class FlashText; class Graphics; class Map; +#ifdef TMWSERV_SUPPORT class Guild; +#endif /** * A player being. Players have their name drawn beneath them. This class also @@ -41,31 +44,45 @@ class Player : public Being */ Player(int id, int job, Map *map); - virtual ~Player(); - - virtual Type - getType() const; - - virtual void - drawName(Graphics *graphics, int offsetX, int offsetY); + ~Player(); /** - * Sets the gender for this player. + * Set up mName to be the character's name */ - void setGender(Gender); + virtual void setName(const std::string &name); + +#ifdef EATHENA_SUPPORT + virtual void logic(); +#endif + + virtual Type getType() const; + + virtual void setGender(Gender gender); /** * Sets the hair style and color for this player. + * + * Only for convenience in 0.0 client. When porting + * this to the trunk remove this function and + * call setSprite directly instead. The server should + * provide the hair ID and coloring in the same way + * it does for other equipment pieces. + * */ void setHairStyle(int style, int color); /** * Sets visible equipments for this player. */ - virtual void - setSprite(int slot, int id, const std::string &color = ""); + virtual void setSprite(int slot, int id, const std::string &color = ""); /** + * Flash the player's name + */ + void flash(int time); + +#ifdef TMWSERV_SUPPORT + /** * Adds a guild to the player. */ Guild* addGuild(short guildId, short rights); @@ -99,6 +116,7 @@ class Player : public Being * Returns whether player is in the party */ bool getInParty() const { return mInParty; } +#endif /** * Gets the way the character is blocked by other objects. @@ -113,19 +131,19 @@ class Player : public Being virtual Map::BlockType getBlockType() const { return Map::BLOCKTYPE_CHARACTER; } + virtual void updateCoords(); + +#ifdef TMWSERV_SUPPORT // Character guild information std::map<int, Guild*> mGuilds; +#endif - /** - * Triggers a visual/audio effect, such as `level up' - * - * \param effect_id ID of the effect to trigger - */ - virtual void - triggerEffect(int effectId) { internalTriggerEffect(effectId, true, true); } + FlashText *mName; +#ifdef TMWSERV_SUPPORT private: bool mInParty; +#endif }; #endif diff --git a/src/player_relations.cpp b/src/player_relations.cpp new file mode 100644 index 00000000..c82876e1 --- /dev/null +++ b/src/player_relations.cpp @@ -0,0 +1,369 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <algorithm> + +#include "being.h" +#include "beingmanager.h" +#include "configuration.h" +#include "graphics.h" +#include "player.h" +#include "player_relations.h" + +#define PLAYER_IGNORE_STRATEGY_NOP "nop" +#define PLAYER_IGNORE_STRATEGY_EMOTE0 "emote0" +#define DEFAULT_IGNORE_STRATEGY PLAYER_IGNORE_STRATEGY_EMOTE0 + +#define NAME "name" // constant for xml serialisation +#define RELATION "relation" // constant for xml serialisation + +#define IGNORE_EMOTE_TIME 100 + + +// (De)serialisation class +class PlayerConfSerialiser : public ConfigurationListManager<std::pair<std::string, PlayerRelation *>, + std::map<std::string, PlayerRelation *> *> +{ + virtual ConfigurationObject *writeConfigItem(std::pair<std::string, PlayerRelation *> value, + ConfigurationObject *cobj) + { + if (!value.second) + return NULL; + cobj->setValue(NAME, value.first); + cobj->setValue(RELATION, value.second->mRelation); + + return cobj; + } + + virtual std::map<std::string, PlayerRelation *> * + readConfigItem(ConfigurationObject *cobj, + std::map<std::string, PlayerRelation *> *container) + { + std::string name = cobj->getValue(NAME, ""); + if (name.empty()) + return container; + + if (!(*container)[name]) { + int v = (int)cobj->getValue(RELATION, PlayerRelation::NEUTRAL); + (*container)[name] = new PlayerRelation(static_cast<PlayerRelation::relation>(v)); + } + // otherwise ignore the duplicate entry + + return container; + } +}; + +static PlayerConfSerialiser player_conf_serialiser; // stateless singleton + +const unsigned int PlayerRelation::RELATION_PERMISSIONS[RELATIONS_NR] = { + /* NEUTRAL */ 0, // we always fall back to the defaults anyway + /* FRIEND */ EMOTE | SPEECH_FLOAT | SPEECH_LOG | WHISPER | TRADE, + /* DISREGARDED*/ EMOTE | SPEECH_FLOAT, + /* IGNORED */ 0 +}; + +PlayerRelation::PlayerRelation(relation relation) +{ + mRelation = relation; +} + +PlayerRelationsManager::PlayerRelationsManager() : + mPersistIgnores(false), + mDefaultPermissions(PlayerRelation::DEFAULT), + mIgnoreStrategy(NULL) +{ +} + +void PlayerRelationsManager::clear() +{ + std::vector<std::string> *names = getPlayers(); + for (std::vector<std::string>::const_iterator + it = names->begin(); it != names->end(); it++) + removePlayer(*it); + delete names; +} + +#define PERSIST_IGNORE_LIST "persist-player-list" +#define PLAYER_IGNORE_STRATEGY "player-ignore-strategy" +#define DEFAULT_PERMISSIONS "default-player-permissions" + +int PlayerRelationsManager::getPlayerIgnoreStrategyIndex(const std::string &name) +{ + std::vector<PlayerIgnoreStrategy *> *strategies = getPlayerIgnoreStrategies(); + for (unsigned int i = 0; i < strategies->size(); i++) + if ((*strategies)[i]->mShortName == name) + return i; + + return -1; +} + +void PlayerRelationsManager::load() +{ + clear(); + + mPersistIgnores = config.getValue(PERSIST_IGNORE_LIST, 0); + mDefaultPermissions = (int)config.getValue(DEFAULT_PERMISSIONS, mDefaultPermissions); + std::string ignore_strategy_name = config.getValue(PLAYER_IGNORE_STRATEGY, DEFAULT_IGNORE_STRATEGY); + int ignore_strategy_index = getPlayerIgnoreStrategyIndex(ignore_strategy_name); + if (ignore_strategy_index >= 0) + setPlayerIgnoreStrategy((*getPlayerIgnoreStrategies())[ignore_strategy_index]); + + config.getList<std::pair<std::string, PlayerRelation *>, + std::map<std::string, PlayerRelation *> *> + ("player", &(mRelations), &player_conf_serialiser); +} + + +void PlayerRelationsManager::init() +{ + load(); + + if (!mPersistIgnores) + clear(); // Yes, we still keep them around in the config file until the next update. +} + +void PlayerRelationsManager::store() +{ + config.setList<std::map<std::string, PlayerRelation *>::const_iterator, + std::pair<std::string, PlayerRelation *>, + std::map<std::string, PlayerRelation *> *> + ("player", + mRelations.begin(), mRelations.end(), + &player_conf_serialiser); + + config.setValue(DEFAULT_PERMISSIONS, mDefaultPermissions); + config.setValue(PERSIST_IGNORE_LIST, mPersistIgnores); + config.setValue(PLAYER_IGNORE_STRATEGY, + (mIgnoreStrategy)? mIgnoreStrategy->mShortName : DEFAULT_IGNORE_STRATEGY); + + config.write(); +} + +void PlayerRelationsManager::signalUpdate(const std::string &name) +{ + store(); + + for (std::list<PlayerRelationsListener *>::const_iterator it = mListeners.begin(); it != mListeners.end(); it++) + (*it)->updatedPlayer(name); +} + +unsigned int PlayerRelationsManager::checkPermissionSilently(const std::string &player_name, unsigned int flags) +{ + PlayerRelation *r = mRelations[player_name]; + if (!r) + return mDefaultPermissions & flags; + else { + unsigned int permissions = PlayerRelation::RELATION_PERMISSIONS[r->mRelation]; + + switch (r->mRelation) { + case PlayerRelation::NEUTRAL: + permissions = mDefaultPermissions; + break; + + case PlayerRelation::FRIEND: + permissions |= mDefaultPermissions; // widen + break; + + default: + permissions &= mDefaultPermissions; // narrow + } + + return permissions & flags; + } +} + +bool PlayerRelationsManager::hasPermission(Being *being, unsigned int flags) +{ + if (being->getType() == Being::PLAYER) + return hasPermission(being->getName(), flags) == flags; + return true; +} + +bool PlayerRelationsManager::hasPermission(const std::string &name, unsigned int flags) +{ + unsigned int rejections = flags & ~checkPermissionSilently(name, flags); + bool permitted = rejections == 0; + + if (!permitted) { + // execute `ignore' strategy, if possible + if (mIgnoreStrategy) { + Player *to_ignore = dynamic_cast<Player *>(beingManager->findBeingByName(name, Being::PLAYER)); + + if (to_ignore) + mIgnoreStrategy->ignore(to_ignore, + rejections); + } + } + + return permitted; +} + +void PlayerRelationsManager::setRelation(const std::string &player_name, PlayerRelation::relation relation) +{ + PlayerRelation *r = mRelations[player_name]; + if (r == NULL) + mRelations[player_name] = new PlayerRelation(relation); + else + r->mRelation = relation; + + signalUpdate(player_name); +} + +std::vector<std::string> * PlayerRelationsManager::getPlayers() +{ + std::vector<std::string> *retval = new std::vector<std::string>(); + + for (std::map<std::string, PlayerRelation *>::const_iterator it = mRelations.begin(); it != mRelations.end(); it++) + if (it->second) + retval->push_back(it->first); + + sort(retval->begin(), retval->end()); + + return retval; +} + +void PlayerRelationsManager::removePlayer(const std::string &name) +{ + if (mRelations[name]) + delete mRelations[name]; + + mRelations.erase(name); + + signalUpdate(name); +} + + +PlayerRelation::relation PlayerRelationsManager::getRelation(const std::string &name) +{ + if (mRelations[name]) + return mRelations[name]->mRelation; + + return PlayerRelation::NEUTRAL; +} + +//////////////////////////////////////// +// defaults + +unsigned int PlayerRelationsManager::getDefault() const +{ + return mDefaultPermissions; +} + +void PlayerRelationsManager::setDefault(unsigned int permissions) +{ + mDefaultPermissions = permissions; + + store(); + signalUpdate(""); +} + + +//////////////////////////////////////// +// ignore strategies + + +class PIS_nothing : public PlayerIgnoreStrategy +{ +public: + PIS_nothing() + { + mDescription = "completely ignore"; + mShortName = PLAYER_IGNORE_STRATEGY_NOP; + } + + virtual void ignore(Player *player, unsigned int flags) + { + } +}; + +class PIS_dotdotdot : public PlayerIgnoreStrategy +{ +public: + PIS_dotdotdot() + { + mDescription = "print '...'"; + mShortName = "dotdotdot"; + } + + virtual void ignore(Player *player, unsigned int flags) + { + player->setSpeech("...", 500); + } +}; + + +class PIS_blinkname : public PlayerIgnoreStrategy +{ +public: + PIS_blinkname() + { + mDescription = "blink name"; + mShortName = "blinkname"; + } + + virtual void ignore(Player *player, unsigned int flags) + { + player->flash(200); + } +}; + +class PIS_emote : public PlayerIgnoreStrategy +{ +public: + PIS_emote(int emote_nr, const std::string &description, const std::string &shortname) : + mEmotion(emote_nr) + { + mDescription = description; + mShortName = shortname; + } + + virtual void ignore(Player *player, unsigned int flags) + { + player->setEmote(mEmotion, IGNORE_EMOTE_TIME); + } +private: + int mEmotion; +}; + + + +static std::vector<PlayerIgnoreStrategy *> player_ignore_strategies; + +std::vector<PlayerIgnoreStrategy *> * +PlayerRelationsManager::getPlayerIgnoreStrategies() +{ + if (player_ignore_strategies.size() == 0) { + // not initialised yet? + player_ignore_strategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE, + "floating '...' bubble", + PLAYER_IGNORE_STRATEGY_EMOTE0)); + player_ignore_strategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE + 1, + "floating bubble", + "emote1")); + player_ignore_strategies.push_back(new PIS_nothing()); + player_ignore_strategies.push_back(new PIS_dotdotdot()); + player_ignore_strategies.push_back(new PIS_blinkname()); + } + return &player_ignore_strategies; +} + + +PlayerRelationsManager player_relations; diff --git a/src/player_relations.h b/src/player_relations.h new file mode 100644 index 00000000..1eb4ede6 --- /dev/null +++ b/src/player_relations.h @@ -0,0 +1,241 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PLAYER_RELATIONS_H +#define PLAYER_RELATIONS_H + +#include <list> +#include <map> +#include <string> +#include <vector> + +class Being; +class Player; + +struct PlayerRelation +{ + static const unsigned int EMOTE = (1 << 0); + static const unsigned int SPEECH_FLOAT = (1 << 1); + static const unsigned int SPEECH_LOG = (1 << 2); + static const unsigned int WHISPER = (1 << 3); + static const unsigned int TRADE = (1 << 4); + + static const unsigned int RELATIONS_NR = 4; + static const unsigned int RELATION_PERMISSIONS[RELATIONS_NR]; + + static const unsigned int DEFAULT = EMOTE + | SPEECH_FLOAT + | SPEECH_LOG + | WHISPER + | TRADE; + enum relation { + NEUTRAL = 0, + FRIEND = 1, + DISREGARDED = 2, + IGNORED = 3 + }; + + PlayerRelation(relation relation); + + relation mRelation; // bitmask for all of the above +}; + + +/** + * Ignore strategy: describes how we should handle ignores. + */ +class PlayerIgnoreStrategy +{ +public: + std::string mDescription; + std::string mShortName; + + virtual ~PlayerIgnoreStrategy() {} + + /** + * Handle the ignoring of the indicated action by the indicated player. + */ + virtual void ignore(Player *player, unsigned int flags) = 0; +}; + +class PlayerRelationsListener +{ +public: + PlayerRelationsListener() { } + virtual ~PlayerRelationsListener() { } + + virtual void updatedPlayer(const std::string &name) = 0; +}; + +/** + * Player relations class, represents any particular relations and/or + * preferences the user of the local client has wrt other players (identified + * by std::string). + */ +class PlayerRelationsManager +{ +public: + PlayerRelationsManager(); + + /** + * Initialise player relations manager (load config file etc.) + */ + void init(); + + /** + * Load configuration from our config file, or substitute defaults. + */ + void load(); + + /** + * Save configuration to our config file. + */ + void store(); + + /** + * Determines whether the player in question is being ignored, filtered by + * the specified flags. + */ + unsigned int checkPermissionSilently(const std::string &player_name, + unsigned int flags); + + /** + * Tests whether the player in question is being ignored for any of the + * actions in the specified flags. If so, trigger appropriate side effects + * if requested by the player. + */ + bool hasPermission(Being *being, unsigned int flags); + + bool hasPermission(const std::string &being, unsigned int flags); + + /** + * Updates the relationship with this player. + */ + void setRelation(const std::string &name, + PlayerRelation::relation relation); + + /** + * Updates the relationship with this player. + */ + PlayerRelation::relation getRelation(const std::string &name); + + /** + * Deletes the information recorded for a player. + */ + void removePlayer(const std::string &name); + + + /** + * Retrieves the default permissions. + */ + unsigned int getDefault() const; + + /** + * Sets the default permissions. + */ + void setDefault(unsigned int permissions); + + + + /** + * Retrieves all known player ignore strategies. + * + * The player ignore strategies are allocated statically and must not be + * deleted. + */ + std::vector<PlayerIgnoreStrategy *> *getPlayerIgnoreStrategies(); + + /** + * Return the current player ignore strategy. + * + * \return A player ignore strategy, or NULL + */ + PlayerIgnoreStrategy *getPlayerIgnoreStrategy() const + { + return mIgnoreStrategy; + } + + /** + * Sets the strategy to call when ignoring players. + */ + void setPlayerIgnoreStrategy(PlayerIgnoreStrategy *strategy) + { + mIgnoreStrategy = strategy; + } + + /** + * For a given ignore strategy short name, find the appropriate index in + * the ignore strategies vector. + * + * \param The short name of the ignore strategy to look up + * \return The appropriate index, or -1 + */ + int getPlayerIgnoreStrategyIndex(const std::string &shortname); + + /** + * Retrieves a sorted vector of all players for which we have any relations + * recorded. + */ + std::vector<std::string> *getPlayers(); + + /** + * Removes all recorded player info. + */ + void clear(); + + /** + * Do we persist our `ignore' setup? + */ + bool getPersistIgnores() const { return mPersistIgnores; } + + /** + * Change the `ignore persist' flag. + * + * @param value Whether to persist ignores + */ + void setPersistIgnores(bool value) { mPersistIgnores = value; } + + void addListener(PlayerRelationsListener *listener) + { + mListeners.push_back(listener); + } + + void removeListener(PlayerRelationsListener *listener) + { + mListeners.remove(listener); + } + +private: + void signalUpdate(const std::string &name); + + bool mPersistIgnores; // If NOT set, we delete the ignored data upon reloading + unsigned int mDefaultPermissions; + + PlayerIgnoreStrategy *mIgnoreStrategy; + std::map<std::string, PlayerRelation *> mRelations; + std::list<PlayerRelationsListener *> mListeners; +}; + + +extern PlayerRelationsManager player_relations; // singleton representation of player relations + + +#endif /* !defined(PLAYER_RELATIONS_H) */ diff --git a/src/position.cpp b/src/position.cpp index cc39a1af..69d50476 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/position.h b/src/position.h index 7beb3ef7..cbcf8c99 100644 --- a/src/position.h +++ b/src/position.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2008 The Mana World Development Team + * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_POSITION_H -#define TMW_POSITION_H +#ifndef POSITION_H +#define POSITION_H #include <list> #include <iostream> @@ -55,4 +55,4 @@ std::ostream& operator <<(std::ostream &os, const Position &p); */ std::ostream& operator <<(std::ostream &os, const Path &path); -#endif // TMW_POSITION_H +#endif // POSITION_H diff --git a/src/properties.h b/src/properties.h index a593e8c2..a2ce5b88 100644 --- a/src/properties.h +++ b/src/properties.h @@ -1,30 +1,30 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_PROPERTIES_H_ -#define _TMW_PROPERTIES_H_ +#ifndef PROPERTIES_H +#define PROPERTIES_H #include <map> -#include <string> #include <sstream> +#include <string> /** * A class holding a set of properties. diff --git a/src/resources/action.cpp b/src/resources/action.cpp index bbea45c9..e2cb11f2 100644 --- a/src/resources/action.cpp +++ b/src/resources/action.cpp @@ -1,31 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "action.h" - #include "animation.h" #include "../utils/dtor.h" - Action::Action() { } diff --git a/src/resources/action.h b/src/resources/action.h index 09eb066e..649d3828 100644 --- a/src/resources/action.h +++ b/src/resources/action.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ACTION_H -#define _TMW_ACTION_H +#ifndef ACTION_H +#define ACTION_H #include <map> @@ -44,11 +44,9 @@ class Action */ ~Action(); - void - setAnimation(int direction, Animation *animation); + void setAnimation(int direction, Animation *animation); - Animation* - getAnimation(int direction) const; + Animation* getAnimation(int direction) const; protected: typedef std::map<int, Animation*> Animations; diff --git a/src/resources/ambientoverlay.cpp b/src/resources/ambientoverlay.cpp index 9eee57f0..32ed47d1 100644 --- a/src/resources/ambientoverlay.cpp +++ b/src/resources/ambientoverlay.cpp @@ -1,26 +1,25 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ambientoverlay.h" - #include "image.h" #include "../graphics.h" diff --git a/src/resources/ambientoverlay.h b/src/resources/ambientoverlay.h index 56c70066..65f9891d 100644 --- a/src/resources/ambientoverlay.h +++ b/src/resources/ambientoverlay.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_RESOURCES_AMBIENTOVERLAY_H_ -#define _TMW_RESOURCES_AMBIENTOVERLAY_H_ +#ifndef RESOURCES_AMBIENTOVERLAY_H +#define RESOURCES_AMBIENTOVERLAY_H class Graphics; class Image; diff --git a/src/resources/animation.cpp b/src/resources/animation.cpp index d2794e61..54c319de 100644 --- a/src/resources/animation.cpp +++ b/src/resources/animation.cpp @@ -1,28 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "animation.h" -#include <algorithm> - #include "../utils/dtor.h" Animation::Animation(): @@ -30,22 +28,19 @@ Animation::Animation(): { } -void -Animation::addFrame(Image *image, unsigned int delay, int offsetX, int offsetY) +void Animation::addFrame(Image *image, unsigned int delay, int offsetX, int offsetY) { Frame frame = { image, delay, offsetX, offsetY }; mFrames.push_back(frame); mDuration += delay; } -void -Animation::addTerminator() +void Animation::addTerminator() { addFrame(NULL, 0, 0, 0); } -bool -Animation::isTerminator(const Frame &candidate) +bool Animation::isTerminator(const Frame &candidate) { return (candidate.image == NULL); } diff --git a/src/resources/animation.h b/src/resources/animation.h index 8dfe8614..0c461ebe 100644 --- a/src/resources/animation.h +++ b/src/resources/animation.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ANIMATION_H -#define _TMW_ANIMATION_H +#ifndef ANIMATION_H +#define ANIMATION_H #include <vector> @@ -54,39 +54,33 @@ class Animation /** * Appends a new animation at the end of the sequence. */ - void - addFrame(Image *image, unsigned int delay, int offsetX, int offsetY); + void addFrame(Image *image, unsigned int delay, int offsetX, int offsetY); /** * Appends an animation terminator that states that the animation * should not loop. */ - void - addTerminator(); + void addTerminator(); /** * Returns the frame at the specified index. */ - Frame* - getFrame(int index) { return &(mFrames[index]); } + Frame* getFrame(int index) { return &(mFrames[index]); } /** * Returns the length of this animation in frames. */ - unsigned int - getLength() const { return mFrames.size(); } + unsigned int getLength() const { return mFrames.size(); } /** * Returns the duration of this animation. */ - int - getDuration() const { return mDuration; } + int getDuration() const { return mDuration; } /** * Determines whether the given animation frame is a terminator. */ - static bool - isTerminator(const Frame &phase); + static bool isTerminator(const Frame &phase); protected: std::vector<Frame> mFrames; diff --git a/src/resources/colordb.cpp b/src/resources/colordb.cpp new file mode 100644 index 00000000..3a8754ea --- /dev/null +++ b/src/resources/colordb.cpp @@ -0,0 +1,122 @@ +/* + * Color database + * Copyright (C) 2008 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <libxml/tree.h> + +#include "colordb.h" + +#include "../log.h" + +#include "../utils/xml.h" + +#define HAIR_COLOR_FILE "colors.xml" +#define TMW_COLOR_FILE "hair.xml" + +namespace +{ + ColorDB::Colors mColors; + bool mLoaded = false; + std::string mFail = "#ffffff"; +} + +void ColorDB::load() +{ + if (mLoaded) + { + return; + } + + XML::Document *doc = new XML::Document(HAIR_COLOR_FILE); + xmlNodePtr root = doc->rootNode(); + bool TMWHair = false; + + if (!root || !xmlStrEqual(root->name, BAD_CAST "colors")) + { + logger->log("Trying TMW's color file, %s.", TMW_COLOR_FILE); + + TMWHair = true; + + delete doc; + + doc = new XML::Document(TMW_COLOR_FILE); + root = doc->rootNode(); + if (!root || !xmlStrEqual(root->name, BAD_CAST "colors")) + { + logger->log("ColorDB: Failed"); + mColors[0] = mFail; + mLoaded = true; + + delete doc; + + return; + } + } + for_each_xml_child_node(node, root) + { + if (xmlStrEqual(node->name, BAD_CAST "color")) + { + int id = XML::getProperty(node, "id", 0); + + if (mColors.find(id) != mColors.end()) + { + logger->log("ColorDB: Redefinition of dye ID %d", id); + } + + TMWHair ? mColors[id] = XML::getProperty(node, "value", "#FFFFFF") : + mColors[id] = XML::getProperty(node, "dye", "#FFFFFF"); + } + } + + delete doc; + + mLoaded = true; +} + +void ColorDB::unload() +{ + logger->log("Unloading color database..."); + + mColors.clear(); + mLoaded = false; +} + +std::string& ColorDB::get(int id) +{ + if (!mLoaded) + load(); + + ColorIterator i = mColors.find(id); + + if (i == mColors.end()) + { + logger->log("ColorDB: Error, unknown dye ID# %d", id); + return mFail; + } + else + { + return i->second; + } +} + +int ColorDB::size() +{ + return mColors.size(); +} diff --git a/src/resources/colordb.h b/src/resources/colordb.h new file mode 100644 index 00000000..c581f653 --- /dev/null +++ b/src/resources/colordb.h @@ -0,0 +1,52 @@ +/* + * Color database + * Copyright (C) 2008 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef COLOR_MANAGER_H +#define COLOR_MANAGER_H + +#include <map> +#include <string> + +/** + * The class that holds the color information. + */ +namespace ColorDB +{ + /** + * Loads the color data from <code>colors.xml</code>. + */ + void load(); + + /** + * Clear the color data + */ + void unload(); + + std::string& get(int id); + + int size(); + + // Color DB + typedef std::map<int, std::string> Colors; + typedef Colors::iterator ColorIterator; +} + +#endif diff --git a/src/resources/dye.cpp b/src/resources/dye.cpp index d180d725..22bd2411 100644 --- a/src/resources/dye.cpp +++ b/src/resources/dye.cpp @@ -1,25 +1,24 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <algorithm> #include <sstream> #include "dye.h" diff --git a/src/resources/dye.h b/src/resources/dye.h index f0bd7aab..3cef334a 100644 --- a/src/resources/dye.h +++ b/src/resources/dye.h @@ -1,27 +1,28 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_DYE_H -#define _TMW_DYE_H +#ifndef DYE_H +#define DYE_H +#include <string> #include <vector> /** @@ -36,7 +37,7 @@ class Palette * The string is either a file name or a sequence of hexadecimal RGB * values separated by ',' and starting with '#'. */ - Palette(const std::string &); + Palette(const std::string &pallete); /** * Gets a pixel color depending on its intensity. @@ -63,7 +64,7 @@ class Dye * The parts of string are separated by semi-colons. Each part starts * by an uppercase letter, followed by a colon and then a palette name. */ - Dye(const std::string &); + Dye(const std::string &dye); /** * Destroys the associated palettes. diff --git a/src/resources/emotedb.cpp b/src/resources/emotedb.cpp new file mode 100644 index 00000000..5e9a146c --- /dev/null +++ b/src/resources/emotedb.cpp @@ -0,0 +1,140 @@ +/* + * Emote database + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "emotedb.h" + +#include "../log.h" + +#include "../utils/xml.h" + +namespace +{ + EmoteInfos mEmoteInfos; + EmoteInfo mUnknown; + bool mLoaded = false; + int mLastEmote = 0; +} + +void EmoteDB::load() +{ + if (mLoaded) + return; + + mLastEmote = 0; + + EmoteSprite *unknownSprite = new EmoteSprite; + unknownSprite->sprite = "error.xml"; + unknownSprite->name = "unknown"; + unknownSprite->variant = 0; + mUnknown.sprites.push_back(unknownSprite); + + logger->log("Initializing emote database..."); + + XML::Document doc("emotes.xml"); + xmlNodePtr rootNode = doc.rootNode(); + + if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "emotes")) + { + logger->log("Emote Database: Error while loading emotes.xml!"); + return; + } + + //iterate <emote>s + for_each_xml_child_node(emoteNode, rootNode) + { + if (!xmlStrEqual(emoteNode->name, BAD_CAST "emote")) + continue; + + int id = XML::getProperty(emoteNode, "id", -1); + if (id == -1) + { + logger->log("Emote Database: Emote with missing ID in emotes.xml!"); + continue; + } + + EmoteInfo *currentInfo = new EmoteInfo; + + for_each_xml_child_node(spriteNode, emoteNode) + { + if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) + { + EmoteSprite *currentSprite = new EmoteSprite; + currentSprite->sprite = (const char*) spriteNode->xmlChildrenNode->content; + currentSprite->variant = XML::getProperty(spriteNode, "variant", 0); + currentInfo->sprites.push_back(currentSprite); + } + else if (xmlStrEqual(spriteNode->name, BAD_CAST "particlefx")) + { + std::string particlefx = (const char*) spriteNode->xmlChildrenNode->content; + currentInfo->particles.push_back(particlefx); + } + } + mEmoteInfos[id] = currentInfo; + if (id > mLastEmote) mLastEmote = id; + } + + mLoaded = true; +} + +void EmoteDB::unload() +{ + for ( EmoteInfosIterator i = mEmoteInfos.begin(); + i != mEmoteInfos.end(); + i++) + { + while (!i->second->sprites.empty()) + { + delete i->second->sprites.front(); + i->second->sprites.pop_front(); + } + delete i->second; + } + + mEmoteInfos.clear(); + + while (!mUnknown.sprites.empty()) + { + delete mUnknown.sprites.front(); + mUnknown.sprites.pop_front(); + } + + mLoaded = false; +} + +const EmoteInfo& EmoteDB::get(int id) +{ + EmoteInfosIterator i = mEmoteInfos.find(id); + + if (i == mEmoteInfos.end()) + { + logger->log("EmoteDB: Warning, unknown emote ID %d requested", id); + return mUnknown; + } + else + { + return *(i->second); + } +} + +const int& EmoteDB::getLast() +{ + return mLastEmote; +} diff --git a/src/resources/emotedb.h b/src/resources/emotedb.h new file mode 100644 index 00000000..ad21722a --- /dev/null +++ b/src/resources/emotedb.h @@ -0,0 +1,60 @@ +/* + * Emote database + * Copyright (C) 2009 Aethyra Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef EMOTE_DB_H +#define EMOTE_DB_H + +#include <list> +#include <map> +#include <string> + +struct EmoteSprite +{ + std::string sprite; + std::string name; + int variant; +}; + +struct EmoteInfo +{ + std::list<EmoteSprite*> sprites; + std::list<std::string> particles; +}; + +typedef std::map<int, EmoteInfo*> EmoteInfos; + +/** + * Emote information database. + */ +namespace EmoteDB +{ + void load(); + + void unload(); + + const EmoteInfo& get(int id); + + const int& getLast(); + + typedef EmoteInfos::iterator EmoteInfosIterator; +} + +#endif diff --git a/src/resources/image.cpp b/src/resources/image.cpp index 77d77f96..7a7e6ac8 100644 --- a/src/resources/image.cpp +++ b/src/resources/image.cpp @@ -1,29 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <SDL_image.h> -#include "image.h" - #include "dye.h" +#include "image.h" #include "../log.h" @@ -168,7 +167,8 @@ Image *Image::load(SDL_Surface *tmpImage) tmpImage = SDL_CreateRGBSurface(SDL_SWSURFACE, realWidth, realHeight, 32, rmask, gmask, bmask, amask); - if (!tmpImage) { + if (!tmpImage) + { logger->log("Error, image convert failed: out of memory"); return NULL; } @@ -179,9 +179,8 @@ Image *Image::load(SDL_Surface *tmpImage) glGenTextures(1, &texture); glBindTexture(mTextureType, texture); - if (SDL_MUSTLOCK(tmpImage)) { + if (SDL_MUSTLOCK(tmpImage)) SDL_LockSurface(tmpImage); - } glTexImage2D( mTextureType, 0, 4, @@ -256,14 +255,13 @@ Image *Image::load(SDL_Surface *tmpImage) SDL_Surface *image; // Convert the surface to the current display format - if (hasAlpha) { + if (hasAlpha) image = SDL_DisplayFormatAlpha(tmpImage); - } - else { + else image = SDL_DisplayFormat(tmpImage); - } - if (!image) { + if (!image) + { logger->log("Error: Image convert failed."); return NULL; } @@ -275,14 +273,16 @@ void Image::unload() { mLoaded = false; - if (mImage) { + if (mImage) + { // Free the image surface. SDL_FreeSurface(mImage); mImage = NULL; } #ifdef USE_OPENGL - if (mGLImage) { + if (mGLImage) + { glDeleteTextures(1, &mGLImage); mGLImage = 0; } @@ -293,10 +293,9 @@ Image *Image::getSubImage(int x, int y, int width, int height) { // Create a new clipped sub-image #ifdef USE_OPENGL - if (mUseOpenGL) { + if (mUseOpenGL) return new SubImage(this, mGLImage, x, y, width, height, mTexWidth, mTexHeight); - } #endif return new SubImage(this, mImage, x, y, width, height); @@ -304,13 +303,13 @@ Image *Image::getSubImage(int x, int y, int width, int height) void Image::setAlpha(float a) { - if (mAlpha == a) { + if (mAlpha == a) return; - } mAlpha = a; - if (mImage) { + if (mImage) + { // Set the alpha value this image is drawn at SDL_SetAlpha(mImage, SDL_SRCALPHA, (int) (255 * mAlpha)); } @@ -322,14 +321,12 @@ float Image::getAlpha() } #ifdef USE_OPENGL -void -Image::setLoadAsOpenGL(bool useOpenGL) +void Image::setLoadAsOpenGL(bool useOpenGL) { Image::mUseOpenGL = useOpenGL; } -int -Image::powerOfTwo(int input) +int Image::powerOfTwo(int input) { int value; if (mTextureType == GL_TEXTURE_2D) @@ -354,7 +351,8 @@ Image::powerOfTwo(int input) SubImage::SubImage(Image *parent, SDL_Surface *image, int x, int y, int width, int height): - Image(image), mParent(parent) + Image(image), + mParent(parent) { mParent->incRef(); @@ -369,7 +367,8 @@ SubImage::SubImage(Image *parent, SDL_Surface *image, SubImage::SubImage(Image *parent, GLuint image, int x, int y, int width, int height, int texWidth, int texHeight): - Image(image, width, height, texWidth, texHeight), mParent(parent) + Image(image, width, height, texWidth, texHeight), + mParent(parent) { mParent->incRef(); @@ -395,3 +394,4 @@ Image *SubImage::getSubImage(int x, int y, int w, int h) { return mParent->getSubImage(mBounds.x + x, mBounds.y + y, w, h); } + diff --git a/src/resources/image.h b/src/resources/image.h index 3677696f..3160add8 100644 --- a/src/resources/image.h +++ b/src/resources/image.h @@ -1,30 +1,31 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_IMAGE_H -#define _TMW_IMAGE_H +#ifndef IMAGE_H +#define IMAGE_H + +#include <SDL.h> #include "../main.h" -#include <SDL.h> #ifdef USE_OPENGL /* The definition of OpenGL extensions by SDL is giving problems with recent @@ -54,8 +55,7 @@ class Image : public Resource /** * Destructor. */ - virtual - ~Image(); + virtual ~Image(); /** * Loads an image from a buffer in memory. @@ -78,7 +78,8 @@ class Image : public Resource * @return <code>NULL</code> if an error occurred, a valid pointer * otherwise. */ - static Resource *load(void *buffer, unsigned bufferSize, Dye const &dye); + static Resource *load(void *buffer, unsigned bufferSize, + Dye const &dye); /** * Loads an image from an SDL surface. @@ -88,21 +89,19 @@ class Image : public Resource /** * Frees the resources created by SDL. */ - virtual void - unload(); + virtual void unload(); /** * Returns the width of the image. */ - virtual int - getWidth() const { return mBounds.w; } - + virtual int getWidth() const + { return mBounds.w; } /** * Returns the height of the image. */ - virtual int - getHeight() const { return mBounds.h; } + virtual int getHeight() const + { return mBounds.h; } /** * Creates a new image with the desired clipping rectangle. @@ -110,20 +109,17 @@ class Image : public Resource * @return <code>NULL</code> if creation failed and a valid * object otherwise. */ - virtual Image* - getSubImage(int x, int y, int width, int height); + virtual Image *getSubImage(int x, int y, int width, int height); /** * Sets the alpha value of this image. */ - void - setAlpha(float alpha); + virtual void setAlpha(float alpha); /** * Returns the alpha value of this image. */ - float - getAlpha(); + float getAlpha(); #ifdef USE_OPENGL /** @@ -133,7 +129,6 @@ class Image : public Resource static void setLoadAsOpenGL(bool useOpenGL); #endif - protected: /** * Constructor. @@ -145,8 +140,7 @@ class Image : public Resource /** * Returns the first power of two equal or bigger than the input. */ - static int - powerOfTwo(int input); + static int powerOfTwo(int input); #endif Image(SDL_Surface *image); @@ -192,8 +186,7 @@ class SubImage : public Image * @return <code>NULL</code> if creation failed and a valid * image otherwise. */ - Image* - getSubImage(int x, int y, int width, int height); + Image *getSubImage(int x, int y, int width, int height); private: Image *mParent; diff --git a/src/resources/imageloader.cpp b/src/resources/imageloader.cpp index 835ba100..40d62797 100644 --- a/src/resources/imageloader.cpp +++ b/src/resources/imageloader.cpp @@ -1,32 +1,31 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <cassert> -#include <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/imageloader.h b/src/resources/imageloader.h index 821a0254..1d6c9ae4 100644 --- a/src/resources/imageloader.h +++ b/src/resources/imageloader.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_IMAGELOADER_H -#define _TMW_IMAGELOADER_H +#ifndef IMAGELOADER_H +#define IMAGELOADER_H #include <string> diff --git a/src/resources/imageset.cpp b/src/resources/imageset.cpp index 1c0f9373..92bb3242 100644 --- a/src/resources/imageset.cpp +++ b/src/resources/imageset.cpp @@ -1,30 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "image.h" #include "imageset.h" #include "../log.h" -#include "image.h" - #include "../utils/dtor.h" ImageSet::ImageSet(Image *img, int width, int height) @@ -45,8 +44,7 @@ ImageSet::~ImageSet() delete_all(mImages); } -Image* -ImageSet::get(size_type i) const +Image* ImageSet::get(size_type i) const { if (i >= mImages.size()) { diff --git a/src/resources/imageset.h b/src/resources/imageset.h index 58b7a8ea..f59c76bb 100644 --- a/src/resources/imageset.h +++ b/src/resources/imageset.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_IMAGESET_H -#define _TMW_IMAGESET_H +#ifndef IMAGESET_H +#define IMAGESET_H #include <vector> @@ -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..c350ac07 100644 --- a/src/resources/imagewriter.cpp +++ b/src/resources/imagewriter.cpp @@ -1,29 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "imagewriter.h" - #include <png.h> -#include <string> #include <SDL.h> +#include <string> + +#include "imagewriter.h" #include "../log.h" diff --git a/src/resources/imagewriter.h b/src/resources/imagewriter.h index 632e2ae4..039d3afb 100644 --- a/src/resources/imagewriter.h +++ b/src/resources/imagewriter.h @@ -1,31 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <iosfwd> - struct SDL_Surface; class ImageWriter { public: static bool writePNG(SDL_Surface *surface, - const std::string &filename); + const std::string &filename); }; diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp index 5dfcfb87..7304f8a7 100644 --- a/src/resources/itemdb.cpp +++ b/src/resources/itemdb.cpp @@ -1,30 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <cassert> + #include <libxml/tree.h> #include "itemdb.h" - -#include "iteminfo.h" #include "resourcemanager.h" #include "../log.h" @@ -32,6 +31,7 @@ #include "../utils/dtor.h" #include "../utils/gettext.h" #include "../utils/strprintf.h" +#include "../utils/stringutils.h" #include "../utils/xml.h" namespace @@ -95,13 +95,13 @@ void ItemDB::load() logger->log("Initializing item database..."); - mUnknown = new ItemInfo(); - mUnknown->setName("Unknown item"); + mUnknown = new ItemInfo; + mUnknown->setName(_("Unknown item")); mUnknown->setImageName(""); mUnknown->setSprite("error.xml", GENDER_MALE); mUnknown->setSprite("error.xml", GENDER_FEMALE); - XML::Document doc("items.xml"); + XML::Document doc(_("items.xml")); xmlNodePtr rootNode = doc.rootNode(); if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "items")) @@ -126,27 +126,37 @@ void ItemDB::load() logger->log("ItemDB: Redefinition of item ID %d", id); } - int type = itemTypeFromString(XML::getProperty(node, "type", "")); + std::string typeStr = XML::getProperty(node, "type", "other"); int weight = XML::getProperty(node, "weight", 0); int view = XML::getProperty(node, "view", 0); std::string name = XML::getProperty(node, "name", ""); std::string image = XML::getProperty(node, "image", ""); std::string description = XML::getProperty(node, "description", ""); +#ifdef TMWSERV_SUPPORT int weaponType = weaponTypeFromString(XML::getProperty(node, "weapon-type", "")); +#else + int weaponType = XML::getProperty(node, "weapon_type", 0); +#endif int attackRange = XML::getProperty(node, "attack-range", 0); ItemInfo *itemInfo = new ItemInfo; itemInfo->setId(id); itemInfo->setImageName(image); - itemInfo->setName(name.empty() ? "Unnamed" : name); + itemInfo->setName(name.empty() ? _("Unnamed") : name); itemInfo->setDescription(description); +#ifdef TMWSERV_SUPPORT + int type = itemTypeFromString(typeStr); itemInfo->setType(type); +#else + itemInfo->setType(typeStr); +#endif itemInfo->setView(view); itemInfo->setWeight(weight); itemInfo->setWeaponType(weaponType); itemInfo->setAttackRange(attackRange); +#ifdef TMWSERV_SUPPORT std::string effect; for (int i = 0; i < int(sizeof(fields) / sizeof(fields[0])); ++i) { @@ -155,6 +165,9 @@ void ItemDB::load() if (!effect.empty()) effect += " / "; effect += strprintf(gettext(fields[i][1]), value); } +#else + std::string effect = XML::getProperty(node, "effect", ""); +#endif itemInfo->setEffect(effect); @@ -176,7 +189,10 @@ void ItemDB::load() NamedItemInfoIterator itr = mNamedItemInfos.find(name); if (itr == mNamedItemInfos.end()) { - mNamedItemInfos[name] = itemInfo; + std::string temp = name; + toLower(trim(temp)); + + mNamedItemInfos[temp] = itemInfo; } else { @@ -191,7 +207,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); @@ -216,7 +232,7 @@ void ItemDB::unload() const ItemInfo& ItemDB::get(int id) { - assert(mLoaded && id); + assert(mLoaded); ItemInfoIterator i = mItemInfos.find(id); @@ -257,7 +273,6 @@ void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node) { itemInfo->setSprite(filename, GENDER_MALE); } - if (gender == "female" || gender == "unisex") { itemInfo->setSprite(filename, GENDER_FEMALE); diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h index 1d814f34..68f3b039 100644 --- a/src/resources/itemdb.h +++ b/src/resources/itemdb.h @@ -1,30 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ITEM_MANAGER_H -#define _TMW_ITEM_MANAGER_H +#ifndef ITEM_MANAGER_H +#define ITEM_MANAGER_H + +#include <map> #include "iteminfo.h" -#include <map> +class ItemInfo; /** * Item information database. diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp index cc7a6afc..f7118755 100644 --- a/src/resources/iteminfo.cpp +++ b/src/resources/iteminfo.cpp @@ -1,30 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "iteminfo.h" - #include "itemdb.h" +#include "iteminfo.h" -const std::string& -ItemInfo::getSprite(Gender gender) const +const std::string& ItemInfo::getSprite(Gender gender) const { if (mView) { @@ -43,8 +41,10 @@ ItemInfo::getSprite(Gender gender) const void ItemInfo::setWeaponType(int type) { + // See server item.hpp file for type values. switch (type) { +#ifdef TMWSERV_SUPPORT case WPNTYPE_NONE: mAttackType = ACTION_DEFAULT; break; @@ -63,18 +63,35 @@ void ItemInfo::setWeaponType(int type) break; default: mAttackType = ACTION_ATTACK; +#else + case 0: // none + mAttackType = ACTION_DEFAULT; + break; + case 1: // knife + case 2: // sword + mAttackType = ACTION_ATTACK_STAB; + break; + case 8: // projectile + mAttackType = ACTION_ATTACK_THROW; + break; + case 10: // bow + mAttackType = ACTION_ATTACK_BOW; + break; + case 11: // sickle + mAttackType = ACTION_ATTACK_SWING; + break; + default: + mAttackType = ACTION_ATTACK; +#endif } } -void -ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename) +void ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename) { mSounds[event].push_back("sfx/" + filename); } - -const std::string& -ItemInfo::getSound(EquipmentSoundEvent event) const +const std::string& ItemInfo::getSound(EquipmentSoundEvent event) const { static const std::string empty; std::map< EquipmentSoundEvent, std::vector<std::string> >::const_iterator i; diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h index 1c1d8467..10749c9e 100644 --- a/src/resources/iteminfo.h +++ b/src/resources/iteminfo.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_ITEMINFO_H_ -#define _TMW_ITEMINFO_H_ +#ifndef ITEMINFO_H +#define ITEMINFO_H #include <map> #include <string> @@ -28,7 +28,7 @@ #include "spritedef.h" -#include "../player.h" +#include "../being.h" enum EquipmentSoundEvent { @@ -115,7 +115,11 @@ class ItemInfo * Constructor. */ ItemInfo(): +#ifdef TMWSERV_SUPPORT mType(ITEM_UNUSABLE), +#else + mType(""), +#endif mWeight(0), mView(0), mAttackType(ACTION_DEFAULT) @@ -149,14 +153,20 @@ class ItemInfo void setEffect(const std::string &effect) { mEffect = effect; } - const std::string& - getEffect() const { return mEffect; } + const std::string& getEffect() const { return mEffect; } +#ifdef TMWSERV_SUPPORT void setType(short type) { mType = type; } short getType() const { return mType; } +#else + void setType(const std::string& type) + { mType = type; } + + const std::string& getType() const { return mType; } +#endif void setWeight(short weight) { mWeight = weight; } @@ -192,7 +202,11 @@ class ItemInfo std::string mName; std::string mDescription; /**< Short description. */ std::string mEffect; /**< Description of effects. */ +#ifdef TMWSERV_SUPPORT char mType; /**< Item type. */ +#else + std::string mType; /**< Item type. */ +#endif short mWeight; /**< Weight in grams. */ int mView; /**< Item ID of how this item looks. */ int mId; /**< Item ID */ diff --git a/src/resources/mapreader.cpp b/src/resources/mapreader.cpp index b812b2ce..c4cb7447 100644 --- a/src/resources/mapreader.cpp +++ b/src/resources/mapreader.cpp @@ -1,39 +1,39 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "mapreader.h" - #include <cassert> #include <iostream> #include <zlib.h> -#include "resourcemanager.h" +#include "animation.h" #include "image.h" +#include "mapreader.h" +#include "resourcemanager.h" #include "../log.h" #include "../map.h" #include "../tileset.h" #include "../utils/base64.h" -#include "../utils/tostring.h" +#include "../utils/stringutils.h" #include "../utils/xml.h" const unsigned int DEFAULT_TILE_WIDTH = 32; @@ -205,14 +205,11 @@ Map *MapReader::readMap(xmlNodePtr node, const std::string &path) // Take the filename off the path const std::string pathDir = path.substr(0, path.rfind("/") + 1); - //xmlChar *prop = xmlGetProp(node, BAD_CAST "version"); - //xmlFree(prop); - const int w = XML::getProperty(node, "width", 0); const int h = XML::getProperty(node, "height", 0); - const int tw = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH); - const int th = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT); - Map *map = new Map(w, h, tw, th); + const int tilew = XML::getProperty(node, "tilewidth", DEFAULT_TILE_WIDTH); + const int tileh = XML::getProperty(node, "tileheight", DEFAULT_TILE_HEIGHT); + Map *map = new Map(w, h, tilew, tileh); for_each_xml_child_node(childNode, node) { @@ -233,6 +230,12 @@ Map *MapReader::readMap(xmlNodePtr node, const std::string &path) } else if (xmlStrEqual(childNode->name, BAD_CAST "objectgroup")) { + // 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 * tilew; + const int offsetY = tileOffsetY * tileh; + for_each_xml_child_node(objectNode, childNode) { if (xmlStrEqual(objectNode->name, BAD_CAST "object")) @@ -253,7 +256,8 @@ Map *MapReader::readMap(xmlNodePtr node, const std::string &path) const int objY = XML::getProperty(objectNode, "y", 0); logger->log("- Loading object name: %s type: %s at %d:%d", - objName.c_str(), objType.c_str(), objX, objY); + objName.c_str(), objType.c_str(), + objX, objY); if (objType == "PARTICLE_EFFECT") { @@ -262,7 +266,9 @@ Map *MapReader::readMap(xmlNodePtr node, const std::string &path) continue; } - map->addParticleEffect(objName, objX, objY); + map->addParticleEffect(objName, + objX + offsetX, + objY + offsetY); } else { @@ -297,7 +303,8 @@ void MapReader::readProperties(xmlNodePtr node, Properties *props) static void setTile(Map *map, MapLayer *layer, int x, int y, int gid) { const Tileset * const set = map->getTilesetWithGid(gid); - if (layer) { + if (layer) + { // Set regular tile on a layer Image * const img = set ? set->get(gid - set->getFirstGid()) : 0; layer->setTile(x, y, img); @@ -313,12 +320,12 @@ void MapReader::readLayer(xmlNodePtr node, Map *map) // Layers are not necessarily the same size as the map const int w = XML::getProperty(node, "width", map->getWidth()); const int h = XML::getProperty(node, "height", map->getHeight()); - const int offsetX = XML::getProperty(node, "xoffset", 0); - const int offsetY = XML::getProperty(node, "yoffset", 0); + const int offsetX = XML::getProperty(node, "x", 0); + 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; @@ -361,7 +368,7 @@ void MapReader::readLayer(xmlNodePtr node, Map *map) while (*charStart) { if (*charStart != ' ' && *charStart != '\t' && - *charStart != '\n') + *charStart != '\n') { *charIndex = *charStart; charIndex++; @@ -401,6 +408,12 @@ void MapReader::readLayer(xmlNodePtr node, Map *map) setTile(map, layer, x, y, gid); + TileAnimation* ani = map->getAnimationForGid(gid); + if (ani) + { + ani->addAffectedTile(layer, x + y * w); + } + x++; if (x == w) { x = 0; y++; @@ -446,46 +459,96 @@ Tileset *MapReader::readTileset(xmlNodePtr node, const std::string &path, Map *map) { + int firstGid = XML::getProperty(node, "firstgid", 0); + XML::Document* doc = NULL; + Tileset *set = NULL; + if (xmlHasProp(node, BAD_CAST "source")) { - logger->log("Warning: External tilesets not supported yet."); - return NULL; + std::string filename = XML::getProperty(node, "source", ""); + while (filename.substr(0, 3) == "../") + filename.erase(0, 3); // Remove "../" + doc = new XML::Document(filename); + node = doc->rootNode(); + firstGid += XML::getProperty(node, "firstgid", 0); } - const int firstGid = XML::getProperty(node, "firstgid", 0); const int tw = XML::getProperty(node, "tilewidth", map->getTileWidth()); const int th = XML::getProperty(node, "tileheight", map->getTileHeight()); for_each_xml_child_node(childNode, node) { - if (!xmlStrEqual(childNode->name, BAD_CAST "image")) - continue; + if (xmlStrEqual(childNode->name, BAD_CAST "image")) + { + const std::string source = XML::getProperty(childNode, "source", ""); - const std::string source = XML::getProperty(childNode, "source", ""); + if (!source.empty()) + { + std::string sourceStr = source; + sourceStr.erase(0, 3); // Remove "../" + + ResourceManager *resman = ResourceManager::getInstance(); + Image* tilebmp = resman->getImage(sourceStr); - if (!source.empty()) + if (tilebmp) + { + set = new Tileset(tilebmp, tw, th, firstGid); + tilebmp->decRef(); + } + else { + logger->log("Warning: Failed to load tileset (%s)", + source.c_str()); + } + } + } + else if (xmlStrEqual(childNode->name, BAD_CAST "tile")) { - std::string sourceStr = source; - sourceStr.erase(0, 3); // Remove "../" + for_each_xml_child_node(tileNode, childNode) + { + if (!xmlStrEqual(tileNode->name, BAD_CAST "properties")) continue; - ResourceManager *resman = ResourceManager::getInstance(); - Image* tilebmp = resman->getImage(sourceStr); + int tileGID = firstGid + XML::getProperty(childNode, "id", 0); - if (tilebmp) - { - Tileset *set = new Tileset(tilebmp, tw, th, firstGid); - tilebmp->decRef(); - return set; - } - else { - logger->log("Warning: Failed to load tileset (%s)", - source.c_str()); + // read tile properties to a map for simpler handling + std::map<std::string, int> tileProperties; + for_each_xml_child_node(propertyNode, tileNode) + { + if (!xmlStrEqual(propertyNode->name, BAD_CAST "property")) continue; + std::string name = XML::getProperty(propertyNode, "name", ""); + int value = XML::getProperty(propertyNode, "value", 0); + tileProperties[name] = value; + logger->log("Tile Prop of %d \"%s\" = \"%d\"", tileGID, name.c_str(), value); + } + + // create animation + if (!set) continue; + + Animation *ani = new Animation; + for (int i = 0; ;i++) + { + std::map<std::string, int>::iterator iFrame, iDelay; + iFrame = tileProperties.find("animation-frame" + toString(i)); + iDelay = tileProperties.find("animation-delay" + toString(i)); + if (iFrame != tileProperties.end() && iDelay != tileProperties.end()) + { + ani->addFrame(set->get(iFrame->second), iDelay->second, 0, 0); + } else { + break; + } + } + + if (ani->getLength() > 0) + { + map->addAnimation(tileGID, new TileAnimation(ani)); + logger->log("Animation length: %d", ani->getLength()); + } else { + delete ani; + } } } - - // Only one image element expected - break; } - return NULL; + delete doc; + + return set; } diff --git a/src/resources/mapreader.h b/src/resources/mapreader.h index 04e83b99..0ed553c3 100644 --- a/src/resources/mapreader.h +++ b/src/resources/mapreader.h @@ -1,33 +1,31 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MAPREADER_H_ -#define _TMW_MAPREADER_H_ - -#include <iosfwd> +#ifndef MAPREADER_H +#define MAPREADER_H #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 ed4acd38..cee9eea5 100644 --- a/src/resources/monsterdb.cpp +++ b/src/resources/monsterdb.cpp @@ -1,32 +1,31 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "monsterdb.h" - -#include "resourcemanager.h" -#include "spritedef.h" +#include "monsterinfo.h" #include "../log.h" #include "../utils/dtor.h" +#include "../utils/gettext.h" #include "../utils/xml.h" namespace @@ -36,18 +35,17 @@ namespace bool mLoaded = false; } -void -MonsterDB::load() +void MonsterDB::load() { if (mLoaded) return; mUnknown.addSprite("error.xml"); - mUnknown.setName("unnamed"); + mUnknown.setName(_("unnamed")); logger->log("Initializing monster database..."); - XML::Document doc("monsters.xml"); + XML::Document doc(_("monsters.xml")); xmlNodePtr rootNode = doc.rootNode(); if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "monsters")) @@ -59,11 +57,13 @@ MonsterDB::load() for_each_xml_child_node(monsterNode, rootNode) { if (!xmlStrEqual(monsterNode->name, BAD_CAST "monster")) + { continue; + } - MonsterInfo *currentInfo = new MonsterInfo(); + MonsterInfo *currentInfo = new MonsterInfo; - currentInfo->setName(XML::getProperty(monsterNode, "name", "unnamed")); + currentInfo->setName(XML::getProperty(monsterNode, "name", _("unnamed"))); std::string targetCursor; targetCursor = XML::getProperty(monsterNode, "targetCursor", "medium"); @@ -81,8 +81,8 @@ MonsterDB::load() } else { - logger->log("MonsterDB: Unknown target cursor type \"%s\" for %s " - "- using medium sized one", + logger->log("MonsterDB: Unknown target cursor type \"%s\" for %s -" + "using medium sized one", targetCursor.c_str(), currentInfo->getName().c_str()); currentInfo->setTargetCursorSize(Being::TC_MEDIUM); } @@ -92,7 +92,8 @@ MonsterDB::load() { if (xmlStrEqual(spriteNode->name, BAD_CAST "sprite")) { - currentInfo->addSprite((const char*) spriteNode->xmlChildrenNode->content); + currentInfo->addSprite( + (const char*) spriteNode->xmlChildrenNode->content); } else if (xmlStrEqual(spriteNode->name, BAD_CAST "sound")) { diff --git a/src/resources/monsterdb.h b/src/resources/monsterdb.h index f1d69e72..0a218661 100644 --- a/src/resources/monsterdb.h +++ b/src/resources/monsterdb.h @@ -1,41 +1,39 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MONSTER_DB_H -#define _TMW_MONSTER_DB_H +#ifndef MONSTER_DB_H +#define MONSTER_DB_H #include <map> -#include "monsterinfo.h" +class MonsterInfo; /** * Monster information database. */ namespace MonsterDB { - void - load(); + void load(); - void - unload(); + void unload(); const MonsterInfo& get(int id); diff --git a/src/resources/monsterinfo.cpp b/src/resources/monsterinfo.cpp index 1e982213..2fc16bef 100644 --- a/src/resources/monsterinfo.cpp +++ b/src/resources/monsterinfo.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -34,8 +34,7 @@ MonsterInfo::~MonsterInfo() mSounds.clear(); } -void -MonsterInfo::addSound(MonsterSoundEvent event, const std::string &filename) +void MonsterInfo::addSound(MonsterSoundEvent event, const std::string &filename) { if (mSounds.find(event) == mSounds.end()) { @@ -45,8 +44,7 @@ MonsterInfo::addSound(MonsterSoundEvent event, const std::string &filename) mSounds[event]->push_back("sfx/" + filename); } -const std::string & -MonsterInfo::getSound(MonsterSoundEvent event) const +const std::string &MonsterInfo::getSound(MonsterSoundEvent event) const { static std::string empty(""); std::map<MonsterSoundEvent, std::vector<std::string>* >::const_iterator i = @@ -55,8 +53,7 @@ MonsterInfo::getSound(MonsterSoundEvent event) const i->second->at(rand() % i->second->size()); } -const std::string & -MonsterInfo::getAttackParticleEffect(int attackType) const +const std::string &MonsterInfo::getAttackParticleEffect(int attackType) const { static std::string empty(""); std::map<int, MonsterAttack*>::const_iterator i = @@ -64,18 +61,16 @@ MonsterInfo::getAttackParticleEffect(int attackType) const return (i == mMonsterAttacks.end()) ? empty : (*i).second->particleEffect; } -SpriteAction -MonsterInfo::getAttackAction(int attackType) const +SpriteAction MonsterInfo::getAttackAction(int attackType) const { std::map<int, MonsterAttack*>::const_iterator i = mMonsterAttacks.find(attackType); return (i == mMonsterAttacks.end()) ? ACTION_ATTACK : (*i).second->action; } -void -MonsterInfo::addMonsterAttack(int id, - const std::string &particleEffect, - SpriteAction action) +void MonsterInfo::addMonsterAttack(int id, + const std::string &particleEffect, + SpriteAction action) { MonsterAttack *a = new MonsterAttack; a->particleEffect = particleEffect; diff --git a/src/resources/monsterinfo.h b/src/resources/monsterinfo.h index 88f6fb2b..02574147 100644 --- a/src/resources/monsterinfo.h +++ b/src/resources/monsterinfo.h @@ -1,35 +1,34 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MONSTERINFO_H_ -#define _TMW_MONSTERINFO_H_ +#ifndef MONSTERINFO_H +#define MONSTERINFO_H +#include <list> #include <map> #include <string> #include <vector> -#include <list> #include "../being.h" - enum MonsterSoundEvent { MONSTER_EVENT_HIT, @@ -63,47 +62,39 @@ class MonsterInfo */ ~MonsterInfo(); - void - setName(const std::string &name) { mName = name; } + void setName(const std::string &name) { mName = name; } - void - addSprite(const std::string &filename) + void addSprite(const std::string &filename) { mSprites.push_back(filename); } - void - setTargetCursorSize(Being::TargetCursorSize targetCursorSize) + void setTargetCursorSize(Being::TargetCursorSize targetCursorSize) { mTargetCursorSize = targetCursorSize; } - void - addSound(MonsterSoundEvent event, const std::string &filename); + void addSound(MonsterSoundEvent event, const std::string &filename); - void - addParticleEffect(const std::string &filename); + void addParticleEffect(const std::string &filename); - const std::string& - getName() const { return mName; } + const std::string& getName() const + { return mName; } - const std::list<std::string>& - getSprites() const { return mSprites; } + const std::list<std::string>& getSprites() const + { return mSprites; } - Being::TargetCursorSize - getTargetCursorSize() const { return mTargetCursorSize; } + Being::TargetCursorSize getTargetCursorSize() const + { return mTargetCursorSize; } - const std::string& - getSound(MonsterSoundEvent event) const; + const std::string &getSound(MonsterSoundEvent event) const; void addMonsterAttack(int id, const std::string &particleEffect, SpriteAction action); - const std::string& - getAttackParticleEffect(int attackType) const; + const std::string &getAttackParticleEffect(int attackType) const; - SpriteAction - getAttackAction(int attackType) const; + SpriteAction getAttackAction(int attackType) const; - const std::list<std::string>& - getParticleEffects() const { return mParticleEffects; } + const std::list<std::string>& getParticleEffects() const + { return mParticleEffects; } private: std::string mName; diff --git a/src/resources/music.cpp b/src/resources/music.cpp index 2386aa43..ed78a541 100644 --- a/src/resources/music.cpp +++ b/src/resources/music.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -55,8 +55,7 @@ Resource *Music::load(void *buffer, unsigned bufferSize) } } -bool -Music::play(int loops) +bool Music::play(int loops) { /* * Warning: loops should be always set to -1 (infinite) with current @@ -71,8 +70,7 @@ Music::play(int loops) return mChannel != -1; } -void -Music::stop() +void Music::stop() { /* * Warning: very dungerous trick, it could try to stop channels occupied diff --git a/src/resources/music.h b/src/resources/music.h index d50150b8..34907cf1 100644 --- a/src/resources/music.h +++ b/src/resources/music.h @@ -1,29 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MUSIC_H -#define _TMW_MUSIC_H +#ifndef MUSIC_H +#define MUSIC_H +#ifdef __APPLE__ +#include <SDL_mixer/SDL_mixer.h> +#else #include <SDL_mixer.h> - +#endif #include "resource.h" /** @@ -56,14 +59,12 @@ class Music : public Resource * @return <code>true</code> if the playback started properly * <code>false</code> otherwise. */ - virtual bool - play(int loops); + virtual bool play(int loops); /** * Stops the music. */ - virtual void - stop(); + virtual void stop(); protected: /** diff --git a/src/resources/npcdb.cpp b/src/resources/npcdb.cpp index 2f8d78d4..ee65136a 100644 --- a/src/resources/npcdb.cpp +++ b/src/resources/npcdb.cpp @@ -1,31 +1,29 @@ /* * The Mana World - * Copyright 2008 The Mana World Development Team + * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "npcdb.h" -#include "resourcemanager.h" - #include "../log.h" -#include "../utils/dtor.h" +#include "../utils/gettext.h" #include "../utils/xml.h" namespace @@ -52,10 +50,10 @@ void NPCDB::load() if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "npcs")) { - logger->error("NPC Database: Error while loading items.xml!"); + logger->error(_("NPC Database: Error while loading npcs.xml!")); } - //iterate <monster>s + //iterate <npc>s for_each_xml_child_node(npcNode, rootNode) { if (!xmlStrEqual(npcNode->name, BAD_CAST "npc")) @@ -91,8 +89,7 @@ void NPCDB::load() mLoaded = true; } -void -NPCDB::unload() +void NPCDB::unload() { for ( NPCInfosIterator i = mNPCInfos.begin(); i != mNPCInfos.end(); @@ -117,8 +114,7 @@ NPCDB::unload() mLoaded = false; } -const NPCInfo& -NPCDB::get(int id) +const NPCInfo& NPCDB::get(int id) { NPCInfosIterator i = mNPCInfos.find(id); diff --git a/src/resources/npcdb.h b/src/resources/npcdb.h index 00b4f99b..af6764bf 100644 --- a/src/resources/npcdb.h +++ b/src/resources/npcdb.h @@ -1,29 +1,29 @@ /* * The Mana World - * Copyright 2008 The Mana World Development Team + * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_NPC_DB_H -#define _TMW_NPC_DB_H +#ifndef NPC_DB_H +#define NPC_DB_H -#include <map> #include <list> +#include <map> #include <string> struct NPCsprite @@ -45,11 +45,9 @@ typedef std::map<int, NPCInfo*> NPCInfos; */ namespace NPCDB { - void - load(); + void load(); - void - unload(); + void unload(); const NPCInfo& get(int id); diff --git a/src/resources/resource.cpp b/src/resources/resource.cpp index 449caf55..d1c3ada4 100644 --- a/src/resources/resource.cpp +++ b/src/resources/resource.cpp @@ -1,42 +1,39 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <cassert> #include "resource.h" - #include "resourcemanager.h" Resource::~Resource() { } -void -Resource::incRef() +void Resource::incRef() { mRefCount++; } -void -Resource::decRef() +void Resource::decRef() { // Reference may not already have reached zero assert(mRefCount != 0); diff --git a/src/resources/resource.h b/src/resources/resource.h index e85e3147..7c5f989e 100644 --- a/src/resources/resource.h +++ b/src/resources/resource.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_RESOURCE_H -#define _TMW_RESOURCE_H +#ifndef RESOURCE_H +#define RESOURCE_H #include <ctime> #include <string> @@ -41,8 +41,7 @@ class Resource /** * Increments the internal reference count. */ - void - incRef(); + void incRef(); /** * Decrements the reference count and deletes the object @@ -51,8 +50,7 @@ class Resource * @return <code>true</code> if the object was deleted * <code>false</code> otherwise. */ - void - decRef(); + void decRef(); /** * Return the path identifying this resource. @@ -64,8 +62,7 @@ class Resource /** * Destructor. */ - virtual - ~Resource(); + virtual ~Resource(); private: std::string mIdPath; /**< Path identifying this resource. */ diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp index 3d42d92e..50eda0ce 100644 --- a/src/resources/resourcemanager.cpp +++ b/src/resources/resourcemanager.cpp @@ -1,43 +1,41 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <cassert> -#include <sstream> -#include <sys/time.h> - #include <physfs.h> #include <SDL_image.h> +#include <sstream> -#include "resourcemanager.h" +#include <sys/time.h> #include "dye.h" #include "image.h" +#include "imageset.h" #include "music.h" +#include "resourcemanager.h" #include "soundeffect.h" -#include "imageset.h" #include "spritedef.h" #include "../log.h" - ResourceManager *ResourceManager::instance = NULL; ResourceManager::ResourceManager() @@ -155,13 +153,13 @@ bool ResourceManager::addToSearchPath(const std::string &path, bool append) } void ResourceManager::searchAndAddArchives(const std::string &path, - const std::string &ext, - bool append) + const std::string &ext, + bool append) { const char *dirSep = PHYSFS_getDirSeparator(); char **list = PHYSFS_enumerateFiles(path.c_str()); - for (char **i = list; *i != NULL; i++) + for (char **i = list; *i; i++) { size_t len = strlen(*i); @@ -209,7 +207,7 @@ std::string ResourceManager::getPath(const std::string &file) else { // if not found in search path return the default path - path = std::string(TMW_DATADIR) + std::string("data") + "/" + file; + path = std::string(PKG_DATADIR) + std::string("data") + "/" + file; } return path; @@ -381,7 +379,7 @@ ResourceManager *ResourceManager::getInstance() { // Create a new instance if necessary. if (!instance) - instance = new ResourceManager(); + instance = new ResourceManager; return instance; } @@ -420,8 +418,7 @@ void *ResourceManager::loadFile(const std::string &fileName, int &fileSize) return buffer; } -std::vector<std::string> -ResourceManager::loadTextFile(const std::string &fileName) +std::vector<std::string> ResourceManager::loadTextFile(const std::string &fileName) { int contentsLength; char *fileContents = (char*)loadFile(fileName, contentsLength); diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h index e70dfb9d..c3c68d88 100644 --- a/src/resources/resourcemanager.h +++ b/src/resources/resourcemanager.h @@ -1,37 +1,37 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_RESOURCE_MANAGER_H -#define _TMW_RESOURCE_MANAGER_H +#ifndef RESOURCE_MANAGER_H +#define RESOURCE_MANAGER_H #include <ctime> #include <map> #include <string> #include <vector> -class Resource; class Image; +class ImageSet; class Music; +class Resource; class SoundEffect; -class ImageSet; class SpriteDef; struct SDL_Surface; @@ -100,7 +100,7 @@ class ResourceManager /** * Returns the real path to a file. Note that this method will always * return a path, it does not check whether the file exists. - * + * * @param file The file to get the real path to. * @return The real path. */ diff --git a/src/resources/soundeffect.cpp b/src/resources/soundeffect.cpp index e21fd2b0..3a285730 100644 --- a/src/resources/soundeffect.cpp +++ b/src/resources/soundeffect.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -47,8 +47,7 @@ Resource *SoundEffect::load(void *buffer, unsigned bufferSize) } } -bool -SoundEffect::play(int loops, int volume) +bool SoundEffect::play(int loops, int volume) { Mix_VolumeChunk(mChunk, volume); diff --git a/src/resources/soundeffect.h b/src/resources/soundeffect.h index c3ff6668..fc2d4a69 100644 --- a/src/resources/soundeffect.h +++ b/src/resources/soundeffect.h @@ -1,28 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SOUND_EFFECT_H -#define _TMW_SOUND_EFFECT_H +#ifndef SOUND_EFFECT_H +#define SOUND_EFFECT_H +#ifdef __APPLE__ +#include <SDL_mixer/SDL_mixer.h> +#else #include <SDL_mixer.h> +#endif #include "resource.h" @@ -35,8 +39,7 @@ class SoundEffect : public Resource /** * Destructor. */ - virtual - ~SoundEffect(); + virtual ~SoundEffect(); /** * Loads a sample from a buffer in memory. @@ -58,8 +61,7 @@ class SoundEffect : public Resource * @return <code>true</code> if the playback started properly * <code>false</code> otherwise. */ - virtual bool - play(int loops, int volume); + virtual bool play(int loops, int volume); protected: /** diff --git a/src/resources/spritedef.cpp b/src/resources/spritedef.cpp index f5b763ea..390bd3d0 100644 --- a/src/resources/spritedef.cpp +++ b/src/resources/spritedef.cpp @@ -1,34 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #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" @@ -167,7 +166,7 @@ void SpriteDef::loadAction(xmlNodePtr node, int variant_offset) actionName.c_str(), getIdPath().c_str()); return; } - Action *action = new Action(); + Action *action = new Action; mActions[actionType] = action; // When first action set it as default direction @@ -201,7 +200,7 @@ void SpriteDef::loadAnimation(xmlNodePtr animationNode, return; } - Animation *animation = new Animation(); + Animation *animation = new Animation; action->setAnimation(directionType, animation); // Get animation frames @@ -322,7 +321,7 @@ SpriteDef::~SpriteDef() SpriteAction SpriteDef::makeSpriteAction(const std::string &action) { - if (action == "" || action == "default") { + if (action.empty() || action == "default") { return ACTION_DEFAULT; } if (action == "stand") { @@ -349,6 +348,7 @@ SpriteAction SpriteDef::makeSpriteAction(const std::string &action) else if (action == "attack_throw") { return ACTION_ATTACK_THROW; } +#ifdef TMWSERV_SUPPORT else if (action == "special0") { return ACTION_SPECIAL_0; } @@ -379,6 +379,7 @@ SpriteAction SpriteDef::makeSpriteAction(const std::string &action) else if (action == "special9") { return ACTION_SPECIAL_9; } +#endif else if (action == "cast_magic") { return ACTION_CAST_MAGIC; } @@ -404,7 +405,7 @@ SpriteAction SpriteDef::makeSpriteAction(const std::string &action) SpriteDirection SpriteDef::makeSpriteDirection(const std::string& direction) { - if (direction == "" || direction == "default") { + if (direction.empty() || direction == "default") { return DIRECTION_DEFAULT; } else if (direction == "up") { diff --git a/src/resources/spritedef.h b/src/resources/spritedef.h index 0c3e443b..c3db8d64 100644 --- a/src/resources/spritedef.h +++ b/src/resources/spritedef.h @@ -1,34 +1,34 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SPRITEDEF_H -#define _TMW_SPRITEDEF_H +#ifndef SPRITEDEF_H +#define SPRITEDEF_H #include <map> #include <string> -#include "resource.h" - #include <libxml/tree.h> +#include "resource.h" + class Action; class ImageSet; @@ -43,6 +43,7 @@ enum SpriteAction ACTION_ATTACK_STAB, ACTION_ATTACK_BOW, ACTION_ATTACK_THROW, +#ifdef TMWSERV_SUPPORT ACTION_SPECIAL_0, ACTION_SPECIAL_1, ACTION_SPECIAL_2, @@ -53,6 +54,7 @@ enum SpriteAction ACTION_SPECIAL_7, ACTION_SPECIAL_8, ACTION_SPECIAL_9, +#endif ACTION_CAST_MAGIC, ACTION_USE_ITEM, ACTION_SIT, @@ -93,6 +95,12 @@ class SpriteDef : public Resource */ static SpriteAction makeSpriteAction(const std::string &action); + /** + * Converts a string into a SpriteDirection enum. + */ + static SpriteDirection + makeSpriteDirection(const std::string &direction); + private: /** * Constructor. @@ -143,13 +151,6 @@ class SpriteDef : public Resource */ void substituteAction(SpriteAction complete, SpriteAction with); - /** - * Converts a string into a SpriteDirection enum. - */ - static SpriteDirection - makeSpriteDirection(const std::string &direction); - - typedef std::map<std::string, ImageSet*> ImageSets; typedef ImageSets::iterator ImageSetIterator; diff --git a/src/serverinfo.h b/src/serverinfo.h index 4d2bb525..c38d13c7 100644 --- a/src/serverinfo.h +++ b/src/serverinfo.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SERVERINFO_ -#define _TMW_SERVERINFO_ +#ifndef SERVERINFO_ +#define SERVERINFO_ #include <string> diff --git a/src/shopitem.cpp b/src/shopitem.cpp index 9888f829..6547aaf1 100644 --- a/src/shopitem.cpp +++ b/src/shopitem.cpp @@ -1,31 +1,32 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "shopitem.h" -#include "utils/tostring.h" +#include "units.h" ShopItem::ShopItem(int id, int quantity, int price): Item(id, quantity), mPrice(price) { - mDisplayName = getInfo().getName() + " (" + toString(mPrice) + " GP)"; + mDisplayName = getInfo().getName() + + " (" + Units::formatCurrency(mPrice).c_str() + ")"; } diff --git a/src/shopitem.h b/src/shopitem.h index 05a0a67d..50af4991 100644 --- a/src/shopitem.h +++ b/src/shopitem.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _SHOPITEM_H_ -#define _SHOPITEM_H_ +#ifndef _SHOPITEM_H +#define _SHOPITEM_H #include "item.h" diff --git a/src/simpleanimation.cpp b/src/simpleanimation.cpp index e8c26df1..65d8e8e2 100644 --- a/src/simpleanimation.cpp +++ b/src/simpleanimation.cpp @@ -1,39 +1,46 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "simpleanimation.h" - #include "graphics.h" #include "log.h" +#include "simpleanimation.h" +#include "resources/animation.h" #include "resources/image.h" -#include "resources/resourcemanager.h" #include "resources/imageset.h" +#include "resources/resourcemanager.h" +SimpleAnimation::SimpleAnimation(Animation *animation): + mAnimation(animation), + mAnimationTime(0), + mAnimationPhase(0), + mCurrentFrame(mAnimation->getFrame(0)) +{ +} SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): mAnimationTime(0), mAnimationPhase(0) { - mAnimation = new Animation(); + mAnimation = new Animation; ImageSet *imageset = ResourceManager::getInstance()->getImageSet( XML::getProperty(animationNode, "imageset", ""), @@ -43,7 +50,7 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): // Get animation frames for ( xmlNodePtr frameNode = animationNode->xmlChildrenNode; - frameNode != NULL; + frameNode; frameNode = frameNode->next) { int delay = XML::getProperty(frameNode, "delay", 0); @@ -106,17 +113,34 @@ SimpleAnimation::SimpleAnimation(xmlNodePtr animationNode): mCurrentFrame = mAnimation->getFrame(0); } +bool SimpleAnimation::draw(Graphics* graphics, int posX, int posY) const +{ + if (!mCurrentFrame || !mCurrentFrame->image) + return false; + + return graphics->drawImage(mCurrentFrame->image, + posX + mCurrentFrame->offsetX, + posY + mCurrentFrame->offsetY); +} + +void SimpleAnimation::reset() +{ + mAnimationTime = 0; + mAnimationPhase = 0; +} + void SimpleAnimation::update(unsigned int timePassed) { mAnimationTime += timePassed; - while (mAnimationTime > mCurrentFrame->delay) + + while (mAnimationTime > mCurrentFrame->delay && mCurrentFrame->delay > 0) { mAnimationTime -= mCurrentFrame->delay; mAnimationPhase++; + if (mAnimationPhase >= mAnimation->getLength()) - { mAnimationPhase = 0; - } + mCurrentFrame = mAnimation->getFrame(mAnimationPhase); } } diff --git a/src/simpleanimation.h b/src/simpleanimation.h index 577268a8..e48644d4 100644 --- a/src/simpleanimation.h +++ b/src/simpleanimation.h @@ -1,33 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SIMPLEANIMAION_H -#define _TMW_SIMPLEANIMAION_H - -#include "resources/animation.h" +#ifndef SIMPLEANIMAION_H +#define SIMPLEANIMAION_H #include "utils/xml.h" +class Animation; class Frame; class Graphics; +class Image; /** * This class is a leightweight alternative to the AnimatedSprite class. @@ -39,12 +39,7 @@ class SimpleAnimation /** * Creates a simple animation with an already created animation. */ - SimpleAnimation(Animation *animation): - mAnimation(animation), - mAnimationTime(0), - mAnimationPhase(0), - mCurrentFrame(mAnimation->getFrame(0)) - {}; + SimpleAnimation(Animation *animation); /** * Creates a simple animation that creates its animation from XML Data. @@ -55,6 +50,13 @@ class SimpleAnimation void update(unsigned int timePassed); + bool draw(Graphics* graphics, int posX, int posY) const; + + /** + * Resets the animation. + */ + void reset(); + Image *getCurrentImage() const; private: diff --git a/src/sound.cpp b/src/sound.cpp index 888dcc31..6e0b0da0 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -1,29 +1,29 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "sound.h" - #include <SDL.h> #include "log.h" +#include "sound.h" + #include "resources/resourcemanager.h" #include "resources/soundeffect.h" @@ -128,7 +128,7 @@ void Sound::playMusic(const std::string &filename, int loop) { if (!mInstalled) return; - if (mMusic != NULL) { + if (mMusic) { stopMusic(); } @@ -154,7 +154,7 @@ void Sound::stopMusic() logger->log("Sound::stopMusic()"); - if (mMusic != NULL) { + if (mMusic) { Mix_HaltMusic(); Mix_FreeMusic(mMusic); mMusic = NULL; @@ -165,7 +165,7 @@ void Sound::fadeInMusic(const std::string &path, int loop, int ms) { if (!mInstalled) return; - if (mMusic != NULL) { + if (mMusic) { stopMusic(); } @@ -188,7 +188,7 @@ void Sound::fadeOutMusic(int ms) logger->log("Sound::fadeOutMusic() Fading-out (%i ms)", ms); - if (mMusic != NULL) { + if (mMusic) { Mix_FadeOutMusic(ms); Mix_FreeMusic(mMusic); mMusic = NULL; diff --git a/src/sound.h b/src/sound.h index 0c2af74b..c30ef7cd 100644 --- a/src/sound.h +++ b/src/sound.h @@ -1,28 +1,33 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SOUND_H -#define _TMW_SOUND_H +#ifndef SOUND_H +#define SOUND_H +#ifdef __APPLE__ +#include <SDL_mixer/SDL_mixer.h> +#else #include <SDL_mixer.h> +#endif +#include <string> #include <string> diff --git a/src/sprite.h b/src/sprite.h index 0e0a95db..a6384e94 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_SPRITE_H_ -#define _TMW_SPRITE_H_ +#ifndef SPRITE_H +#define SPRITE_H class Graphics; @@ -44,30 +44,26 @@ class Sprite * would support setting a translation offset. It already does this * partly with the clipping rectangle support. */ - virtual void - draw(Graphics *graphics, int offsetX, int offsetY) const = 0; + virtual void draw(Graphics *graphics, int offsetX, int offsetY) const = 0; /** * Returns the horizontal size of the sprites graphical representation * in pixels or 0 when it is undefined. */ - virtual int - getWidth() const + virtual int getWidth() const { return 0; } /** * Returns the vertical size of the sprites graphical representation * in pixels or 0 when it is undefined. */ - virtual int - getHeight() const + virtual int getHeight() const { return 0; } /** * Returns the pixel Y coordinate of the sprite. */ - virtual int - getPixelY() const = 0; + virtual int getPixelY() const = 0; }; #endif diff --git a/src/statuseffect.cpp b/src/statuseffect.cpp new file mode 100644 index 00000000..c0d689f0 --- /dev/null +++ b/src/statuseffect.cpp @@ -0,0 +1,170 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <map> + +#include "gui/chat.h" +#include "statuseffect.h" + +#include "log.h" +#include "utils/xml.h" + + +#define STATUS_EFFECTS_FILE "status-effects.xml" + +StatusEffect::StatusEffect() : + mPersistentParticleEffect(false) +{} + +StatusEffect::~StatusEffect() +{} + +void StatusEffect::playSFX() +{ + if (!mSFXEffect.empty()) + sound.playSfx(mSFXEffect); +} + +void StatusEffect::deliverMessage() +{ + if (!mMessage.empty()) + chatWindow->chatLog(mMessage, BY_SERVER); +} + +Particle *StatusEffect::getParticle() +{ + if (mParticleEffect.empty()) + return NULL; + else + return particleEngine->addEffect(mParticleEffect, 0, 0); +} + +AnimatedSprite *StatusEffect::getIcon() +{ + if (mIcon.empty()) + return NULL; + else { + AnimatedSprite *sprite = AnimatedSprite::load( + "graphics/sprites/" + mIcon); + if (false && sprite) { + sprite->play(ACTION_DEFAULT); + sprite->reset(); + } + return sprite; + } +} + +SpriteAction StatusEffect::getAction() +{ + if (mAction.empty()) + return ACTION_INVALID; + else + return SpriteDef::makeSpriteAction(mAction); +} + + +// -- initialisation and static parts -- + + +typedef std::map<int, StatusEffect *> status_effect_map[2]; + +static status_effect_map statusEffects; +static status_effect_map stunEffects; +static std::map<int, int> blockEffectIndexMap; + +int StatusEffect::blockEffectIndexToEffectIndex(int blockIndex) +{ + load(); + if (blockEffectIndexMap.find(blockIndex) == blockEffectIndexMap.end()) + return -1; + return blockEffectIndexMap[blockIndex]; +} + +StatusEffect *StatusEffect::getStatusEffect(int index, bool enabling) +{ + load(); + return statusEffects[enabling][index]; +} + +StatusEffect *StatusEffect::getStunEffect(int index, bool enabling) +{ + load(); + return stunEffects[enabling][index]; +} + +static bool status_effects_loaded = false; + + + +void StatusEffect::load() +{ + if (status_effects_loaded) + return; + + status_effects_loaded = true; + + XML::Document doc(STATUS_EFFECTS_FILE); + xmlNodePtr rootNode = doc.rootNode(); + + if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "status-effects")) + { + logger->log("Error loading status effects file: " + STATUS_EFFECTS_FILE); + return; + } + + for_each_xml_child_node(node, rootNode) + { + status_effect_map *the_map = NULL; + + int index = atoi(XML::getProperty(node, "id", "-1").c_str()); + + if (xmlStrEqual(node->name, BAD_CAST "status-effect")) + { + the_map = &statusEffects; + int block_index = atoi(XML::getProperty(node, "block-id", "-1").c_str()); + + if (index >= 0 && block_index >= 0) + blockEffectIndexMap[block_index] = index; + + } else if (xmlStrEqual(node->name, BAD_CAST "stun-effect")) + the_map = &stunEffects; + + if (the_map) { + StatusEffect *startEffect = new StatusEffect; + StatusEffect *endEffect = new StatusEffect; + + startEffect->mMessage = XML::getProperty(node, "start-message", ""); + startEffect->mSFXEffect = XML::getProperty(node, "start-audio", ""); + startEffect->mParticleEffect = XML::getProperty(node, "start-particle", ""); + startEffect->mIcon = XML::getProperty(node, "icon", ""); + startEffect->mAction = XML::getProperty(node, "action", ""); + startEffect->mPersistentParticleEffect = (XML::getProperty(node, "persistent-particle-effect", "no")) != "no"; + + endEffect->mMessage = XML::getProperty(node, "end-message", ""); + endEffect->mSFXEffect = XML::getProperty(node, "end-audio", ""); + endEffect->mParticleEffect = XML::getProperty(node, "end-particle", ""); + + (*the_map)[1][index] = startEffect; + (*the_map)[0][index] = endEffect; + } + } +} diff --git a/src/statuseffect.h b/src/statuseffect.h new file mode 100644 index 00000000..16fed69a --- /dev/null +++ b/src/statuseffect.h @@ -0,0 +1,108 @@ +/* + * The Mana World + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef STATUS_EFFECT_H +#define STATUS_EFFECT_H + +#include "resources/animation.h" +#include "particle.h" +#include "animatedsprite.h" +#include "sound.h" + +class StatusEffect +{ +public: + StatusEffect(); + ~StatusEffect(); + + /** + * Plays the sound effect associated with this status effect, if possible. + */ + void playSFX(); + + /** + * Delivers the chat message associated with this status effect, if + * possible. + */ + void deliverMessage(); + + /** + * Creates the particle effect associated with this status effect, if + * possible. + */ + Particle *getParticle(); + + /** + * Retrieves the status icon for this effect, if applicable + */ + AnimatedSprite *getIcon(); + + /** + * Retrieves an action to perform, or ACTION_INVALID + */ + SpriteAction getAction(); + + /** + * Determines whether the particle effect should be restarted when the + * being changes maps + */ + bool particleEffectIsPersistent() const { return mPersistentParticleEffect; } + + + /** + * Retrieves a status effect. + * + * \param index Index of the status effect. + * \param enabling Whether to retrieve the activating effect (true) or + * the deactivating effect (false). + */ + static StatusEffect *getStatusEffect(int index, bool enabling); + + /** + * Retrieves a stun effect. + * + * \param index Index of the stun effect. + * \param enabling Whether to retrieve the activating effect (true) or + * the deactivating effect (false). + */ + static StatusEffect *getStunEffect(int index, bool enabling); + + /** + * Maps a block effect index to its corresponding effect index. Block + * effect indices are used for opt2/opt3/status.option blocks; their + * mapping to regular effect indices is handled in the config file. + * + * Returns -1 on failure. + */ + static int blockEffectIndexToEffectIndex(int blocKIndex); + +private: + static void load(); + + std::string mMessage; + std::string mSFXEffect; + std::string mParticleEffect; + std::string mIcon; + std::string mAction; + bool mPersistentParticleEffect; +}; + +#endif // !defined(STATUS_EFFECT_H) diff --git a/src/text.cpp b/src/text.cpp new file mode 100644 index 00000000..cb4587d3 --- /dev/null +++ b/src/text.cpp @@ -0,0 +1,183 @@ +/* + * Support for non-overlapping floating text + * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net> + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "text.h" + +#include <guichan/font.hpp> + +#include "configuration.h" +#include "textmanager.h" +#include "resources/resourcemanager.h" +#include "resources/image.h" + +#include "gui/gui.h" + +int Text::mInstances = 0; +ImageRect Text::mBubble; +Image *Text::mBubbleArrow; + +Text::Text(const std::string &text, int x, int y, + gcn::Graphics::Alignment alignment, + gcn::Color color, bool isSpeech) : + mText(text), + mColor(color), + mIsSpeech(isSpeech) +{ + if (textManager == 0) + { + textManager = new TextManager; + ResourceManager *resman = ResourceManager::getInstance(); + Image *sbImage = resman->getImage("graphics/gui/bubble.png|W:#" + + config.getValue("speechBubblecolor", "000000")); + mBubble.grid[0] = sbImage->getSubImage(0, 0, 5, 5); + mBubble.grid[1] = sbImage->getSubImage(5, 0, 5, 5); + mBubble.grid[2] = sbImage->getSubImage(10, 0, 5, 5); + mBubble.grid[3] = sbImage->getSubImage(0, 5, 5, 5); + mBubble.grid[4] = sbImage->getSubImage(5, 5, 5, 5); + mBubble.grid[5] = sbImage->getSubImage(10, 5, 5, 5); + mBubble.grid[6] = sbImage->getSubImage(0, 10, 5, 5); + mBubble.grid[7] = sbImage->getSubImage(5, 10, 5, 5); + mBubble.grid[8] = sbImage->getSubImage(10, 10, 5, 5); + mBubbleArrow = sbImage->getSubImage(0, 15, 15, 10); + const float bubbleAlpha = config.getValue("speechBubbleAlpha", 1.0); + for (int i = 0; i < 9; i++) + { + mBubble.grid[i]->setAlpha(bubbleAlpha); + } + mBubbleArrow->setAlpha(bubbleAlpha); + sbImage->decRef(); + } + ++mInstances; + mHeight = boldFont->getHeight(); + mWidth = boldFont->getWidth(text); + + switch (alignment) + { + case gcn::Graphics::LEFT: + mXOffset = 0; + break; + case gcn::Graphics::CENTER: + mXOffset = mWidth / 2; + break; + case gcn::Graphics::RIGHT: + mXOffset = mWidth; + break; + } + mX = x - mXOffset; + mY = y; + textManager->addText(this); +} + +Text::~Text() +{ + textManager->removeText(this); + if (--mInstances == 0) + { + delete textManager; + textManager = 0; + delete mBubble.grid[0]; + delete mBubble.grid[1]; + delete mBubble.grid[2]; + delete mBubble.grid[3]; + delete mBubble.grid[4]; + delete mBubble.grid[5]; + delete mBubble.grid[6]; + delete mBubble.grid[7]; + delete mBubble.grid[8]; + delete mBubbleArrow; + } +} + +void Text::adviseXY(int x, int y) +{ + textManager->moveText(this, x - mXOffset, y); +} + +void Text::draw(gcn::Graphics *graphics, int xOff, int yOff) +{ + graphics->setFont(boldFont); + + if (mIsSpeech) { + static_cast<Graphics*>(graphics)->drawImageRect( + mX - xOff - 5, mY - yOff - 5, mWidth + 10, mHeight + 10, + mBubble); + /* + if (mWidth >= 15) { + static_cast<Graphics*>(graphics)->drawImage( + mBubbleArrow, mX - xOff - 7 + mWidth / 2, + mY - yOff + mHeight + 4); + } + */ + } + + // Text shadow + graphics->setColor(gcn::Color(0, 0, 0)); + graphics->drawText(mText, mX - xOff + 1, mY - yOff + 1, + gcn::Graphics::LEFT); + + if (!mIsSpeech) { + graphics->setColor(gcn::Color(0, 0, 0, 64)); + /* + // TODO: Reanable when we can draw it nicely in software mode + graphics->drawText(mText, mX - xOff + 2, mY - yOff + 2, + gcn::Graphics::LEFT); + graphics->drawText(mText, mX - xOff + 1, mY - yOff + 2, + gcn::Graphics::LEFT); + graphics->drawText(mText, mX - xOff + 2, mY - yOff + 1, + gcn::Graphics::LEFT); + */ + + // Text outline + graphics->setColor(gcn::Color(0, 0, 0)); + graphics->drawText(mText, mX - xOff + 1, mY - yOff, + gcn::Graphics::LEFT); + graphics->drawText(mText, mX - xOff - 1, mY - yOff, + gcn::Graphics::LEFT); + graphics->drawText(mText, mX - xOff, mY - yOff + 1, + gcn::Graphics::LEFT); + graphics->drawText(mText, mX - xOff, mY - yOff - 1, + gcn::Graphics::LEFT); + } + + graphics->setColor(mColor); + graphics->drawText(mText, mX - xOff, mY - yOff, gcn::Graphics::LEFT); +} + +FlashText::FlashText(const std::string &text, int x, int y, + gcn::Graphics::Alignment alignment, + gcn::Color color) : + Text(text, x, y, alignment, color), + mTime(0) +{ +} + +void FlashText::draw(gcn::Graphics *graphics, int xOff, int yOff) +{ + if (mTime) + { + if ((--mTime & 4) == 0) + { + return; + } + } + Text::draw(graphics, xOff, yOff); +} diff --git a/src/text.h b/src/text.h new file mode 100644 index 00000000..6e121da7 --- /dev/null +++ b/src/text.h @@ -0,0 +1,102 @@ +/* + * Support for non-overlapping floating text + * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net> + * Copyright (C) 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TEXT_H +#define TEXT_H + +#include <guichan/color.hpp> + +#include "graphics.h" +#include "guichanfwd.h" + +class TextManager; + +class Text +{ + friend class TextManager; + + public: + /** + * Constructor creates a text object to display on the screen. + */ + Text(const std::string &text, int x, int y, + gcn::Graphics::Alignment alignment, + gcn::Color color, bool isSpeech = false); + + /** + * Destructor. The text is removed from the screen. + */ + virtual ~Text(); + + /** + * Allows the originator of the text to specify the ideal coordinates. + */ + void adviseXY(int x, int y); + + /** + * Draws the text. + */ + virtual void draw(gcn::Graphics *graphics, int xOff, int yOff); + + private: + int mX; /**< Actual x-value of left of text written. */ + int mY; /**< Actual y-value of top of text written. */ + int mWidth; /**< The width of the text. */ + int mHeight; /**< The height of the text. */ + int mXOffset; /**< The offset of mX from the desired x. */ + static int mInstances; /**< Instances of text. */ + std::string mText; /**< The text to display. */ + gcn::Color mColor; /**< The color of the text. */ + bool mIsSpeech; /**< Is this text a speech bubble? */ + + protected: + static ImageRect mBubble; /**< Speech bubble graphic */ + static Image *mBubbleArrow; /**< Speech bubble arrow graphic */ +}; + +class FlashText : public Text +{ + public: + FlashText(const std::string &text, int x, int y, + gcn::Graphics::Alignment alignment, + gcn::Color color); + + /** + * Remove the text from the screen + */ + virtual ~FlashText() {} + + /** + * Flash the text for so many refreshes. + */ + void flash(int time) {mTime = time; } + + /** + * Draws the text. + */ + virtual void draw(gcn::Graphics *graphics, int xOff, int yOff); + + private: + int mTime; /**< Time left for flashing */ +}; + +#endif // TEXT_H diff --git a/src/textmanager.cpp b/src/textmanager.cpp new file mode 100644 index 00000000..6bc8f8b6 --- /dev/null +++ b/src/textmanager.cpp @@ -0,0 +1,169 @@ +/* + * Support for non-overlapping floating text + * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "textmanager.h" + +#include <cstring> + +#include "text.h" + +TextManager *textManager = 0; + +TextManager::TextManager() +{ +} + +void TextManager::addText(Text *text) +{ + place(text, 0, text->mX, text->mY, text->mHeight); + mTextList.push_back(text); +} + +void TextManager::moveText(Text *text, int x, int y) +{ + text->mX = x; + text->mY = y; + place(text, text, text->mX, text->mY, text->mHeight); +} + +void TextManager::removeText(const Text *text) +{ + for (TextList::iterator ptr = mTextList.begin(), + pEnd = mTextList.end(); ptr != pEnd; ++ptr) + { + if (*ptr == text) + { + mTextList.erase(ptr); + return; + } + } +} + +TextManager::~TextManager() +{ +} + +void TextManager::draw(gcn::Graphics *graphics, int xOff, int yOff) +{ + for (TextList::iterator bPtr = mTextList.begin(), ePtr = mTextList.end(); + bPtr != ePtr; ++bPtr) + { + (*bPtr)->draw(graphics, xOff, yOff); + } +} + +void TextManager::place(const Text *textObj, const Text *omit, + int &x, int &y, int h) +{ + int xLeft = textObj->mX; + int xRight = xLeft + textObj->mWidth - 1; + const int TEST = 100; // Number of lines to test for text + bool occupied[TEST]; // is some other text obscuring this line? + std::memset(&occupied, 0, sizeof(occupied)); // set all to false + int wantedTop = (TEST - h) / 2; // Entry in occupied at top of text + int occupiedTop = y - wantedTop; // Line in map representing to of occupied + + for (TextList::const_iterator ptr = mTextList.begin(), + pEnd = mTextList.end(); ptr != pEnd; ++ptr) + { + if (*ptr != omit && + (*ptr)->mX <= xRight && + (*ptr)->mX + (*ptr)->mWidth > xLeft) + { + int from = (*ptr)->mY - occupiedTop; + int to = from + (*ptr)->mHeight - 1; + if (to < 0 || from >= TEST) // out of range considered + continue; + if (from < 0) + from = 0; + if (to >= TEST) + to = TEST - 1; + for (int i = from; i <= to; ++i) + occupied[i] = true; + } + } + bool ok = true; + for (int i = wantedTop; i < wantedTop + h; ++i) + { + ok = ok && !occupied[i]; + } + + if (ok) + return; + + // Have to move it up or down, so find nearest spaces either side + int consec = 0; + int upSlot = -1; // means not found + for (int seek = wantedTop + h - 2; seek >= 0; --seek) + { + if (occupied[seek]) + { + consec = 0; + } + else + { + if (++consec == h) + { + upSlot = seek; + break; + } + } + } + int downSlot = -1; + consec = 0; + for (int seek = wantedTop + 1; seek < TEST; ++seek) + { + if (occupied[seek]) + { + consec = 0; + } + else + { + if (++consec == h) + { + downSlot = seek - h + 1; + break; + } + } + } + if (upSlot == -1 && downSlot == -1) // no good solution, so leave as is + { + return; + } + if (upSlot == -1) // must go down + { + y += downSlot - wantedTop; + return; + } + if (downSlot == -1) // must go up + { + y -= wantedTop - upSlot; + return; + } + if (wantedTop - upSlot > downSlot - wantedTop) // down is better + { + y += downSlot - wantedTop; + } + else + { + y -= wantedTop - upSlot; + } +} diff --git a/src/textmanager.h b/src/textmanager.h new file mode 100644 index 00000000..ee8e1209 --- /dev/null +++ b/src/textmanager.h @@ -0,0 +1,77 @@ +/* + * Support for non-overlapping floating text + * Copyright (C) 2008 Douglas Boffey <DougABoffey@netscape.net> + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TEXTMANAGER_H +#define TEXTMANAGER_H + +#include <list> + +#include "guichanfwd.h" + +class Text; + +class TextManager +{ + public: + /** + * Constructor + */ + TextManager(); + + /** + * Add text to the manager + */ + void addText(Text *text); + + /** + * Move the text around the screen + */ + void moveText(Text *text, int x, int y); + + /** + * Remove the text from the manager + */ + void removeText(const Text *text); + + /** + * Destroy the manager + */ + ~TextManager(); + + /** + * Draw the text + */ + void draw(gcn::Graphics *graphics, int xOff, int yOff); + + private: + /** + * Position the text so as to avoid conflict + */ + void place(const Text *textObj, const Text *omit, + int &x, int &y, int h); + + typedef std::list<Text *> TextList; /**< The container type */ + TextList mTextList; /**< The container */ +}; + +extern TextManager *textManager; + +#endif // TEXTMANAGER_H diff --git a/src/textparticle.cpp b/src/textparticle.cpp index 308c043d..f38c32ce 100644 --- a/src/textparticle.cpp +++ b/src/textparticle.cpp @@ -1,27 +1,28 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "textparticle.h" +#include <guichan/color.hpp> #include "graphics.h" +#include "textparticle.h" TextParticle::TextParticle(Map *map, const std::string &text, int colorR, int colorG, int colorB, diff --git a/src/textparticle.h b/src/textparticle.h index d56dbf84..76c247bf 100644 --- a/src/textparticle.h +++ b/src/textparticle.h @@ -1,32 +1,29 @@ /* * The Mana World - * Copyright 2006 The Mana World Development Team + * Copyright (C) 2006 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _TEXTPARTICLE_H -#define _TEXTPARTICLE_H - -#include "particle.h" - -#include <guichan/color.hpp> +#ifndef TEXTPARTICLE_H +#define TEXTPARTICLE_H #include "guichanfwd.h" +#include "particle.h" class TextParticle : public Particle { diff --git a/src/tileset.h b/src/tileset.h index fb855831..d4de7ba5 100644 --- a/src/tileset.h +++ b/src/tileset.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_TILESET_H_ -#define _TMW_TILESET_H_ +#ifndef TILESET_H +#define TILESET_H #include "resources/imageset.h" @@ -13,7 +13,7 @@ FILETYPE VFT_APP { VALUE "CompanyName", "The Mana World Development Team" VALUE "FileVersion", PACKAGE_VERSION VALUE "FileDescription", "The Mana World" - VALUE "LegalCopyright", "2004-2006 (C)" + VALUE "LegalCopyright", "2004-2009 (C)" VALUE "OriginalFilename", "tmw.exe" VALUE "ProductName", "The Mana World MMORPG" VALUE "ProductVersion", PACKAGE_VERSION diff --git a/src/units.cpp b/src/units.cpp new file mode 100644 index 00000000..4f8b95f0 --- /dev/null +++ b/src/units.cpp @@ -0,0 +1,232 @@ +/* + * Support for custom units + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "units.h" + +#include <cmath> +#include <climits> +#include <vector> + +#include "log.h" + +#include "utils/strprintf.h" +#include "utils/stringutils.h" +#include "utils/xml.h" + +struct UnitLevel { + std::string symbol; + int count; + int round; +}; + +struct UnitDescription { + std::vector<struct UnitLevel> levels; + double conversion; + bool mix; +}; + +enum UnitType { + UNIT_WEIGHT = 0, + UNIT_CURRENCY = 1, + UNIT_END +}; + +struct UnitDescription units[UNIT_END]; + +void Units::loadUnits() +{ + int level; + std::string type; + XML::Document doc("units.xml"); + xmlNodePtr root = doc.rootNode(); + + { // Setup default weight + struct UnitDescription ud; + + ud.conversion = 1.0; + ud.mix = false; + + struct UnitLevel bu; + bu.symbol = "g"; + bu.count = 1; + bu.round = 0; + + ud.levels.push_back(bu); + + struct UnitLevel ul; + ul.symbol = "kg"; + ul.count = 1000; + ul.round = 2; + + ud.levels.push_back(ul); + + units[UNIT_WEIGHT] = ud; + } + + { // Setup default currency + struct UnitDescription ud; + + ud.conversion = 1.0; + ud.mix = false; + + struct UnitLevel bu; + bu.symbol = "¤"; + bu.count = 1; + bu.round = 0; + + ud.levels.push_back(bu); + + units[UNIT_CURRENCY] = ud; + } + + if (!root || !xmlStrEqual(root->name, BAD_CAST "units")) + { + logger->log("Error loading unit definition file: units.xml"); + return; + } + + for_each_xml_child_node(node, root) + { + if (xmlStrEqual(node->name, BAD_CAST "unit")) + { + struct UnitDescription ud; + level = 1; + type = XML::getProperty(node, "type", ""); + ud.conversion = XML::getProperty(node, "conversion", 1.0); + ud.mix = XML::getProperty(node, "mix", "no") == "yes"; + + struct UnitLevel bu; + bu.symbol = XML::getProperty(node, "base", "¤"); + bu.count = 1; + bu.round = XML::getProperty(node, "round", 2); + + ud.levels.push_back(bu); + + for_each_xml_child_node(uLevel, node) + { + if (xmlStrEqual(uLevel->name, BAD_CAST "level")) + { + struct UnitLevel ul; + ul.symbol = XML::getProperty(uLevel, "symbol", + strprintf("¤%d",level)); + ul.count = XML::getProperty(uLevel, "count", -1); + ul.round = XML::getProperty(uLevel, "round", bu.round); + + if (ul.count > 0) + { + ud.levels.push_back(ul); + level++; + } + else + { + logger->log("Error bad unit count: %d for %s in %s", + ul.count, ul.symbol.c_str(), bu.symbol.c_str()); + } + } + } + + // Add one more level for saftey + struct UnitLevel ll; + ll.symbol = ""; + ll.count = INT_MAX; + ll.round = 0; + + ud.levels.push_back(ll); + + if (type == "weight") units[UNIT_WEIGHT] = ud; + else if (type =="currency") units[UNIT_CURRENCY] = ud; + else logger->log("Error unknown unit type: %s", type.c_str()); + } + } +} + +std::string formatUnit(int value, int type) +{ + struct UnitDescription ud = units[type]; + struct UnitLevel ul; + double amount = ud.conversion * value; + + // Shortcut for 0 + if (value == 0) { + ul = ud.levels[0]; + return strprintf("0%s", ul.symbol.c_str()); + } else { + // If only the first level is needed, act like mix if false + if (ud.mix && ud.levels.size() > 0 && ud.levels[1].count < amount) + { + std::string output; + struct UnitLevel pl = ud.levels[0]; + ul = ud.levels[1]; + int levelAmount = (int) amount; + int nextAmount; + + levelAmount /= ul.count; + + amount -= levelAmount * ul.count; + + if (amount > 0) { + output = strprintf("%.*f%s", pl.round, amount, + pl.symbol.c_str()); + } + + for (unsigned int i = 2; i < ud.levels.size(); i++) + { + pl = ul; + ul = ud.levels[i]; + + nextAmount = levelAmount / ul.count; + levelAmount %= ul.count; + + if (levelAmount > 0) output = strprintf("%d%s", + levelAmount, pl.symbol.c_str()) + output; + + if (!nextAmount) break; + levelAmount = nextAmount; + } + + return output; + } + else + { + for (unsigned int i = 0; i < ud.levels.size(); i++) + { + ul = ud.levels[i]; + if (amount < ul.count && ul.count > 0) { + ul = ud.levels[i - 1]; + break; + } + amount /= ul.count; + } + + return strprintf("%.*f%s", ul.round, amount, ul.symbol.c_str()); + } + } +} + +std::string Units::formatCurrency(int value) +{ + return formatUnit(value, UNIT_CURRENCY); +} + +std::string Units::formatWeight(int value) +{ + return formatUnit(value, UNIT_WEIGHT); +} diff --git a/src/units.h b/src/units.h new file mode 100644 index 00000000..6aa07b70 --- /dev/null +++ b/src/units.h @@ -0,0 +1,46 @@ +/* + * Support for custom units + * Copyright (C) 2009 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UNITS_H +#define UNITS_H + +#include <string> + +class Units +{ + public: + /** + * Loads and parses the units.xml file (if found). + */ + static void loadUnits(); + + /** + * Formats the given number in the correct currency format. + */ + static std::string formatCurrency(int value); + + /** + * Formats the given number in the correct weight/mass format. + */ + static std::string formatWeight(int value); +}; + +#endif // UNITS_H 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/base64.h b/src/utils/base64.h index c802207b..92c23016 100644 --- a/src/utils/base64.h +++ b/src/utils/base64.h @@ -27,10 +27,10 @@ +----------------------------------------------------------------------+ */ -#ifndef _TMW_BASE64_H -#define _TMW_BASE64_H +#ifndef BASE64_H +#define BASE64_H extern unsigned char *php3_base64_encode(const unsigned char *, int, int *); extern unsigned char *php3_base64_decode(const unsigned char *, int, int *); -#endif /* _TMW_BASE64_H */ +#endif /* BASE64_H */ diff --git a/src/utils/dtor.h b/src/utils/dtor.h index 9aa92c84..8dbc441f 100644 --- a/src/utils/dtor.h +++ b/src/utils/dtor.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_UTILS_DTOR_H -#define _TMW_UTILS_DTOR_H +#ifndef UTILS_DTOR_H +#define UTILS_DTOR_H #include <algorithm> #include <functional> diff --git a/src/utils/gettext.h b/src/utils/gettext.h index 0cd9114b..5281d491 100644 --- a/src/utils/gettext.h +++ b/src/utils/gettext.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_UTILS_GETTEXT_H -#define _TMW_UTILS_GETTEXT_H +#ifndef UTILS_GETTEXT_H +#define UTILS_GETTEXT_H #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/src/utils/minmax.h b/src/utils/minmax.h deleted file mode 100644 index 7e3d84f2..00000000 --- a/src/utils/minmax.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * The Mana World - * Copyright 2006 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 <cstdlib> - -/** - * Returns a random numeric value that is larger than or equal min and smaller - * than max - */ - -template <typename T> struct MinMax -{ - void set(T min, T max) - { - minVal=min; maxVal=max; - } - - void set(T val) - { - set(val, val); - } - - bool operator+= (T arg) - { - minVal += arg; - maxVal += arg; - return true; - } - - bool operator-= (T arg) - { - minVal -= arg; - maxVal -= arg; - return true; - } - - bool operator*= (T arg) - { - minVal *= arg; - maxVal *= arg; - return true; - } - - T value() - { - return (T)(minVal + (maxVal - minVal) * (rand() / ((double) RAND_MAX + 1))); - } - - T minVal; - T maxVal; -}; diff --git a/src/utils/mutex.h b/src/utils/mutex.h index 62c6b4e1..5e5df8f8 100644 --- a/src/utils/mutex.h +++ b/src/utils/mutex.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2008 The Mana World Development Team + * Copyright (C) 2008 The Mana World Development Team * * This file is part of The Mana World. * - * The Mana World is free software; you can redistribute it and/or modify + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_MUTEX_H -#define TMW_MUTEX_H +#ifndef MUTEX_H +#define MUTEX_H #include <SDL_thread.h> @@ -94,4 +94,4 @@ inline MutexLocker::~MutexLocker() mMutex->unlock(); } -#endif // TMW_MUTEX_H +#endif // MUTEX_H diff --git a/src/utils/sha256.h b/src/utils/sha256.h index 66152caf..0aa5ba1f 100644 --- a/src/utils/sha256.h +++ b/src/utils/sha256.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_UTILS_SHA256_H_ -#define _TMW_UTILS_SHA256_H_ +#ifndef UTILS_SHA256_H +#define UTILS_SHA256_H #include <string> @@ -32,4 +32,4 @@ */ std::string sha256(const std::string& string); -#endif // _TMW_UTILS_SHA256_H_ +#endif // UTILS_SHA256_H diff --git a/src/utils/trim.h b/src/utils/stringutils.cpp index a7c40ca2..04a54149 100644 --- a/src/utils/trim.h +++ b/src/utils/stringutils.cpp @@ -1,35 +1,29 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_UTILS_TRIM_H_ -#define _TMW_UTILS_TRIM_H_ +#include "stringutils.h" -#include <string> +#include <algorithm> -/** - * Trims spaces off the end and the beginning of the given string. - * - * @param str the string to trim spaces off - */ -inline void trim(std::string &str) +std::string &trim(std::string &str) { std::string::size_type pos = str.find_last_not_of(' '); if (pos != std::string::npos) @@ -46,6 +40,24 @@ inline void trim(std::string &str) // There is nothing else but whitespace in the string str.clear(); } + return str; +} + +std::string &toLower(std::string &str) +{ + std::transform(str.begin(), str.end(), str.begin(), tolower); + return str; } -#endif +const char *ipToString(int address) +{ + static char asciiIP[16]; + + sprintf(asciiIP, "%i.%i.%i.%i", + (unsigned char)(address), + (unsigned char)(address >> 8), + (unsigned char)(address >> 16), + (unsigned char)(address >> 24)); + + return asciiIP; +} diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h new file mode 100644 index 00000000..8b8b7bc2 --- /dev/null +++ b/src/utils/stringutils.h @@ -0,0 +1,68 @@ +/* + * The Mana World + * Copyright (C) 2007 The Mana World Development Team + * + * This file is part of The Mana World. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef UTILS_STRINGUTILS_H +#define UTILS_STRINGUTILS_H + +#include <string> +#include <sstream> + +/** + * Trims spaces off the end and the beginning of the given string. + * + * @param str the string to trim spaces off + * @return a reference to the trimmed string + */ +std::string &trim(std::string &str); + +/** + * Converts the given string to lower case. + * + * @param str the string to convert to lower case + * @return a reference to the given string converted to lower case + */ +std::string &toLower(std::string &str); + +/** + * Converts the given value to a string using std::stringstream. + * + * @param arg the value to convert to a string + * @return the string representation of arg + */ +template<typename T> std::string toString(const T &arg) +{ + std::stringstream ss; + ss << arg; + return ss.str(); +} + +/** + * Converts the given IP address to a string. + * + * The returned string is statically allocated, and shouldn't be freed. It is + * changed upon the next use of this method. + * + * @param address the address to convert to a string + * @return the string representation of the address + */ +const char *ipToString(int address); + +#endif // UTILS_STRINGUTILS_H diff --git a/src/utils/strprintf.cpp b/src/utils/strprintf.cpp index c5d7a595..bed4a7c4 100644 --- a/src/utils/strprintf.cpp +++ b/src/utils/strprintf.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/utils/strprintf.h b/src/utils/strprintf.h index 382ab6e0..78e7a04c 100644 --- a/src/utils/strprintf.h +++ b/src/utils/strprintf.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_UTILS_STRPRINTF_H -#define _TMW_UTILS_STRPRINTF_H +#ifndef UTILS_STRPRINTF_H +#define UTILS_STRPRINTF_H #include <string> diff --git a/src/utils/xml.cpp b/src/utils/xml.cpp index 05df9f1d..d5dd54be 100644 --- a/src/utils/xml.cpp +++ b/src/utils/xml.cpp @@ -1,26 +1,28 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #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 d0aba62e..76a63ff4 100644 --- a/src/utils/xml.h +++ b/src/utils/xml.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2004 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_XML_H -#define _TMW_XML_H +#ifndef XML_H +#define XML_H #include <libxml/tree.h> diff --git a/src/vector.cpp b/src/vector.cpp index 7d5f055a..9b573e88 100644 --- a/src/vector.cpp +++ b/src/vector.cpp @@ -1,21 +1,21 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ diff --git a/src/vector.h b/src/vector.h index f32b201a..6dd461ac 100644 --- a/src/vector.h +++ b/src/vector.h @@ -1,26 +1,26 @@ /* * The Mana World - * Copyright 2007 The Mana World Development Team + * Copyright (C) 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 + * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * - * The Mana World is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with The Mana World; if not, write to the Free Software + * 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_VECTOR_H_ -#define _TMW_VECTOR_H_ +#ifndef VECTOR_H +#define VECTOR_H #include <math.h> @@ -187,4 +187,4 @@ class Vector */ std::ostream& operator <<(std::ostream &os, const Vector &v); -#endif // _TMW_VECTOR_H_ +#endif // VECTOR_H |