Commit ae898aa1a5175b2b08f7248e4cd89bf61bc8e4be

  • avatar
  • Yohann Ferreira <yohann_dot_ferreira_at_orange_dot_efer>
  • Thu Jul 29 20:20:51 CEST 2010
Changed the items loading to handle a new 'attack-action' parameter.

The old behaviour was to load the weapon-type value and do many
unnecessary checks and transformation on it:
The weapon-type was transformed using hard-coded values into
an integer enum value.
The exact same thing was done on the opposite side in the animation
files before comparing the two.
As both data were string values, I simplified all of it by using
the value taken in items.xml to call the corresponding action.

This now also permit to set up new attack animation in items.xml
and in the playerset.xml without having the need
to modify the client code.

Last but not least, the weapon-type value was used by both the skills
and the actions and avoided the possibility to set up a definite action
for a weapon-type.

Note: The weapon-type parameter will become deprecated for the server
in favor of a 'skill' parameter to reflect more it's actual use.

This patch is the first step to fix Manasource issue: #157.
  
5151 mSprite->incRef();
5252
5353 // Play the stand animation by default
54 play(ACTION_STAND);
54 play(SpriteAction::STAND);
5555}
5656
5757AnimatedSprite *AnimatedSprite::load(const std::string &filename, int variant)
8181 return ret;
8282}
8383
84bool AnimatedSprite::play(SpriteAction spriteAction)
84bool AnimatedSprite::play(std::string spriteAction)
8585{
8686 Action *action = mSprite->getAction(spriteAction);
8787 if (!action)
122122 if (!updateCurrentAnimation(dt))
123123 {
124124 // Animation finished, reset to default
125 play(ACTION_STAND);
125 play(SpriteAction::STAND);
126126 }
127127
128128 // Make sure something actually changed
  
5656
5757 bool reset();
5858
59 bool play(SpriteAction action);
59 bool play(std::string action);
6060
6161 bool update(int time);
6262
src/being.cpp
(22 / 18)
  
249249 mPath = path;
250250
251251 if ((Net::getNetworkType() == ServerInfo::TMWATHENA) &&
252 mAction != WALK && mAction != DEAD)
252 mAction != MOVE && mAction != DEAD)
253253 {
254254 nextTile();
255255 mActionTime = tick_time;
550550
551551void Being::setAction(Action action, int attackType)
552552{
553 SpriteAction currentAction = ACTION_INVALID;
553 std::string currentAction = SpriteAction::INVALID;
554554
555555 switch (action)
556556 {
557 case WALK:
558 currentAction = ACTION_WALK;
557 case MOVE:
558 currentAction = SpriteAction::MOVE;
559 // Note: When adding a run action,
560 // Differentiate walk and run with action name,
561 // while using only the ACTION_MOVE.
559562 break;
560563 case SIT:
561 currentAction = ACTION_SIT;
564 currentAction = SpriteAction::SIT;
562565 break;
563566 case ATTACK:
564567 if (mEquippedWeapon)
565568 {
566 currentAction = mEquippedWeapon->getWeaponAttackType();
569 currentAction = mEquippedWeapon->getAttackAction();
567570 reset();
568571 }
569572 else
601601
602602 break;
603603 case HURT:
604 //currentAction = ACTION_HURT; // Buggy: makes the player stop
604 //currentAction = SpriteAction::HURT;// Buggy: makes the player stop
605605 // attacking and unable to attack
606 // again until he moves
606 // again until he moves.
607 // TODO: fix this!
607608 break;
608609 case DEAD:
609 currentAction = ACTION_DEAD;
610 currentAction = SpriteAction::DEAD;
610611 sound.playSfx(mInfo->getSound(SOUND_EVENT_DIE));
611612 break;
612613 case STAND:
613 currentAction = ACTION_STAND;
614 currentAction = SpriteAction::STAND;
614615 break;
615616 }
616617
617 if (currentAction != ACTION_INVALID)
618 if (currentAction != SpriteAction::INVALID)
618619 {
619620 play(currentAction);
620621 mAction = action;
621622 }
622623
623 if (currentAction != ACTION_WALK)
624 if (currentAction != SpriteAction::MOVE)
624625 mActionTime = tick_time;
625626}
626627
683683
684684 mX = pos.x;
685685 mY = pos.y;
686 setAction(WALK);
686 setAction(MOVE);
687687 mActionTime += (int)(mWalkSpeed.x / 10);
688688}
689689
747747 else
748748 setPosition(mPos + diff);
749749
750 if (mAction != WALK)
751 setAction(WALK);
750 if (mAction != MOVE)
751 setAction(MOVE);
752752
753753 // Update the player sprite direction.
754754 // N.B.: We only change this if the distance is more than one pixel.
777777 // remove it and go to the next one.
778778 mPath.pop_front();
779779 }
780 else if (mAction == WALK)
780 else if (mAction == MOVE)
781781 {
782782 setAction(STAND);
783783 }
794794 case HURT:
795795 break;
796796
797 case WALK:
797 case MOVE:
798798 if ((int) ((get_elapsed_time(mActionTime) * frameCount)
799799 / getWalkSpeed().x) >= frameCount)
800800 nextTile();
945945int Being::getOffset(char pos, char neg) const
946946{
947947 // Check whether we're walking in the requested direction
948 if (mAction != WALK || !(mDirection & (pos | neg)))
948 if (mAction != MOVE || !(mDirection & (pos | neg)))
949949 return 0;
950950
951951 int offset = 0;
  
7373 enum Action
7474 {
7575 STAND,
76 WALK,
76 MOVE,
7777 ATTACK,
7878 SIT,
7979 DEAD,
  
6767 return ret;
6868}
6969
70bool CompoundSprite::play(SpriteAction action)
70bool CompoundSprite::play(std::string action)
7171{
7272 bool ret = false;
7373
  
3636
3737 virtual bool reset();
3838
39 virtual bool play(SpriteAction action);
39 virtual bool play(std::string action);
4040
4141 virtual bool update(int time);
4242
  
1919 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2020 */
2121
22#ifndef SKILL_H
23#define SKILL_H
22#ifndef SKILLDIALOG_H
23#define SKILLDIALOG_H
2424
2525#include "guichanfwd.h"
2626
  
3737 bool reset()
3838 { return false; }
3939
40 bool play(SpriteAction action)
40 bool play(std::string action)
4141 { return false; }
4242
4343 bool update(int time)
  
776776 mWalkingDir = dir;
777777
778778 // If we're not already walking, start walking.
779 if (mAction != WALK && dir)
779 if (mAction != MOVE && dir)
780780 {
781781 startWalking(dir);
782782 }
783 else if (mAction == WALK && (Net::getNetworkType() == ServerInfo::MANASERV))
783 else if (mAction == MOVE && (Net::getNetworkType() == ServerInfo::MANASERV))
784784 {
785785 nextTile(dir);
786786 }
793793 if (!mMap || !dir)
794794 return;
795795
796 if (mAction == WALK && !mPath.empty())
796 if (mAction == MOVE && !mPath.empty())
797797 {
798798 // Just finish the current action, otherwise we get out of sync
799799 if (Net::getNetworkType() == ServerInfo::MANASERV)
848848
849849void LocalPlayer::stopWalking(bool sendToServer)
850850{
851 if (mAction == WALK && mWalkingDir)
851 if (mAction == MOVE && mWalkingDir)
852852 {
853853 mWalkingDir = 0;
854854 mLocalWalkTime = 0;
  
641641 x = msg.readInt16();
642642 y = msg.readInt16();
643643 dstBeing->setTileCoords(x, y);
644 if (dstBeing->getCurrentAction() == Being::WALK)
644 if (dstBeing->getCurrentAction() == Being::MOVE)
645645 dstBeing->setAction(Being::STAND);
646646 }
647647 }
  
9090
9191const Attack *BeingInfo::getAttack(int type) const
9292{
93 static Attack *empty = new Attack(ACTION_ATTACK, "", "");
93 static Attack *empty = new Attack(SpriteAction::ATTACK, "", "");
9494
9595 Attacks::const_iterator i = mAttacks.find(type);
9696 return (i == mAttacks.end()) ? empty : (*i).second;
9797}
9898
99void BeingInfo::addAttack(int id, SpriteAction action,
99void BeingInfo::addAttack(int id, std::string action,
100100 const std::string &particleEffect,
101101 const std::string &missileParticle)
102102{
  
3232#include <vector>
3333
3434struct Attack {
35 SpriteAction action;
35 std::string action;
3636 std::string particleEffect;
3737 std::string missileParticle;
3838
39 Attack(SpriteAction action, std::string particleEffect,
39 Attack(std::string action, std::string particleEffect,
4040 std::string missileParticle)
4141 {
4242 this->action = action;
9595
9696 const std::string &getSound(SoundEvent event) const;
9797
98 void addAttack(int id, SpriteAction action,
98 void addAttack(int id, std::string action,
9999 const std::string &particleEffect,
100100 const std::string &missileParticle);
101101
  
8585 else return ITEM_UNUSABLE;
8686}
8787
88static WeaponType weaponTypeFromString(const std::string &name)
89{
90 if (name=="knife") return WPNTYPE_KNIFE;
91 else if (name=="sword") return WPNTYPE_SWORD;
92 else if (name=="polearm") return WPNTYPE_POLEARM;
93 else if (name=="staff") return WPNTYPE_STAFF;
94 else if (name=="whip") return WPNTYPE_WHIP;
95 else if (name=="bow") return WPNTYPE_BOW;
96 else if (name=="shooting") return WPNTYPE_SHOOTING;
97 else if (name=="mace") return WPNTYPE_MACE;
98 else if (name=="axe") return WPNTYPE_AXE;
99 else if (name=="thrown") return WPNTYPE_THROWN;
100
101 else return WPNTYPE_NONE;
102}
103
10488static std::string normalized(const std::string &name)
10589{
10690 std::string normalized = name;
137137 std::string name = XML::getProperty(node, "name", "");
138138 std::string image = XML::getProperty(node, "image", "");
139139 std::string description = XML::getProperty(node, "description", "");
140 int weaponType = weaponTypeFromString(XML::getProperty(node, "weapon-type", ""));
140 std::string attackAction = XML::getProperty(node, "attack-action", "");
141141 int attackRange = XML::getProperty(node, "attack-range", 0);
142142 std::string missileParticle = XML::getProperty(node, "missile-particle", "");
143143
151151 itemInfo->setType(itemTypeFromString(typeStr));
152152 itemInfo->setView(view);
153153 itemInfo->setWeight(weight);
154 itemInfo->setWeaponType(weaponType);
154 itemInfo->setAttackAction(attackAction);
155155 itemInfo->setAttackRange(attackRange);
156156 itemInfo->setMissileParticle(missileParticle);
157157
215215 }
216216 }
217217
218 if (weaponType > 0)
218 if (!attackAction.empty())
219219 if (attackRange == 0)
220220 logger->log("ItemDB: Missing attack range from weapon %i!", id);
221221
  
4141 }
4242}
4343
44void ItemInfo::setWeaponType(int type)
44void ItemInfo::setAttackAction(std::string attackAction)
4545{
46 // See server item.hpp file for type values.
47 switch (type)
48 {
49 case WPNTYPE_NONE:
50 mWeaponAttackType = ACTION_DEFAULT;
51 break;
52 case WPNTYPE_KNIFE:
53 case WPNTYPE_SWORD:
54 mWeaponAttackType = ACTION_ATTACK_STAB;
55 break;
56 case WPNTYPE_THROWN:
57 mWeaponAttackType = ACTION_ATTACK_THROW;
58 break;
59 case WPNTYPE_BOW:
60 mWeaponAttackType = ACTION_ATTACK_BOW;
61 break;
62 case WPNTYPE_POLEARM:
63 mWeaponAttackType = ACTION_ATTACK_SWING;
64 break;
65 default:
66 mWeaponAttackType = ACTION_ATTACK;
67 }
46 if (attackAction.empty())
47 mAttackAction = SpriteAction::ATTACK; // (Equal to unarmed animation)
48 else
49 mAttackAction = attackAction;
6850}
6951
7052void ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename)
  
9090};
9191
9292/**
93 * Enumeration of available weapon's types.
94 */
95enum WeaponType
96{
97 WPNTYPE_NONE = 0,
98 WPNTYPE_KNIFE,
99 WPNTYPE_SWORD,
100 WPNTYPE_POLEARM,
101 WPNTYPE_STAFF,
102 WPNTYPE_WHIP,
103 WPNTYPE_BOW,
104 WPNTYPE_SHOOTING,
105 WPNTYPE_MACE,
106 WPNTYPE_AXE,
107 WPNTYPE_THROWN
108};
109
110/**
11193 * Defines a class for storing item infos. This includes information used when
11294 * the item is equipped.
11395 */
104104 mWeight(0),
105105 mView(0),
106106 mId(0),
107 mWeaponAttackType(ACTION_DEFAULT)
107 mAttackAction(SpriteAction::INVALID)
108108 {
109109 }
110110
162162
163163 const std::string &getSprite(Gender gender) const;
164164
165 void setWeaponType(int);
165 void setAttackAction(std::string attackAction);
166166
167167 // Handlers for seting and getting the string used for particles when attacking
168168 void setMissileParticle(std::string s) { mMissileParticle = s; }
169169
170170 std::string getMissileParticle() const { return mMissileParticle; }
171171
172 SpriteAction getWeaponAttackType() const
173 { return mWeaponAttackType; }
172 std::string getAttackAction() const
173 { return mAttackAction; }
174174
175175 int getAttackRange() const
176176 { return mAttackRange; }
193193 int mView; /**< Item ID of how this item looks. */
194194 int mId; /**< Item ID */
195195
196 // Equipment related members
197 SpriteAction mWeaponAttackType; /**< Attack type, in case of weapon. */
196 // Equipment related members.
197 /** Attack type, in case of weapon.
198 * See SpriteAction in spritedef.h for more info.
199 * Attack action sub-types (bow, sword, ...) are defined in items.xml.
200 */
201 std::string mAttackAction;
198202 int mAttackRange; /**< Attack range, will be zero if non weapon. */
199203
200204 // Particle to be shown when weapon attacks
  
126126 const int id = XML::getProperty(spriteNode, "id", 0);
127127 const std::string particleEffect = XML::getProperty(
128128 spriteNode, "particle-effect", "");
129 SpriteAction spriteAction = SpriteDef::makeSpriteAction(
130 XML::getProperty(spriteNode, "action", "attack"));
129 const std::string spriteAction = XML::getProperty(spriteNode,
130 "action",
131 "attack");
131132 const std::string missileParticle = XML::getProperty(
132133 spriteNode, "missile-particle", "");
133134 currentInfo->addAttack(id, spriteAction,
  
3939SpriteReference *SpriteReference::Empty = new SpriteReference(
4040 paths.getStringValue("spriteErrorFile"), 0);
4141
42Action *SpriteDef::getAction(SpriteAction action) const
42Action *SpriteDef::getAction(std::string action) const
4343{
4444 Actions::const_iterator i = mActions.find(action);
4545
4646 if (i == mActions.end())
4747 {
48 logger->log("Warning: no action \"%u\" defined!", action);
48 logger->log("Warning: no action \"%s\" defined!", action.c_str());
4949 return NULL;
5050 }
5151
8484 return def;
8585}
8686
87void SpriteDef::substituteAction(std::string complete, std::string with)
88{
89 if (mActions.find(complete) == mActions.end())
90 {
91 Actions::iterator i = mActions.find(with);
92 if (i != mActions.end())
93 {
94 mActions[complete] = i->second;
95 }
96 }
97}
98
8799void SpriteDef::substituteActions()
88100{
89 substituteAction(ACTION_STAND, ACTION_DEFAULT);
90 substituteAction(ACTION_WALK, ACTION_STAND);
91 substituteAction(ACTION_WALK, ACTION_RUN);
92 substituteAction(ACTION_ATTACK, ACTION_STAND);
93 substituteAction(ACTION_ATTACK_SWING, ACTION_ATTACK);
94 substituteAction(ACTION_ATTACK_STAB, ACTION_ATTACK_SWING);
95 substituteAction(ACTION_ATTACK_BOW, ACTION_ATTACK_STAB);
96 substituteAction(ACTION_ATTACK_THROW, ACTION_ATTACK_SWING);
97 substituteAction(ACTION_CAST_MAGIC, ACTION_ATTACK_SWING);
98 substituteAction(ACTION_USE_ITEM, ACTION_CAST_MAGIC);
99 substituteAction(ACTION_SIT, ACTION_STAND);
100 substituteAction(ACTION_SLEEP, ACTION_SIT);
101 substituteAction(ACTION_HURT, ACTION_STAND);
102 substituteAction(ACTION_DEAD, ACTION_HURT);
101 substituteAction(SpriteAction::STAND, SpriteAction::DEFAULT);
102 substituteAction(SpriteAction::MOVE, SpriteAction::STAND);
103 substituteAction(SpriteAction::ATTACK, SpriteAction::STAND);
104 substituteAction(SpriteAction::CAST_MAGIC, SpriteAction::ATTACK);
105 substituteAction(SpriteAction::USE_ITEM, SpriteAction::CAST_MAGIC);
106 substituteAction(SpriteAction::SIT, SpriteAction::STAND);
107 substituteAction(SpriteAction::SLEEP, SpriteAction::SIT);
108 substituteAction(SpriteAction::HURT, SpriteAction::STAND);
109 substituteAction(SpriteAction::DEAD, SpriteAction::HURT);
103110}
104111
105112void SpriteDef::loadSprite(xmlNodePtr spriteNode, int variant,
178178 }
179179 ImageSet *imageSet = si->second;
180180
181 SpriteAction actionType = makeSpriteAction(actionName);
182 if (actionType == ACTION_INVALID)
181 if (actionName == SpriteAction::INVALID)
183182 {
184183 logger->log("Warning: Unknown action \"%s\" defined in %s",
185184 actionName.c_str(), getIdPath().c_str());
186185 return;
187186 }
188187 Action *action = new Action;
189 mActions[actionType] = action;
188 mActions[actionName] = action;
190189
191190 // When first action set it as default direction
192 if (mActions.empty())
191 if (mActions.size() == 1)
193192 {
194 mActions[ACTION_DEFAULT] = action;
193 mActions[SpriteAction::DEFAULT] = action;
195194 }
196195
197196 // Load animations
303303 loadSprite(rootNode, 0);
304304}
305305
306void SpriteDef::substituteAction(SpriteAction complete, SpriteAction with)
307{
308 if (mActions.find(complete) == mActions.end())
309 {
310 Actions::iterator i = mActions.find(with);
311 if (i != mActions.end())
312 {
313 mActions[complete] = i->second;
314 }
315 }
316}
317
318306SpriteDef::~SpriteDef()
319307{
320308 // Actions are shared, so ensure they are deleted only once.
324324 {
325325 i->second->decRef();
326326 }
327}
328
329SpriteAction SpriteDef::makeSpriteAction(const std::string &action)
330{
331 if (action.empty() || action == "default")
332 return ACTION_DEFAULT;
333
334 if (action == "stand")
335 return ACTION_STAND;
336 else if (action == "walk")
337 return ACTION_WALK;
338 else if (action == "run")
339 return ACTION_RUN;
340 else if (action == "attack")
341 return ACTION_ATTACK;
342 else if (action == "attack_swing")
343 return ACTION_ATTACK_SWING;
344 else if (action == "attack_stab")
345 return ACTION_ATTACK_STAB;
346 else if (action == "attack_bow")
347 return ACTION_ATTACK_BOW;
348 else if (action == "attack_throw")
349 return ACTION_ATTACK_THROW;
350 else if (action == "special0")
351 return ACTION_SPECIAL_0;
352 else if (action == "special1")
353 return ACTION_SPECIAL_1;
354 else if (action == "special2")
355 return ACTION_SPECIAL_2;
356 else if (action == "special3")
357 return ACTION_SPECIAL_3;
358 else if (action == "special4")
359 return ACTION_SPECIAL_4;
360 else if (action == "special5")
361 return ACTION_SPECIAL_5;
362 else if (action == "special6")
363 return ACTION_SPECIAL_6;
364 else if (action == "special7")
365 return ACTION_SPECIAL_7;
366 else if (action == "special8")
367 return ACTION_SPECIAL_8;
368 else if (action == "special9")
369 return ACTION_SPECIAL_9;
370 else if (action == "cast_magic")
371 return ACTION_CAST_MAGIC;
372 else if (action == "use_item")
373 return ACTION_USE_ITEM;
374 else if (action == "sit")
375 return ACTION_SIT;
376 else if (action == "sleep")
377 return ACTION_SLEEP;
378 else if (action == "hurt")
379 return ACTION_HURT;
380 else if (action == "dead")
381 return ACTION_DEAD;
382 else
383 return ACTION_INVALID;
384327}
385328
386329SpriteDirection SpriteDef::makeSpriteDirection(const std::string &direction)
  
5454};
5555
5656typedef std::list<SpriteReference*>::const_iterator SpriteRefs;
57
57#if 0
5858enum SpriteAction
5959{
6060 ACTION_DEFAULT = 0,
8484 ACTION_DEAD,
8585 ACTION_INVALID
8686};
87
87#endif
88#if 1 // Aim to be reached
89/*
90 * Remember those are the main action.
91 * Action subtypes, e.g.: "attack_bow" are to be passed by items.xml after
92 * an ACTION_ATTACK call.
93 * Which special to be use to to be passed with the USE_SPECIAL call.
94 * Running, walking, ... is a sub-type of moving.
95 * ...
96 * Please don't add hard-coded subtypes here!
97 */
98namespace SpriteAction
99{
100 static const std::string DEFAULT = "stand";
101 static const std::string STAND = "stand";
102 static const std::string SIT = "sit";
103 static const std::string SLEEP = "sleep";
104 static const std::string DEAD = "dead";
105 static const std::string MOVE = "walk";
106 static const std::string ATTACK = "attack";
107 static const std::string HURT = "hurt";
108 static const std::string USE_SPECIAL = "special";
109 static const std::string CAST_MAGIC = "magic";
110 static const std::string USE_ITEM = "item";
111 static const std::string INVALID = "";
112};
113#endif
88114enum SpriteDirection
89115{
90116 DIRECTION_DEFAULT = 0,
135135 /**
136136 * Returns the specified action.
137137 */
138 Action *getAction(SpriteAction action) const;
138 Action *getAction(std::string action) const;
139139
140140 /**
141 * Converts a string into a SpriteAction enum.
142 */
143 static SpriteAction makeSpriteAction(const std::string &action);
144
145 /**
146141 * Converts a string into a SpriteDirection enum.
147142 */
148143 static SpriteDirection
191191 * When there are no animations defined for the action "complete", its
192192 * animations become a copy of those of the action "with".
193193 */
194 void substituteAction(SpriteAction complete, SpriteAction with);
194 void substituteAction(std::string complete, std::string with);
195195
196196 typedef std::map<std::string, ImageSet*> ImageSets;
197197 typedef ImageSets::iterator ImageSetIterator;
198198
199 typedef std::map<SpriteAction, Action*> Actions;
199 typedef std::map<std::string, Action*> Actions;
200200
201201 ImageSets mImageSets;
202202 Actions mActions;
  
4343 *
4444 * @returns true if the sprite changed, false otherwise
4545 */
46 virtual bool play(SpriteAction action) = 0;
46 virtual bool play(std::string action) = 0;
4747
4848 /**
4949 * Inform the animation of the passed time so that it can output the
  
7373 paths.getStringValue("sprites") + mIcon);
7474 if (false && sprite)
7575 {
76 sprite->play(ACTION_DEFAULT);
76 sprite->play(SpriteAction::DEFAULT);
7777 sprite->reset();
7878 }
7979 return sprite;
8080 }
8181}
8282
83SpriteAction StatusEffect::getAction()
83std::string StatusEffect::getAction()
8484{
8585 if (mAction.empty())
86 return ACTION_INVALID;
86 return SpriteAction::INVALID;
8787 else
88 return SpriteDef::makeSpriteAction(mAction);
88 return mAction;
8989}
9090
9191
  
5656 AnimatedSprite *getIcon();
5757
5858 /**
59 * Retrieves an action to perform, or ACTION_INVALID
59 * Retrieves an action to perform, or SpriteAction::INVALID
6060 */
61 SpriteAction getAction();
61 std::string getAction();
6262
6363 /**
6464 * Determines whether the particle effect should be restarted when the