diff options
author | Eugenio Favalli <elvenprogrammer@gmail.com> | 2006-07-19 15:12:06 +0000 |
---|---|---|
committer | Eugenio Favalli <elvenprogrammer@gmail.com> | 2006-07-19 15:12:06 +0000 |
commit | 4050f8c0bced625a95d542d30647c3f8bbf2267b (patch) | |
tree | 420d65a5ed6a2155762b4e13a4c90ab2df9f888e | |
parent | da3a1fd114dd7b8e5e8c880bd987506acc16ac42 (diff) | |
download | mana-4050f8c0bced625a95d542d30647c3f8bbf2267b.tar.gz mana-4050f8c0bced625a95d542d30647c3f8bbf2267b.tar.bz2 mana-4050f8c0bced625a95d542d30647c3f8bbf2267b.tar.xz mana-4050f8c0bced625a95d542d30647c3f8bbf2267b.zip |
Merged new_animation branch until r2415 into trunk.
37 files changed, 1191 insertions, 261 deletions
@@ -2,6 +2,17 @@ * tmw.cbp: Added Code::Blocks project file. +2006-07-19 Eugenio Favalli <elvenprogrammer@gmail.com> + + * data/graphics/sprites/item001.png, data/graphics/sprites/item001.xml, + data/graphics/sprites/item002.png, data/graphics/sprites/item002.xml, + data/graphics/sprites/item1202.png, data/graphics/sprites/Makefile.am, + docs/INSTALL/win32.txt, src/animation.cpp, src/being.cpp, src/being.h, + src/gui/equipmentwindow.cpp, src/gui/newskill.cpp, src/main.cpp, + src/net/beinghandler.cpp, src/net/charserverhandler.cpp, + src/player.cpp, src/player.h: Merged trunk changes r2381:2397 into + new_animation branch. + 2006-07-18 Bjørn Lindeijer <bjorn@lindeijer.nl> * src/gui/updatewindow.cpp, src/gui/updatewindow.h, src/main.cpp, @@ -10,11 +21,11 @@ specified in the downloaded resources.txt file, and in the order in which they are mentioned (the top one being the most significant). - + 2006-07-17 Frode Lindeijer <f.lindeijer@gmail.com> * Added shorts to items.png - + 2006-07-12 Bjørn Lindeijer <bjorn@lindeijer.nl> * src/gui/newskill.cpp: Fixed up a string comparison that caused a @@ -24,23 +35,204 @@ * /tmw/trunk/data/graphics/sprites/item001.png: Completed the cotton shirt equipment graphic. + +2006-07-06 Philipp Sehmisch <tmw@crushnet.org> + + * src/animation.cpp, src/animation.h, src/being.cpp, src/being.h, + src/monster.cpp, src/npc.cpp, src/player.cpp: + Fixed some minor bugs, cleaned up general code style and added more + comments. + +2006-07-05 Björn Steinbrink <B.Steinbrink@gmx.de> + + * src/monster.cpp, src/npc.cpp, src/player.cpp: Fixed broken paths. + * data/graphics/sprites/Makefile.am: Added new files. + * src/animation.cpp: Added missing return value... + * src/Makefile.am: Added new files. + +2006-07-05 Bjørn Lindeijer <bjorn@lindeijer.nl> + + * data/graphics/sprites/monster0.xml: Fixed frame size of maggot. + * src/being.h: drawName should be virtual, lest we want names to be + drawn. + +2006-07-03 Philipp Sehmisch <tmw@crushnet.org> + + * src/spriteset.cpp, src/spriteset.h: Spriteset::get() doesn't crash + anymore when requesting a sprite outside of the spriteset. (it returns + NULL instead and logs a warning). + +2006-07-03 Philipp Sehmisch <tmw@crushnet.org> + + * src/being.cpp: Fixed a compiler issue reported by Pajarico. 2006-07-03 Bjørn Lindeijer <bjorn@lindeijer.nl> * tools/Reorganize.java: Added tool used for reorganizing and auto-cropping the monster spritesets. + +2006-07-03 Philipp Sehmisch <tmw@crushnet.org> + + * src/main.cpp, src/engine.cpp: Removed some no longer required old + style spritesets. + * src/being.h, src/being.cpp: Removed some no longer needed member + variables. + * src/monster.cpp: Monsters are now drawed with the new animation + system. + * src/npc.cpp, data/graphics/sprites/npcs.xml: NPCs are now drawed + with the new animation system. + * src/being.h, src/being.cpp, src/npc.cpp, src/npc.h, src/monster.cpp, + src/monster.h: Moved all drawing code from the Being based classes + into Being. + * data/graphics/sprites/monster0.png, + data/graphics/sprites/monster1.png, + data/graphics/sprites/monster2.png, + data/graphics/sprites/monster3.png, + data/graphics/sprites/monster4.png, + data/graphics/sprites/monster5.png, + data/graphics/sprites/monster6.png, + data/graphics/sprites/monster7.png, + data/graphics/sprites/monster8.png, + data/graphics/sprites/monster9.png, + data/graphics/sprites/monster10.png, + data/graphics/sprites/monster11.png, + data/graphics/sprites/monster12.png, + data/graphics/sprites/monster13.png, + data/graphics/sprites/monster14.png, + data/graphics/sprites/monster15.png, + data/graphics/sprites/monster16.png, + data/graphics/sprites/monster17.png: Resized and reorganized the + monster spritesets to fit the new animation system (thanks, Bjørn). + * data/graphics/sprites/monster0.xml, + data/graphics/sprites/monster1.xml, + data/graphics/sprites/monster2.xml, + data/graphics/sprites/monster3.xml, + data/graphics/sprites/monster4.xml, + data/graphics/sprites/monster5.xml, + data/graphics/sprites/monster6.xml, + data/graphics/sprites/monster7.xml, + data/graphics/sprites/monster8.xml, + data/graphics/sprites/monster9.xml, + data/graphics/sprites/monster10.xml, + data/graphics/sprites/monster11.xml, + data/graphics/sprites/monster12.xml, + data/graphics/sprites/monster13.xml, + data/graphics/sprites/monster14.xml, + data/graphics/sprites/monster15.xml, + data/graphics/sprites/monster16.xml, + data/graphics/sprites/monster17.xml: Added animation files for all + monsters. + * src/animation.cpp: The offset values of the Frames of animated + sprites are now modified so every frame is drawn centered. + * data/graphics/sprites/hairstyle0.xml, + data/graphics/sprites/hairstyle1.xml, + data/graphics/sprites/hairstyle2.xml, + data/graphics/sprites/hairstyle3.xml, + data/graphics/sprites/hairstyle4.xml, + data/graphics/sprites/hairstyle5.xml, + data/graphics/sprites/hairstyle6.xml, + data/graphics/sprites/hairstyle7.xml: Retuned the offsets of the hair + sprites. + * src/animation.cpp: Small stability fix. + * src/being.cpp, src/being.h: weapon animation now uses the new + animation system. + * data/graphics/sprites/player_male_base.xml + data/graphics/sprites/player_female_base.xml + data/graphics/sprites/hairstyle0.xml, + data/graphics/sprites/hairstyle1.xml, + data/graphics/sprites/hairstyle2.xml, + data/graphics/sprites/hairstyle3.xml, + data/graphics/sprites/hairstyle4.xml, + data/graphics/sprites/hairstyle5.xml, + data/graphics/sprites/hairstyle6.xml, + data/graphics/sprites/hairstyle7.xml: Tuned walk speed and added bow + animations. + +2006-07-03 Eugenio Favalli <elvenprogrammer@gmail.com> + + * src/being.cpp: Removed an unnecessary parameter. + +2006-07-03 Bjørn Lindeijer <bjorn@lindeijer.nl> + + * data/graphics/sprites/Makefile.am: Updated to new xml files. + +2006-07-02 Philipp Sehmisch <tmw@crushnet.org> + + * src/localplayer.cpp: Fixed the "walking against walls" bug. + * src/animation.cpp src/animation.h: fixed the "sliding" bug and + removed some unused variables. + +2006-07-01 Philipp Sehmisch <tmw@crushnet.org> + + * src/being.cpp, src/being.h, src/player.cpp, src/player.h, + src/localplayer.cpp: Sprites are now stored in a vector instead of a + list, so they can be replaced a lot easier; added female playerset; + added hairstyles and colors. + * src/animation.cpp, src/animation.h: added support for variations, + variations are animations stored in the same spriteset with the same + layout and sequence but starting at another index. + * data/graphics/sprites/player_female_base.xml: Added xml file for + female characters. + * data/graphics/sprites/hairstyle0.xml, + data/graphics/sprites/hairstyle1.xml, + data/graphics/sprites/hairstyle2.xml, + data/graphics/sprites/hairstyle3.xml, + data/graphics/sprites/hairstyle4.xml, + data/graphics/sprites/hairstyle5.xml, + data/graphics/sprites/hairstyle6.xml, + data/graphics/sprites/hairstyle7.xml: Added xml files for all + hairstyles (these xml files are using the new variation feature). + * src/being.cpp, src/being.h, src/localplayer.cpp, src/player.cpp: The + beings now haven't got one, but a list of animated sprites (named + mSprites). At the moment it contains the hair and the base sprite. + * src/animation.cpp, src/animation,h: Fixed a crash when substituting + an undefined direction; renamed completeDirections method to + substituteAction. + * data/graphics/sprites/hairstyle0.xml: Made a xml file for the hair + animation. 2006-06-29 Eugenio Favalli <elvenprogrammer@gmail.com> * data/items.xml, src/being.cpp, src/being.h src/net/beinghandler.cpp, src/player.cpp: Clients get notified of equipping visible items. * src/net/beinghandler.cpp: GCC 4 fix. + +2006-06-28 Philipp Sehmisch <tmw@crushnet.org> + + * src/animation.cpp, src/animation.h: Parser now works like described + on the wiki; the single animation phases are now stored in structures; + drawing call for animatiedSprites moved into the animatiedSprite + class. + * src/being.cpp, src/being.h, src/localplayer.cpp, src/player.cpp: + Renamed mAnimatedSprite to mBaseSprite to distinct it from hair-equip + and other sprites that will also be part of the class. + * src/player.cpp: Drawing call for animatiedSprites moved into the + animatiedSprite class; time now correctly passed in ms to the + animatedSprite class. + * src/graphic/spriteset.cpp, src/graphic/spriteset.h: Width and height + of the subimages is now saved in the spritesheet class. + * src/graphics.cpp: Added an additional check to avoid crashes when + passing a NULL pointer as image argument. + * data/graphics/sprites/player_male_base.xml: Animation file now has + the syntax described on the wiki. + +2006-06-27 Frode Lindeijer <f.lindeijer@gmail.com> + + * /tmw/trunk/data/graphics/sprites/player_male_base.png: + Fixed transparency issue with the north punching frames 2006-06-27 Eugenio Favalli <elvenprogrammer@gmail.com> - * src/being.cpp, src/gui/equipmentwindow.cpp, src/player.cpp: Equipment - window now show all the slots, and adapted visible shirts to head - (middle) equipments. + * data/graphics/sprites/Makefile.am, + data/graphics/sprites/player_male_base.xml, src/being.cpp, + src/being.h, src/engine.cpp, src/localplayer.cpp, src/main.cpp, + src/net/beinghandler.cpp, src/net/playerhandler.cpp, + src/resources/itemmanager.cpp, The Mana World.dev: Added a beginning + of a new animation system to slow down player walking. + * src/animation.cpp, src/animation.h: Forgot 2 files. + * src/being.cpp, src/gui/equipmentwindow.cpp, src/player.cpp: + Equipment window now show all the slots, and adapted visible shirts to + head (middle) equipments. 2006-06-27 Frode Lindeijer <f.lindeijer@gmail.com> @@ -129,9 +321,9 @@ 2006-05-03 Eugenio Favalli <elvenprogrammer@gmail.com> * configure.ac, src/game.cpp, src/graphics.cpp, src/main.cpp, - src/openglgraphics.cpp, The Mana World: Increased fps limit granularity - and cleaned some code, fixed some xml library name in Dev-C++ project - file, switched version to 0.0.20. + src/openglgraphics.cpp, The Mana World: Increased fps limit + granularity and cleaned some code, fixed some xml library name in + Dev-C++ project file, switched version to 0.0.20. * src/game.cpp, src/gui/setup.cpp, src/gui/setup_video.cpp, src/gui/setup_video.h, src/main.cpp: FPS limit can now be set in setup dialog. Default value for FPS is 50. (Code based on peoro's patch). @@ -232,8 +424,8 @@ 2006-03-13 Philipp Sehmisch <tmw@crushnet.org> - * data/maps/new_7.1.tmx.gz: Fixed some map bugs (update of server sided - walkmap required!) + * data/maps/new_7.1.tmx.gz: Fixed some map bugs (update of server + sided walkmap required!) 2006-03-11 Eugenio Favalli <elvenprogrammer@gmail.com> diff --git a/The Mana World.dev b/The Mana World.dev index deb5ded3..b929434a 100644 --- a/The Mana World.dev +++ b/The Mana World.dev @@ -1,7 +1,7 @@ [Project] FileName=The Mana World.dev Name=tmw -UnitCount=225 +UnitCount=229 Type=0 Ver=1 ObjFiles= @@ -20,7 +20,7 @@ ObjectOutput=obj OverrideOutput=1 OverrideOutputName=tmw.exe HostApplication= -Folders=graphic,graphic/header,graphic/source,gui,gui/header,gui/source,header,net,net/header,net/source,resources +Folders=graphic,graphic/header,graphic/source,gui,gui/header,gui/source,header,net,net/header,net/source,resources,utils CommandLine= UseCustomMakefile=0 CustomMakefile= @@ -2307,3 +2307,43 @@ Priority=1000 OverrideBuildCmd=0 BuildCmd= +[Unit226] +FileName=src\animation.h +CompileCpp=1 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit227] +FileName=src\animation.cpp +CompileCpp=1 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit228] +FileName=src\utils\dtor.h +CompileCpp=1 +Folder=utils +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit229] +FileName=src\utils\tostring.h +CompileCpp=1 +Folder=utils +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/src/Makefile.am b/src/Makefile.am index e4fef745..c6db2ec6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -181,6 +181,8 @@ tmw_SOURCES = graphic/spriteset.cpp \ resources/buddylist.cpp \ utils/dtor.h \ utils/tostring.h \ + animation.cpp \ + animation.h \ base64.cpp \ base64.h \ being.cpp \ diff --git a/src/animation.cpp b/src/animation.cpp new file mode 100644 index 00000000..57fb931a --- /dev/null +++ b/src/animation.cpp @@ -0,0 +1,389 @@ +/* + * 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 + * + * $Id$ + */ + +#include "animation.h" + +#include <libxml/tree.h> + +#include "log.h" + +#include "graphic/spriteset.h" + +#include "resources/image.h" +#include "resources/resourcemanager.h" + +#define READ_PROP(node, prop, name, target, cast) \ + prop = xmlGetProp(node, BAD_CAST name); \ + if (prop) { \ + target = cast((const char*)prop); \ + xmlFree(prop); \ + } + +Animation::Animation(): + mTime(0) +{ + iCurrentPhase = mAnimationPhases.begin(); +} + +void +Animation::update(unsigned int time) +{ + mTime += time; + if (!mAnimationPhases.empty()) + { + while ((mTime > (*iCurrentPhase).delay) && + (*iCurrentPhase).delay > 0) + { + mTime -= (*iCurrentPhase).delay; + iCurrentPhase++; + if (iCurrentPhase == mAnimationPhases.end()) + { + iCurrentPhase = mAnimationPhases.begin(); + } + } + } +} + +int +Animation::getCurrentPhase() +{ + if (mAnimationPhases.empty()) + { + return -1; + } + else + { + return (*iCurrentPhase).image; + } +} + +void +Animation::addPhase (int image, unsigned int delay, int offsetX, int offsetY) +{ + //add new phase to animation list + AnimationPhase newPhase; + newPhase.image = image; + newPhase.delay = delay; + newPhase.offsetX = offsetX; + newPhase.offsetY = offsetY; + mAnimationPhases.push_back(newPhase); + //reset animation circle + iCurrentPhase = mAnimationPhases.begin(); +} + +Action::Action() + :mImageset("") +{ + //NOOP +} + +Action::~Action() +{ + for (AnimationIterator i = mAnimations.begin(); i != mAnimations.end(); i++) + { + delete i->second; + } + mAnimations.clear(); +} + +Animation * +Action::getAnimation(std::string direction) +{ + Animation *animation = NULL; + AnimationIterator i = mAnimations.find(direction); + if (i == mAnimations.end()) + { + //when the direction isn't defined just use another one + animation = mAnimations["default"]; + } + else + { + animation = mAnimations[direction]; + } + + return animation; +} + +void +Action::setAnimation(std::string direction, Animation *animation) +{ + //set first direction as default direction + if (mAnimations.empty()) + { + mAnimations["default"] = animation; + } + + mAnimations[direction] = animation; +} + + +AnimatedSprite::AnimatedSprite(std::string animationFile, int variant): + mAction("stand"), mDirection("down"), mLastTime(0) +{ + int variant_num = 0; + int variant_offset = 0; + int size; + ResourceManager *resman = ResourceManager::getInstance(); + char *data = (char*)resman->loadFile( + animationFile.c_str(), size); + + if (!data) { + logger->error("Animation: Could not find " + animationFile + " !"); + } + + xmlDocPtr doc = xmlParseMemory(data, size); + free(data); + + if (!doc) + { + logger->error("Animation: Error while parsing animation definition file!"); + return; + } + + xmlNodePtr node = xmlDocGetRootElement(doc); + if (!node || !xmlStrEqual(node->name, BAD_CAST "sprite")) + { + logger->error("Animation: this is not a valid animation definition file!"); + return; + } + + //get the variant + xmlChar *prop = NULL; + READ_PROP(node, prop, "variants", variant_num, atoi); + READ_PROP(node, prop, "variant_offset", variant_offset, atoi); + + if (variant_num > 0 && variant < variant_num ) + { + variant_offset *= variant; + } + else + { + variant_offset = 0; + } + + for (node = node->xmlChildrenNode; node != NULL; node = node->next) + { + if (xmlStrEqual(node->name, BAD_CAST "imageset")) + { + int width = 0, height = 0; + std::string name = "", imageSrc = ""; + xmlChar *prop = NULL; + READ_PROP(node, prop, "name", name, ); + READ_PROP(node, prop, "src", imageSrc, ); + READ_PROP(node, prop, "width", width, atoi); + READ_PROP(node, prop, "height", height, atoi); + + Spriteset *spriteset = resman->createSpriteset( + imageSrc, width, height); + if (!spriteset) + { + logger->error("Couldn't load spriteset!"); + } + else + { + mSpritesets[name] = spriteset; + } + } + // get action + else if (xmlStrEqual(node->name, BAD_CAST "action")) + { + std::string name = "", imageset = ""; + xmlChar *prop = NULL; + READ_PROP(node, prop, "name", name, ); + READ_PROP(node, prop, "imageset", imageset, ); + + Action *action = new Action(); + mActions[name] = action; + action->setImageset(imageset); + + //get animations + for ( xmlNodePtr animationNode = node->xmlChildrenNode; + animationNode != NULL; + animationNode = animationNode->next) + { + if (xmlStrEqual(animationNode->name, BAD_CAST "animation")) + { + std::string direction = ""; + + + Animation *animation = new Animation(); + READ_PROP(animationNode, prop, "direction", direction, ); + + //get animation phases + for ( xmlNodePtr phaseNode = animationNode->xmlChildrenNode; + phaseNode != NULL; + phaseNode = phaseNode->next) + { + int index = -1; + int start = 0; + int end = 0; + int delay = 0; + int offsetX = 0; + int offsetY = 0; + if (xmlStrEqual(phaseNode->name, BAD_CAST "frame")) + { + READ_PROP(phaseNode, prop, "index", index, atoi); + READ_PROP(phaseNode, prop, "delay", delay, atoi); + READ_PROP(phaseNode, prop, "offsetX", offsetX, atoi); + READ_PROP(phaseNode, prop, "offsetY", offsetY, atoi); + offsetY = offsetY - mSpritesets[imageset]->getHeight() + 32; + offsetX = offsetX - mSpritesets[imageset]->getWidth() / 2 + 16; + animation->addPhase(index + variant_offset, delay, offsetX, offsetY); + } + if (xmlStrEqual(phaseNode->name, BAD_CAST "sequence")) + { + READ_PROP(phaseNode, prop, "start", start, atoi); + READ_PROP(phaseNode, prop, "end", end, atoi); + READ_PROP(phaseNode, prop, "delay", delay, atoi); + offsetY = 0 - mSpritesets[imageset]->getHeight() + 32; + offsetX = 0 - mSpritesets[imageset]->getWidth() / 2 + 16; + while (end >= start) + { + animation->addPhase(start + variant_offset, delay, offsetX, offsetY); + start++; + } + } + } // for phaseNode + action->setAnimation(direction, animation); + } // if "<animation>" + } // for animationNode + } // if "<imageset>" else if "<action>" + } // for node + + //complete missing actions + substituteAction("stand", ""); + substituteAction("walk", "stand"); + substituteAction("walk", "run"); + substituteAction("attack", "stand"); + substituteAction("attack_swing", "attack"); + substituteAction("attack_stab", "attack_swing"); + substituteAction("attack_bow", "attack_stab"); + substituteAction("attack_throw", "attack_swing"); + substituteAction("cast_magic", "attack_swing"); + substituteAction("use_item", "cast_magic"); + substituteAction("sit", "stand"); + substituteAction("sleeping", "sit"); + substituteAction("hurt", "stand"); + substituteAction("dead", "hurt"); + + xmlFreeDoc(doc); +} + +void +AnimatedSprite::substituteAction(std::string complete, std::string with) +{ + if (mActions.find(complete) == mActions.end()) + { + mActions[complete] = mActions[with]; + } +} + +AnimatedSprite::~AnimatedSprite() +{ + for (SpritesetIterator i = mSpritesets.begin(); i != mSpritesets.end(); i++) + { + delete i->second; + } + mSpritesets.clear(); +} + +void +AnimatedSprite::play(std::string action) +{ + if (mAction != action) + { + mAction = action; + } + mLastTime = 0; +} + +void +AnimatedSprite::play(std::string action, std::string direction) +{ + play(action); + mDirection = direction; +} + +void +AnimatedSprite::update(int time) +{ + //avoid freaking out at first frame or when tick_time overflows + if (time < mLastTime || mLastTime == 0) mLastTime = time; + + Action *action = mActions[mAction]; + action->getAnimation(mDirection)->update(time - mLastTime); + mLastTime = time; +} + +bool +AnimatedSprite::draw(Graphics * graphics, Sint32 posX, Sint32 posY) +{ + Sint32 offsetX, offsetY; + Action *action = mActions[mAction]; + Spriteset *spriteset = mSpritesets[action->getImageset()]; + Animation *animation = action->getAnimation(mDirection); + + if (animation->getCurrentPhase() >= 0) + { + Image *image = spriteset->get(animation->getCurrentPhase()); + offsetX = animation->getOffsetX(); + offsetY = animation->getOffsetY(); + return graphics->drawImage(image, posX + offsetX, posY + offsetY); + } + else + { + return false; + } +} + +Image * +AnimatedSprite::getCurrentFrame() +{ + Action *action = mActions[mAction]; + Spriteset *spriteset = mSpritesets[action->getImageset()]; + Animation *animation = action->getAnimation(mDirection); + if (animation->getCurrentPhase() >= 0) + { + return spriteset->get(animation->getCurrentPhase()); + } + else + { + return NULL; + } +} + +int +AnimatedSprite::getWidth() +{ + Action *action = mActions[mAction]; + Spriteset *spriteset = mSpritesets[action->getImageset()]; + return spriteset->getWidth(); +} + +int +AnimatedSprite::getHeight() +{ + Action *action = mActions[mAction]; + Spriteset *spriteset = mSpritesets[action->getImageset()]; + return spriteset->getHeight(); +} diff --git a/src/animation.h b/src/animation.h new file mode 100644 index 00000000..55f0bc99 --- /dev/null +++ b/src/animation.h @@ -0,0 +1,160 @@ +/* + * 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 + * + * $Id$ + */ + +#ifndef _TMW_ANIMATION_H +#define _TMW_ANIMATION_H + +#include <list> +#include <map> +#include <string> + +#include "graphics.h" + +class Image; +class Spriteset; + +struct AnimationPhase +{ + int image; + unsigned int delay; + int offsetX; + int offsetY; +}; + +class Animation +{ + public: + Animation(); + + void addPhase (int image, unsigned int delay, int offsetX, int offsetY); + + void update(unsigned int time); + + int getCurrentPhase(); + + int getOffsetX() { return (*iCurrentPhase).offsetX ; }; + int getOffsetY() { return (*iCurrentPhase).offsetY ; }; + + protected: + std::list<AnimationPhase> mAnimationPhases; + std::list<AnimationPhase>::iterator iCurrentPhase; + unsigned int mTime; +}; + +class Action +{ + public: + Action(); + + ~Action(); + + void setImageset(std::string imageset) { mImageset = imageset; } + + std::string getImageset() { return mImageset; } + + void setAnimation(std::string direction, Animation *animation); + + Animation *getAnimation(std::string direction); // { return mAnimations[direction]; } + + protected: + std::string mImageset; + typedef std::map<std::string, Animation*> Animations; + typedef Animations::iterator AnimationIterator; + Animations mAnimations; +}; + +/** + * Defines a class to load an animation. + */ +class AnimatedSprite +{ + public: + /** + * Constructor. + */ + AnimatedSprite(std::string animationFile, int variant); + + /** + * Destructor. + */ + ~AnimatedSprite(); + + /** + * Sets a new action using the current direction. + */ + void play(std::string action); + + /** + * Sets a new action with a new direction. + */ + void play(std::string action, std::string direction); + + /** + * Inform the animation of the passed time so that it can output the + * correct animation phase. + */ + void update(int time); + + /** + * Draw the current animation phase at the coordinates given in screen + * pixels + */ + bool draw(Graphics * graphics, Sint32 posX, Sint32 posY); + + /** + * Draw the current animation phase. + */ + Image *getCurrentFrame(); + + /** + * gets the width in pixels of the current animation phase. + */ + int getWidth(); + + /** + * gets the height in pixels of the current animation phase. + */ + int getHeight(); + + /** + * Sets the direction. + */ + void setDirection(std::string direction) { mDirection = direction; } + + protected: + /** + * When there are no animations defined for the action "complete", its + * animations become a copy of those of the action "with". + */ + void substituteAction(std::string complete, std::string with); + + typedef std::map<std::string, Spriteset*> Spritesets; + typedef Spritesets::iterator SpritesetIterator; + Spritesets mSpritesets; + typedef std::map<std::string, Action*> Actions; + Actions mActions; + std::string mAction, mDirection; + int mLastTime; +}; + +#endif diff --git a/src/base64.cpp b/src/base64.cpp index e2df07de..6d503a53 100644 --- a/src/base64.cpp +++ b/src/base64.cpp @@ -105,7 +105,7 @@ unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_ headache. - Turadg Aleahmad <turadg@wise.berkeley.edu> */ - if (ch == ' ') ch = '+'; + if (ch == ' ') ch = '+'; ch = reverse_table[ch]; if (ch < 0) continue; diff --git a/src/being.cpp b/src/being.cpp index a0db8208..19d9d916 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -44,7 +44,7 @@ PATH_NODE::PATH_NODE(Uint16 iX, Uint16 iY): Being::Being(Uint32 id, Uint16 job, Map *map): mJob(job), mX(0), mY(0), mDirection(DOWN), - mAction(0), mFrame(0), + mAction(0), mWalkTime(0), mEmotion(0), mEmotionTime(0), mAttackSpeed(350), @@ -53,24 +53,29 @@ Being::Being(Uint32 id, Uint16 job, Map *map): mWeapon(0), mWalkSpeed(150), mMap(NULL), - mHairStyle(1), mHairColor(1), - mSex(0), + mHairStyle(0), mHairColor(0), + mSex(2), mSpeechTime(0), mDamageTime(0), - mShowSpeech(false), mShowDamage(false), - mSpriteset(NULL), mSpriteFrame(0) + mShowSpeech(false), mShowDamage(false) { setMap(map); - memset(mVisibleEquipment, 0, 6 * sizeof(int)); + mSprites.resize(VECTOREND_SPRITE, NULL); } Being::~Being() { + for (int i =0; i < VECTOREND_SPRITE; i++) + { + delete mSprites[i]; + } + clearPath(); setMap(NULL); } -void Being::setDestination(Uint16 destX, Uint16 destY) +void +Being::setDestination(Uint16 destX, Uint16 destY) { if (mMap) { @@ -78,12 +83,14 @@ void Being::setDestination(Uint16 destX, Uint16 destY) } } -void Being::clearPath() +void +Being::clearPath() { mPath.clear(); } -void Being::setPath(const Path &path) +void +Being::setPath(const Path &path) { mPath = path; @@ -94,7 +101,8 @@ void Being::setPath(const Path &path) } } -void Being::setHairColor(Uint16 color) +void +Being::setHairColor(Uint16 color) { mHairColor = color; if (mHairColor < 1 || mHairColor > NR_HAIR_COLORS + 1) @@ -103,7 +111,8 @@ void Being::setHairColor(Uint16 color) } } -void Being::setHairStyle(Uint16 style) +void +Being::setHairStyle(Uint16 style) { mHairStyle = style; if (mHairStyle < 1 || mHairStyle > NR_HAIR_STYLES) @@ -113,6 +122,26 @@ void Being::setHairStyle(Uint16 style) } void +Being::setHair(Uint16 style, Uint16 color) +{ + mHairStyle = style; + if (mHairStyle < 1 || mHairStyle > NR_HAIR_STYLES) + { + mHairStyle = 1; + } + mHairColor = color; + if (mHairColor < 1 || mHairColor > NR_HAIR_COLORS + 1) + { + mHairColor = 1; + } +} + +void +Being::setVisibleEquipment(Uint8 slot, Uint8 id) +{ +} + +void Being::setSpeech(const std::string &text, Uint32 time) { mSpeech = text; @@ -147,13 +176,93 @@ Being::setMap(Map *map) } void -Being::nextStep() +Being::setAction(Action action) { - mFrame = 0; + if (action != mAction) + { + std::string currentAction = "stand"; + switch (action) + { + case WALK: + currentAction = "walk"; + break; + case SIT: + currentAction = "sit"; + break; + case ATTACK: + if (getType() == MONSTER) + { + currentAction = "dead"; + }else{ + switch (getWeapon()) + { + case 2: + currentAction = "attack_bow"; + break; + case 1: + currentAction = "attack_stab"; + break; + case 0: + currentAction = "attack"; + break; + } + }; + break; + case MONSTER_ATTACK: + currentAction = "attack"; + break; + case DEAD: + currentAction = "dead"; + break; + default: + currentAction = "stand"; + break; + } + + for (int i = 0; i < VECTOREND_SPRITE; i++) + { + if (mSprites[i] != NULL) mSprites[i]->play(currentAction); + } + } + mAction = action; +} +void +Being::setDirection(Uint8 direction) +{ + mDirection |= direction; + std::string dir; + + if (direction & UP) + { + dir = "up"; + } + else if (direction & RIGHT) + { + dir = "right"; + } + else if (direction & DOWN) + { + dir = "down"; + } + else + { + dir = "left"; + } + + for (int i = 0; i < VECTOREND_SPRITE; i++) + { + if (mSprites[i] != NULL) mSprites[i]->setDirection(dir); + } + +} + +void +Being::nextStep() +{ if (mPath.empty()) { - mAction = STAND; + setAction(STAND); return; } @@ -162,17 +271,17 @@ Being::nextStep() mDirection = 0; if (node.x > mX) - mDirection |= RIGHT; + setDirection(RIGHT); else if (node.x < mX) - mDirection |= LEFT; + setDirection(LEFT); if (node.y > mY) - mDirection |= DOWN; + setDirection(DOWN); else if (node.y < mY) - mDirection |= UP; + setDirection(UP); mX = node.x; mY = node.y; - mAction = WALK; + setAction(WALK); mWalkTime += mWalkSpeed / 10; } @@ -202,17 +311,36 @@ Being::logic() mEmotion = 0; } } + + // Update sprite animations + for (int i = 0; i < VECTOREND_SPRITE; i++) + { + if (mSprites[i] != NULL) + { + printf("Draw: %i\n", i); + mSprites[i]->update(tick_time * 10); + } + } } -void Being::draw(Graphics *graphics, int offsetX, int offsetY) +void +Being::draw(Graphics *graphics, int offsetX, int offsetY) { - if (!mSpriteset) - return; - int px = mPx + offsetX; int py = mPy + offsetY; - graphics->drawImage(mSpriteset->get(mSpriteFrame), px, py); + //what are these two lines good for? please add a comment. + unsigned char dir = 0; + while (!(mDirection & (1 << dir))) dir++; + + for (int i = 0; i < VECTOREND_SPRITE; i++) + { + if (mSprites[i] != NULL) + { + mSprites[i]->draw(graphics, px, py); + printf("Draw: %i\n", i); + } + } } void @@ -274,12 +402,14 @@ Being::drawSpeech(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) } } -Being::Type Being::getType() const +Being::Type +Being::getType() const { return UNKNOWN; } -void Being::setWeaponById(Uint16 weapon) +void +Being::setWeaponById(Uint16 weapon) { switch (weapon) { @@ -309,7 +439,8 @@ void Being::setWeaponById(Uint16 weapon) } } -int Being::getOffset(char pos, char neg) const +int +Being::getOffset(char pos, char neg) const { // Check whether we're walking in the requested direction if (mAction != WALK || !(mDirection & (pos | neg))) { diff --git a/src/being.h b/src/being.h index 9970b5d1..6fac98b7 100644 --- a/src/being.h +++ b/src/being.h @@ -27,11 +27,13 @@ #include <list> #include <string> #include <SDL_types.h> +#include <vector> +#include "animation.h" #include "sprite.h" #include "map.h" -#define NR_HAIR_STYLES 6 +#define NR_HAIR_STYLES 7 #define NR_HAIR_COLORS 10 class Equipment; @@ -75,6 +77,19 @@ class Being : public Sprite HIT = 17 }; + enum Sprite { + BASE_SPRITE = 0, + SHOE_SPRITE, + BOTTOMCLOTHES_SPRITE, + TOPCLOTHES_SPRITE, + HAIR_SPRITE, + HAT_SPRITE, + WEAPON_SPRITE, + VECTOREND_SPRITE + }; + + + /** * Directions, to be used as bitmask values */ @@ -83,14 +98,14 @@ class Being : public Sprite static const char UP = 4; static const char RIGHT = 8; - Uint16 mJob; /**< Job (player job, npc, monster, ) */ + Uint16 mJob; /**< Job (player job, npc, monster, ) */ Uint16 mX, mY; /**< Tile coordinates */ - Uint8 mDirection; /**< Facing direction */ - Uint8 mAction; + Uint8 mDirection; /**< Facing direction */ + Uint8 mAction; /**< Action the being is performing */ Uint8 mFrame; Uint16 mWalkTime; - Uint8 mEmotion; /**< Currently showing emotion */ - Uint8 mEmotionTime; /**< Time until emotion disappears */ + Uint8 mEmotion; /**< Currently showing emotion */ + Uint8 mEmotionTime; /**< Time until emotion disappears */ Uint16 mAttackSpeed; /**< Attack speed */ @@ -149,7 +164,7 @@ class Being : public Sprite /** * Sets the hair color for this being. */ - void + virtual void setHairColor(Uint16 color); /** @@ -161,7 +176,7 @@ class Being : public Sprite /** * Sets the hair style for this being. */ - void + virtual void setHairStyle(Uint16 style); /** @@ -169,11 +184,23 @@ class Being : public Sprite */ Uint16 getHairStyle() const { return mHairStyle; } - + + /** + * Sets the hair style and color for this being. + */ + virtual void + setHair(Uint16 style, Uint16 color); + + /** + * Sets visible equipments for this being. + */ + virtual void + setVisibleEquipment(Uint8 slot, Uint8 id); + /** * Sets the sex for this being. */ - void + virtual void setSex(Uint8 sex) { mSex = sex; } /** @@ -268,6 +295,16 @@ class Being : public Sprite void setMap(Map *map); /** + * Sets the current action. + */ + void setAction(Action action); + + /** + * Sets the current direction. + */ + void setDirection(Uint8 direction); + + /** * Draws this being to the given graphics context. * * @see Sprite::draw(Graphics, int, int) @@ -300,7 +337,7 @@ class Being : public Sprite */ int getYOffset() const { return getOffset(UP, DOWN); } - + std::auto_ptr<Equipment> mEquipment; int mVisibleEquipment[6]; /**< Visible equipments */ @@ -334,8 +371,7 @@ class Being : public Sprite bool mShowSpeech, mShowDamage; Sint32 mPx, mPy; /**< Pixel coordinates */ - Spriteset *mSpriteset; - int mSpriteFrame; + std::vector<AnimatedSprite *>mSprites; }; #endif diff --git a/src/engine.cpp b/src/engine.cpp index 724c0930..ba28fcc9 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -25,6 +25,7 @@ #include <list> +#include "animation.h" #include "being.h" #include "beingmanager.h" #include "flooritemmanager.h" @@ -57,14 +58,13 @@ extern Minimap *minimap; char itemCurrenyQ[10] = "0"; int camera_x, camera_y; -std::map<int, Spriteset*> monsterset; - ItemManager *itemDb; /**< Item database object */ Spriteset *itemset; Spriteset *emotionset; Spriteset *npcset; std::vector<Spriteset *> weaponset; +AnimatedSprite *animatedSprite; Engine::Engine(Network *network): @@ -102,9 +102,6 @@ Engine::Engine(Network *network): Engine::~Engine() { // Delete sprite sets - for_each(monsterset.begin(), monsterset.end(), make_dtor(monsterset)); - monsterset.clear(); - delete npcset; delete emotionset; for_each(weaponset.begin(), weaponset.end(), make_dtor(weaponset)); @@ -112,6 +109,8 @@ Engine::~Engine() delete itemset; delete itemDb; + + delete animatedSprite; } void Engine::changeMap(const std::string &mapPath) diff --git a/src/game.cpp b/src/game.cpp index 0ccc7542..51b541a6 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -357,7 +357,7 @@ void Game::logic() } gameTime = tick_time; - + fpsLimit = (int)config.getValue("fpslimit", 50); if (fpsLimit) { diff --git a/src/graphic/spriteset.cpp b/src/graphic/spriteset.cpp index b008a701..3b190f31 100644 --- a/src/graphic/spriteset.cpp +++ b/src/graphic/spriteset.cpp @@ -23,6 +23,8 @@ #include "spriteset.h" +#include "../log.h" + #include "../resources/image.h" #include "../utils/dtor.h" @@ -36,9 +38,25 @@ Spriteset::Spriteset(Image *img, int width, int height) mSpriteset.push_back(img->getSubImage(x, y, width, height)); } } + mWidth = width; + mHeight = height; } Spriteset::~Spriteset() { for_each(mSpriteset.begin(), mSpriteset.end(), make_dtor(mSpriteset)); } + +Image * +Spriteset::get(size_type i) +{ + if (i > mSpriteset.size()) + { + logger->log("Warning: Sprite #%i does not exist in this spriteset", i); + return NULL; + } + else + { + return mSpriteset[i]; + } +} diff --git a/src/graphic/spriteset.h b/src/graphic/spriteset.h index 08ff65f5..94ccb742 100644 --- a/src/graphic/spriteset.h +++ b/src/graphic/spriteset.h @@ -44,14 +44,21 @@ class Spriteset { */ ~Spriteset(); + int getWidth() { return mWidth; }; + + int getHeight() { return mHeight; }; + typedef std::vector<Image*>::size_type size_type; - Image* get(size_type i) { return mSpriteset[i]; } + Image * get(size_type i); size_type size() { return mSpriteset.size(); } private: // Vector storing the whole spriteset. std::vector<Image*> mSpriteset; + //height and width of the images in the spriteset + int mHeight; + int mWidth; }; #endif diff --git a/src/graphics.cpp b/src/graphics.cpp index d709bfe1..2757214a 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -126,14 +126,16 @@ bool Graphics::drawImage(Image *image, int x, int y) bool Graphics::drawImage(Image *image, int srcX, int srcY, int dstX, int dstY, int width, int height) { + // Check that preconditions for blitting are met. + if (!mScreen || !image || !image->mImage) return false; + dstX += mClipStack.top().xOffset; dstY += mClipStack.top().yOffset; srcX += image->mBounds.x; srcY += image->mBounds.y; - // Check that preconditions for blitting are met. - if (!mScreen || !image->mImage) return false; + SDL_Rect dstRect; SDL_Rect srcRect; diff --git a/src/gui/chargedialog.h b/src/gui/chargedialog.h index d1726500..c09c692c 100644 --- a/src/gui/chargedialog.h +++ b/src/gui/chargedialog.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - + #ifndef _TMW_CHARGE_H #define _TMW_CHARGE_H diff --git a/src/gui/inventorywindow.h b/src/gui/inventorywindow.h index f588fa8e..179e5314 100644 --- a/src/gui/inventorywindow.h +++ b/src/gui/inventorywindow.h @@ -22,7 +22,7 @@ */ #ifndef _TMW_INVENTORYWINDOW_H -#define _TMW_INVENTORYWINDOW_H +#define _TMW_INVENTORYWINDOW_H #include <guichan/actionlistener.hpp> diff --git a/src/gui/menuwindow.h b/src/gui/menuwindow.h index 945bca94..f43b9921 100644 --- a/src/gui/menuwindow.h +++ b/src/gui/menuwindow.h @@ -48,4 +48,4 @@ class MenuWindow : public Window }; #endif - + diff --git a/src/gui/minimap.h b/src/gui/minimap.h index 53b18630..5e9458bf 100644 --- a/src/gui/minimap.h +++ b/src/gui/minimap.h @@ -22,7 +22,7 @@ */ #ifndef _TMW_MINIMAP_H -#define _TMW_MINIMAP_H +#define _TMW_MINIMAP_H #include "window.h" diff --git a/src/gui/ministatus.h b/src/gui/ministatus.h index b5d149e7..f56f847c 100644 --- a/src/gui/ministatus.h +++ b/src/gui/ministatus.h @@ -64,4 +64,4 @@ class MiniStatusWindow : public Window }; #endif - + diff --git a/src/gui/newskill.h b/src/gui/newskill.h index 96bcf9ad..764019f5 100644 --- a/src/gui/newskill.h +++ b/src/gui/newskill.h @@ -20,7 +20,7 @@ * * $Id$ */ - + #ifndef _TMW_NSKILL_H #define _TMW_NSKILL_H @@ -35,7 +35,7 @@ class ProgressBar; #define N_SKILL 100 // skill count constant #define N_SKILL_CAT 9 // skill category count #define N_SKILL_CAT_SIZE 10 // skill category maximum size - + struct nSkill { short level; short exp; diff --git a/src/gui/sell.cpp b/src/gui/sell.cpp index bde8906b..ec565ac3 100644 --- a/src/gui/sell.cpp +++ b/src/gui/sell.cpp @@ -212,7 +212,7 @@ void SellDialog::action(const std::string& eventId) else if (eventId == "sell") { // Attempt sell assert(mAmountItems > 0 && mAmountItems <= mMaxItems); - + MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_SELL_REQUEST); outMsg.writeInt16(8); diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index d6289bbc..05543092 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -141,7 +141,7 @@ Setup_Video::Setup_Video(): mModeList->setSelected(-1); mAlphaSlider->setValue(mOpacity); - + mFpsField->setText(toString(mFps)); mFpsField->setEnabled(mFps > 0); mFpsSlider->setValue(mFps); @@ -213,7 +213,7 @@ void Setup_Video::apply() new OkDialog("Changing OpenGL", "Applying change to OpenGL requires restart."); } - + // FPS change config.setValue("fpslimit", mFps); @@ -273,7 +273,7 @@ void Setup_Video::action(const std::string &event) void Setup_Video::keyPress(const gcn::Key &key) { std::stringstream tempFps(mFpsField->getText()); - + if (tempFps >> mFps) { if (mFps < 10) diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h index d8ee1914..b021ead4 100644 --- a/src/gui/setup_video.h +++ b/src/gui/setup_video.h @@ -42,7 +42,7 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, void cancel(); void action(const std::string&); - + /** Called when key is pressed */ void keyPress(const gcn::Key& key); diff --git a/src/gui/status.h b/src/gui/status.h index 66068a7d..52ece323 100644 --- a/src/gui/status.h +++ b/src/gui/status.h @@ -88,7 +88,7 @@ class StatusWindow : public Window, public gcn::ActionListener { gcn::Label *mStatsAccuracyPoints, *mStatsEvadePoints; gcn::Label *mStatsReflexPoints; - /** + /** * Stats captions. */ gcn::Label *mStatsLabel[6]; @@ -96,7 +96,7 @@ class StatusWindow : public Window, public gcn::ActionListener { gcn::Label *mStatsDisplayLabel[6]; gcn::Label *mRemainingStatsPointsLabel; - /** + /** * Stats buttons. */ gcn::Button *mStatsButton[6]; diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 0313fe81..339435a5 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -210,7 +210,7 @@ void LocalPlayer::walk(unsigned char dir) { // Update the player direction to where he wants to walk // Warning: Not communicated to the server yet - mDirection = dir; + setDirection(dir); } } @@ -344,22 +344,22 @@ void LocalPlayer::attack(Being *target, bool keep) if (abs(dist_y) >= abs(dist_x)) { if (dist_y > 0) - mDirection = DOWN; + setDirection(DOWN); else - mDirection = UP; + setDirection(UP); } else { if (dist_x > 0) - mDirection = RIGHT; + setDirection(RIGHT); else - mDirection = LEFT; + setDirection(LEFT); } // Implement charging attacks here mLastAttackTime = 0; - mAction = ATTACK; + setAction(ATTACK); mWalkTime = tick_time; if (getWeapon() == 2) sound.playSfx("sfx/bow_shoot_1.ogg"); diff --git a/src/main.cpp b/src/main.cpp index a4ef390e..5ecb4f35 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,7 @@ #define NOGDI #endif +#include "animation.h" #include "configuration.h" #include "game.h" #include "graphics.h" @@ -84,7 +85,6 @@ char n_server, n_character; std::vector<Spriteset *> hairset; Spriteset *playerset[2]; -Spriteset *equipmentset[2]; Graphics *graphics; // TODO Anyone knows a good location for this? Or a way to make it non-global? @@ -250,12 +250,6 @@ void init_engine() playerset[1] = resman->createSpriteset( "graphics/sprites/player_female_base.png", 64, 64); if (!playerset[1]) logger->error("Couldn't load female player spriteset!"); - equipmentset[0] = resman->createSpriteset( - "graphics/sprites/item001.png", 64, 64); - if (!equipmentset[0]) logger->error("Couldn't load player equipmentset!"); - equipmentset[1] = resman->createSpriteset( - "graphics/sprites/item002.png", 64, 64); - if (!equipmentset[1]) logger->error("Couldn't load player equipmentset!"); for (int i=0; i < NR_HAIR_STYLES; i++) @@ -298,8 +292,6 @@ void exit_engine() hairset.clear(); delete playerset[0]; delete playerset[1]; - delete equipmentset[0]; - delete equipmentset[1]; // Shutdown libxml xmlCleanupParser(); @@ -685,10 +677,12 @@ int main(int argc, char *argv[]) break; case CHAR_CONNECT_STATE: + printf("Char: %i\n", loginData.sex); charLogin(network, &loginData); break; case ACCOUNT_STATE: + printf("Account: %i\n", loginData.sex); accountLogin(network, &loginData); break; diff --git a/src/monster.cpp b/src/monster.cpp index af84b25e..43823e50 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -30,28 +30,15 @@ #include "utils/tostring.h" -class Spriteset; -extern std::map<int, Spriteset*> monsterset; Monster::Monster(Uint32 id, Uint16 job, Map *map): Being(id, job, map) { - // Load monster spriteset, if necessary - if (monsterset.find(job - 1002) == monsterset.end()) - { - Spriteset *tmp = ResourceManager::getInstance()->createSpriteset( - "graphics/sprites/monster" + toString(job - 1002) + ".png", - 60, 60); - if (!tmp) { - logger->error("Unable to load monster spriteset!"); - } else { - monsterset[job - 1002] = tmp; - } - } - mSpriteset = monsterset[job-1002]; + mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/monster" + toString(job - 1002) + ".xml", 0); } -void Monster::logic() +void +Monster::logic() { if (mAction != STAND) { @@ -66,27 +53,9 @@ void Monster::logic() Being::logic(); } -Being::Type Monster::getType() const +Being::Type +Monster::getType() const { return MONSTER; } -void Monster::draw(Graphics *graphics, int offsetX, int offsetY) -{ - if (mFrame >= 4) - { - mFrame = 3; - } - - mSpriteFrame = mAction; - if (mAction != MONSTER_DEAD) { - mSpriteFrame += mFrame; - } - - unsigned char dir = 0; - while (!(mDirection & (1 << dir))) dir++; - - mSpriteFrame = dir + 4 * mSpriteFrame; - - Being::draw(graphics, offsetX - 12, offsetY - 25); -} diff --git a/src/monster.h b/src/monster.h index 6f3d2a89..4a82a461 100644 --- a/src/monster.h +++ b/src/monster.h @@ -34,8 +34,6 @@ class Monster : public Being virtual void logic(); virtual Type getType() const; - - virtual void draw(Graphics *graphics, int offsetX, int offsetY); }; #endif diff --git a/src/net/beinghandler.cpp b/src/net/beinghandler.cpp index 58660094..cd5653fc 100644 --- a/src/net/beinghandler.cpp +++ b/src/net/beinghandler.cpp @@ -96,7 +96,7 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->clearPath(); dstBeing->mFrame = 0; dstBeing->mWalkTime = tick_time; - dstBeing->mAction = Being::STAND; + dstBeing->setAction(Being::STAND); } // Prevent division by 0 when calculating frame @@ -106,7 +106,7 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->mJob = job; dstBeing->setHairStyle(msg->readInt16()); dstBeing->setWeapon(msg->readInt16()); - dstBeing->mVisibleEquipment[3] = msg->readInt16(); // head (bottom) + dstBeing->setVisibleEquipment(3, msg->readInt16()); // head bottom if (msg->getId() == SMSG_BEING_MOVE) { @@ -114,8 +114,8 @@ void BeingHandler::handleMessage(MessageIn *msg) } msg->readInt16(); // shield - dstBeing->mVisibleEquipment[4] = msg->readInt16(); // head (top) - dstBeing->mVisibleEquipment[5] = msg->readInt16(); // head (mid) + dstBeing->setVisibleEquipment(4, msg->readInt16()); // head top + dstBeing->setVisibleEquipment(5, msg->readInt16()); // head mid dstBeing->setHairColor(msg->readInt16()); msg->readInt16(); // unknown msg->readInt16(); // head dir @@ -131,7 +131,7 @@ void BeingHandler::handleMessage(MessageIn *msg) { Uint16 srcX, srcY, dstX, dstY; msg->readCoordinatePair(srcX, srcY, dstX, dstY); - dstBeing->mAction = Being::STAND; + dstBeing->setAction(Being::STAND); dstBeing->mX = srcX; dstBeing->mY = srcY; dstBeing->setDestination(dstX, dstY); @@ -160,13 +160,13 @@ void BeingHandler::handleMessage(MessageIn *msg) switch (dstBeing->getType()) { case Being::MONSTER: - dstBeing->mAction = Being::MONSTER_DEAD; + dstBeing->setAction(Being::MONSTER_DEAD); dstBeing->mFrame = 0; dstBeing->mWalkTime = tick_time; break; default: - dstBeing->mAction = Being::DEAD; + dstBeing->setAction(Being::DEAD); break; } } @@ -205,11 +205,11 @@ void BeingHandler::handleMessage(MessageIn *msg) // buggy if (srcBeing->getType() == Being::MONSTER) { - srcBeing->mAction = Being::MONSTER_ATTACK; + srcBeing->setAction(Being::MONSTER_ATTACK); } else { - srcBeing->mAction = Being::ATTACK; + srcBeing->setAction(Being::ATTACK); } srcBeing->mFrame = 0; srcBeing->mWalkTime = tick_time; @@ -219,13 +219,13 @@ void BeingHandler::handleMessage(MessageIn *msg) case 2: // Sit if (srcBeing == NULL) break; srcBeing->mFrame = 0; - srcBeing->mAction = Being::SIT; + srcBeing->setAction(Being::SIT); break; case 3: // Stand up if (srcBeing == NULL) break; srcBeing->mFrame = 0; - srcBeing->mAction = Being::STAND; + srcBeing->setAction(Being::STAND); break; } break; @@ -269,8 +269,8 @@ void BeingHandler::handleMessage(MessageIn *msg) case 3: case 4: case 5: - // Equip/unequip head 3. Bottom 4. Top 5. Bottom - dstBeing->mVisibleEquipment[type] = msg->readInt8(); + // Equip/unequip head 3. Bottom 4. Top 5. Middle + dstBeing->setVisibleEquipment(type, msg->readInt8()); // First 3 slots of mVisibleEquipments are reserved for // later use, probably accessories. break; @@ -314,15 +314,15 @@ void BeingHandler::handleMessage(MessageIn *msg) dstBeing->setHairStyle(msg->readInt16()); dstBeing->setWeaponById(msg->readInt16()); // item id 1 msg->readInt16(); // item id 2 - dstBeing->mVisibleEquipment[3] = msg->readInt16(); // head (bottom) + dstBeing->setVisibleEquipment(3, msg->readInt16()); // head bottom if (msg->getId() == SMSG_PLAYER_MOVE) { msg->readInt32(); // server tick } - dstBeing->mVisibleEquipment[4] = msg->readInt16(); // head (top) - dstBeing->mVisibleEquipment[5] = msg->readInt16(); // head (mid) + dstBeing->setVisibleEquipment(4, msg->readInt16()); // head top + dstBeing->setVisibleEquipment(5, msg->readInt16()); // head mid dstBeing->setHairColor(msg->readInt16()); msg->readInt16(); // unknown msg->readInt16(); // head dir @@ -353,7 +353,7 @@ void BeingHandler::handleMessage(MessageIn *msg) { if (msg->readInt8() == 2) { - dstBeing->mAction = Being::SIT; + dstBeing->setAction(Being::SIT); } } else if (msg->getId() == SMSG_PLAYER_MOVE) @@ -371,8 +371,8 @@ void BeingHandler::handleMessage(MessageIn *msg) case 0x0119: // Change in players look printf("0x0119 %i %i %i %x %i\n", msg->readInt32(), - msg->readInt16(), msg->readInt16(), msg->readInt16(), - msg->readInt8()); + msg->readInt16(), msg->readInt16(), msg->readInt16(), + msg->readInt8()); break; } } diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp index 9857ddc0..06ec78c1 100644 --- a/src/net/charserverhandler.cpp +++ b/src/net/charserverhandler.cpp @@ -191,10 +191,10 @@ LocalPlayer* CharServerHandler::readPlayerData(MessageIn *msg, int &slot) tempPlayer->setWeapon(weapon); tempPlayer->mLevel = msg->readInt16(); msg->readInt16(); // skill point - tempPlayer->mVisibleEquipment[3] = msg->readInt16(); // head bottom + tempPlayer->setVisibleEquipment(3, msg->readInt16()); // head bottom msg->readInt16(); // shield - tempPlayer->mVisibleEquipment[4] = msg->readInt16(); // head option top - tempPlayer->mVisibleEquipment[5] = msg->readInt16(); // head option mid + tempPlayer->setVisibleEquipment(4, msg->readInt16()); // head option top + tempPlayer->setVisibleEquipment(5, msg->readInt16()); // head option mid tempPlayer->setHairColor(msg->readInt16()); msg->readInt16(); // unknown tempPlayer->setName(msg->readString(24)); diff --git a/src/net/playerhandler.cpp b/src/net/playerhandler.cpp index 070fb112..94788333 100644 --- a/src/net/playerhandler.cpp +++ b/src/net/playerhandler.cpp @@ -104,7 +104,7 @@ void PlayerHandler::handleMessage(MessageIn *msg) current_npc = 0; - player_node->mAction = Being::STAND; + player_node->setAction(Being::STAND); player_node->stopAttack(); player_node->mFrame = 0; player_node->mX = x; @@ -163,7 +163,7 @@ void PlayerHandler::handleMessage(MessageIn *msg) deathNotice = new OkDialog("Message", "You're now dead, press ok to restart"); deathNotice->addActionListener(&deathListener); - player_node->mAction = Being::DEAD; + player_node->setAction(Being::DEAD); } } break; diff --git a/src/npc.cpp b/src/npc.cpp index 9712a06d..354322a3 100644 --- a/src/npc.cpp +++ b/src/npc.cpp @@ -34,21 +34,17 @@ NPC *current_npc = 0; NPC::NPC(Uint32 id, Uint16 job, Map *map, Network *network): Being(id, job, map), mNetwork(network) { - mSpriteset = npcset; - mSpriteFrame = job-100; + mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/npc.xml", job-100); } -Being::Type NPC::getType() const +Being::Type +NPC::getType() const { return Being::NPC; } -void NPC::draw(Graphics *graphics, int offsetX, int offsetY) -{ - Being::draw(graphics, offsetX - 8, offsetY - 52); -} - -void NPC::talk() +void +NPC::talk() { MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_TALK); @@ -57,14 +53,16 @@ void NPC::talk() current_npc = this; } -void NPC::nextDialog() +void +NPC::nextDialog() { MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_NEXT_REQUEST); outMsg.writeInt32(mId); } -void NPC::dialogChoice(char choice) +void +NPC::dialogChoice(char choice) { MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_LIST_CHOICE); @@ -76,7 +74,8 @@ void NPC::dialogChoice(char choice) * 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() { MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST); @@ -84,7 +83,8 @@ void NPC::buy() outMsg.writeInt8(0); } -void NPC::sell() +void +NPC::sell() { MessageOut outMsg(mNetwork); outMsg.writeInt16(CMSG_NPC_BUY_SELL_REQUEST); @@ -35,8 +35,6 @@ class NPC : public Being virtual Type getType() const; - virtual void draw(Graphics *graphics, int offsetX, int offsetY); - void talk(); void nextDialog(); void dialogChoice(char choice); diff --git a/src/player.cpp b/src/player.cpp index 43439ab1..9b7536cf 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -23,55 +23,26 @@ #include "player.h" +#include "animation.h" #include "equipment.h" #include "game.h" #include "graphics.h" -#include "graphic/spriteset.h" +#include "utils/tostring.h" #include "gui/gui.h" -extern std::vector<Spriteset *> hairset; -extern Spriteset *playerset[2]; -extern std::vector<Spriteset *> weaponset; -extern Spriteset *equipmentset[2]; - -signed char hairtable[19][4][2] = { - // S(x,y) W(x,y) N(x,y) E(x,y) - { {-5, -4}, {-6, -4}, {-6, 0}, {-4, -4} }, // STAND - { {-5, -3}, {-6, -4}, {-6, 0}, {-4, -4} }, // WALK 1st frame - { {-5, -4}, {-6, -3}, {-6, -1}, {-4, -3} }, // WALK 2nd frame - { {-5, -4}, {-6, -4}, {-6, -1}, {-4, -4} }, // WALK 3rd frame - { {-5, -3}, {-6, -4}, {-6, 0}, {-4, -4} }, // WALK 4th frame - { {-5, -4}, {-6, -3}, {-6, -1}, {-4, -3} }, // WALK 5th frame - { {-5, -4}, {-6, -4}, {-6, -1}, {-4, -4} }, // WALK 6th frame - { {-5, 8}, {-1, 5}, {-6, 8}, {-9, 5} }, // SIT - { {16, 21}, {16, 21}, {16, 21}, {16, 21} }, // DEAD - { {-5, -2}, {-2, -5}, {-6, 0}, {-7, -5} }, // ATTACK 1st frame - { {-5, -3}, {-2, -6}, {-6, 0}, {-7, -6} }, // ATTACK 2nd frame - { {-5, 0}, {-6, -3}, {-6, 0}, {-4, -3} }, // ATTACK 3rd frame - { {-5, 1}, {-7, -2}, {-6, 2}, {-3, -2} }, // ATTACK 4th frame - { {-5, -3}, {-3, -4}, {-6, 0}, {-7, -4} }, // BOW_ATTACK 1st frame - { {-5, -3}, {-3, -4}, {-6, 0}, {-7, -4} }, // BOW_ATTACK 2nd frame - { {-5, -3}, {-3, -4}, {-7, 0}, {-7, -4} }, // BOW_ATTACK 3rd frame - { {-5, -2}, {-1, -5}, {-7, 1}, {-9, -5} }, // BOW_ATTACK 4th frame - { {-5, -3}, {-1, -5}, {-7, 0}, {-9, -5} }, // BOW_ATTACK 5th frame - { { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0} } // ?? HIT -}; - -unsigned char hairframe[4][20] = { - { 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 3, 3, 3, 3, 3, 3, 3, 3, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }, - { 4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }, - { 5, 5, 5, 5, 5, 5, 5, 5, 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 } -}; - Player::Player(Uint32 id, Uint16 job, Map *map): Being(id, job, map) { + // Load the weapon sprite. + // When there are more different weapons this should be moved to the + // setWeapon Method. + mSprites[WEAPON_SPRITE] = new AnimatedSprite("graphics/sprites/weapons.xml", 0); } -void Player::logic() +void +Player::logic() { switch (mAction) { case WALK: @@ -80,7 +51,6 @@ void Player::logic() nextStep(); } break; - case ATTACK: int frames = 4; if (getWeapon() == 2) @@ -93,80 +63,95 @@ void Player::logic() } break; } - - - Being::logic(); } -Being::Type Player::getType() const +Being::Type +Player::getType() const { return PLAYER; } -void Player::draw(Graphics *graphics, int offsetX, int offsetY) +void +Player::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) { int px = mPx + offsetX; int py = mPy + offsetY; - int frame = mAction; - - frame = mAction; - if (mAction != SIT && mAction != DEAD) - { - frame += mFrame; - } + graphics->setFont(speechFont); + graphics->setColor(gcn::Color(255, 255, 255)); + graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER); +} - if (mAction == ATTACK && getWeapon() > 0) +void +Player::setSex(Uint8 sex) +{ + if (sex != mSex) { - if (getWeapon() == 2) + delete mSprites[BASE_SPRITE]; + if (sex == 0) { - frame += 4; + mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/player_male_base.xml", 0); } - } - - unsigned char dir = 0; - while (!(mDirection & (1 << dir))) dir++; - - graphics->drawImage(playerset[mSex]->get(frame + 18 * dir), - px - 16, py - 32); - - if (getWeapon() != 0 && mAction == ATTACK) - { - int frames = 4; - if (getWeapon() == 2) + else { - frames = 5; + mSprites[BASE_SPRITE] = new AnimatedSprite("graphics/sprites/player_female_base.xml", 0); } - Image *image = weaponset[getWeapon() - 1]->get(mFrame + frames * dir); - graphics->drawImage(image, px - 16, py - 32); } + Being::setSex(sex); +} - if (getHairColor() <= NR_HAIR_COLORS) +void +Player::setHairColor(Uint16 color) +{ + if (color != mHairColor && mHairStyle > 0) { - int hf = 9 * (getHairColor() - 1) + hairframe[dir][frame]; - - graphics->drawImage(hairset[getHairStyle() - 1]->get(hf), - px + 1 + hairtable[frame][dir][0], - py - 33 + hairtable[frame][dir][1]); + delete mSprites[HAIR_SPRITE]; + mSprites[HAIR_SPRITE] = new AnimatedSprite("graphics/sprites/hairstyle"+toString(mHairStyle)+".xml", color - 1); } - - // Display middle equipment - if (mVisibleEquipment[5]) + Being::setHairColor(color); +}; + +void +Player::setHairStyle(Uint16 style) +{ + if (style != mHairStyle && mHairColor > 0) { - graphics->drawImage( - equipmentset[mVisibleEquipment[5] - 1]->get(frame + 18 * dir), - px - 16, py - 32); + delete mSprites[HAIR_SPRITE]; + mSprites[HAIR_SPRITE] = new AnimatedSprite("graphics/sprites/hairstyle"+toString(style)+".xml", mHairColor - 1); } -} + Being::setHairStyle(style); +}; void -Player::drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY) +Player::setVisibleEquipment(Uint8 slot, Uint8 id) { - int px = mPx + offsetX; - int py = mPy + offsetY; - - graphics->setFont(speechFont); - graphics->setColor(gcn::Color(255, 255, 255)); - graphics->drawText(mName, px + 15, py + 30, gcn::Graphics::CENTER); + // Translate eAthena specific slot + Uint8 position = 0; + switch (slot) { + case 3: + position = BOTTOMCLOTHES_SPRITE; + break; + case 4: + position = HAT_SPRITE; + break; + case 5: + position = TOPCLOTHES_SPRITE; + break; + } + // id = 0 means unequip + if (mSprites[position]) { + delete mSprites[position]; + mSprites[position] = 0; + } + if (id) { + char stringId[4]; + sprintf(stringId, "%03i", id); + printf("Id: %i %i %s\n", id, slot, stringId); + mSprites[position] = new AnimatedSprite( + "graphics/sprites/item" + toString(stringId) + ".xml", 0); + } + Being::setVisibleEquipment(slot, id); } + + diff --git a/src/player.h b/src/player.h index 3c68116e..15e7f655 100644 --- a/src/player.h +++ b/src/player.h @@ -26,8 +26,11 @@ #include "being.h" +#include <string> + class Graphics; class Map; +class AnimatedSprite; class Player : public Being { @@ -38,9 +41,15 @@ class Player : public Being virtual Type getType() const; - virtual void draw(Graphics *graphics, int offsetX, int offsetY); - virtual void drawName(Graphics *graphics, Sint32 offsetX, Sint32 offsetY); + + virtual void setSex(Uint8 sex); + + virtual void setHairColor(Uint16 color); + + virtual void setHairStyle(Uint16 style); + + virtual void setVisibleEquipment(Uint8 slot, Uint8 id); }; #endif diff --git a/src/resources/imagewriter.cpp b/src/resources/imagewriter.cpp index f4be3a66..7cfa16b4 100644 --- a/src/resources/imagewriter.cpp +++ b/src/resources/imagewriter.cpp @@ -55,7 +55,7 @@ bool ImageWriter::writePNG(SDL_Surface *surface, logger->log("Had trouble creating png_structp"); return false; } - + info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { diff --git a/src/resources/itemmanager.cpp b/src/resources/itemmanager.cpp index d18152da..56ac6354 100644 --- a/src/resources/itemmanager.cpp +++ b/src/resources/itemmanager.cpp @@ -21,10 +21,11 @@ * $Id$ */ +#include "itemmanager.h" + #include <libxml/tree.h> #include "iteminfo.h" -#include "itemmanager.h" #include "resourcemanager.h" #include "../log.h" diff --git a/src/sound.h b/src/sound.h index 421bf899..39901121 100644 --- a/src/sound.h +++ b/src/sound.h @@ -88,7 +88,7 @@ class Sound { /** * Sets music volume. - * + * * \param volume Volume value */ void setMusicVolume(int volume); |