diff options
author | Erik Schilling <ablu.erikschilling@googlemail.com> | 2012-06-10 15:11:01 +0200 |
---|---|---|
committer | Erik Schilling <ablu.erikschilling@googlemail.com> | 2013-01-08 16:58:57 +0100 |
commit | 6f287f239e9d94707735b183d6c6b89eea9fef20 (patch) | |
tree | 694427dbff77f73a1a3a4f84b4f53269a4763f74 /src/game-server/being.cpp | |
parent | 0f0004ff3e286270c0425642a5669661ef6cb592 (diff) | |
download | manaserv-6f287f239e9d94707735b183d6c6b89eea9fef20.tar.gz manaserv-6f287f239e9d94707735b183d6c6b89eea9fef20.tar.bz2 manaserv-6f287f239e9d94707735b183d6c6b89eea9fef20.tar.xz manaserv-6f287f239e9d94707735b183d6c6b89eea9fef20.zip |
Work on (Auto)Attack system.
During the implementation bjorn and I agreed to limit the number of attacks that
can be used in the same tick to one. This makes a lot of stuff easier and the
client cannot display two frames at the same time
Things done:
- Implemented setting of attacks when equipping/unequipping items
- Single place where the xml attack node is parsed
- Finished attack logic
- Unified the attack handling of monsters and characters
- Added a global cooldown after attack use
(not only for next use of same attack)
- Removed the temponary attributes for the monster attack values
- Priorities for all attacks
- Rewrote the attack core:
- Attacks now have this attributes:
- warmup -> time a attack needs after starting it to actually deal the damage
- cooldown -> time a attack needs after dealing damage before another attack
can be used
- reuse -> time before the same attack can be used again
- If no attack is performed at the moment the following is done:
- make a list with all ready attacks
- check for attack that has the necessarily range and highest priority
- start this attack (inform client about it)
- when warmup is finished -> trigger damage
- when cooldown is finished -> allow to use other (or the same if reusetimer
allows) attacks
TODO:
- sync client with this to allow better timed animations
Diffstat (limited to 'src/game-server/being.cpp')
-rw-r--r-- | src/game-server/being.cpp | 86 |
1 files changed, 70 insertions, 16 deletions
diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp index 7ae01a00..2064cfc5 100644 --- a/src/game-server/being.cpp +++ b/src/game-server/being.cpp @@ -30,6 +30,7 @@ #include "game-server/eventlistener.h" #include "game-server/mapcomposite.h" #include "game-server/effect.h" +#include "game-server/skillmanager.h" #include "game-server/statuseffect.h" #include "game-server/statusmanager.h" #include "utils/logger.h" @@ -40,6 +41,7 @@ Being::Being(EntityType type): mAction(STAND), mTarget(NULL), mGender(GENDER_UNSPECIFIED), + mCurrentAttack(0), mDirection(DOWN) { const AttributeManager::AttributeScope &attr = attributeManager->getAttributeScope(BeingScope); @@ -185,6 +187,65 @@ void Being::died() } } +void Being::processAttacks() +{ + if (mAction != ATTACK || !mTarget) + return; + + // Ticks attacks even when not attacking to permit cooldowns and warmups. + std::vector<Attack *> attacksReady; + mAttacks.getUsuableAttacks(&attacksReady); + + if (Attack *triggerableAttack = mAttacks.getTriggerableAttack()) + { + processAttack(*triggerableAttack); + mAttacks.markAttackAsTriggered(); + } + + // Deal with the ATTACK action. + if (attacksReady.empty()) + return; + + Attack *highestPriorityAttack = 0; + // Performs all ready attacks. + for (std::vector<Attack *>::const_iterator it = attacksReady.begin(), + it_end = attacksReady.end(); it != it_end; ++it) + { + // check if target is in range using the pythagorean theorem + int distx = this->getPosition().x - mTarget->getPosition().x; + int disty = this->getPosition().y - mTarget->getPosition().y; + int distSquare = (distx * distx + disty * disty); + AttackInfo *info = (*it)->getAttackInfo(); + int maxDist = info->getDamage().range + getSize(); + + if (distSquare <= maxDist * maxDist && + (!highestPriorityAttack || + highestPriorityAttack->getAttackInfo()->getPriority() + < info->getPriority())) + { + highestPriorityAttack = *it; + } + } + if (highestPriorityAttack) + { + mAttacks.startAttack(highestPriorityAttack); + mCurrentAttack = highestPriorityAttack; + setDestination(getPosition()); + // TODO: Turn into direction of enemy + raiseUpdateFlags(UPDATEFLAG_ATTACK); + } +} + +void Being::addAttack(AttackInfo *attackInfo) +{ + mAttacks.add(attackInfo); +} + +void Being::removeAttack(AttackInfo *attackInfo) +{ + mAttacks.remove(attackInfo); +} + void Being::setDestination(const Point &dst) { mDst = dst; @@ -409,7 +470,7 @@ int Being::directionToAngle(int direction) } } -int Being::performAttack(Being *target, const Damage &damage) +int Being::performAttack(Being *target, const Damage &dmg) { // check target legality if (!target @@ -423,25 +484,11 @@ int Being::performAttack(Being *target, const Damage &damage) && getType() == OBJECT_CHARACTER) return -1; - // check if target is in range using the pythagorean theorem - int distx = this->getPosition().x - target->getPosition().x; - int disty = this->getPosition().y - target->getPosition().y; - int distSquare = (distx * distx + disty * disty); - int maxDist = damage.range + target->getSize(); - if (maxDist * maxDist < distSquare) - return -1; - - // Note: The auto-attack system will handle the delay between two attacks. - - return target->damage(this, damage); + return target->damage(this, dmg); } void Being::setAction(BeingAction action) { - // Stops the auto-attacks when changing action - if (mAction == ATTACK && action != ATTACK) - mAttacks.stop(); - mAction = action; if (action != ATTACK && // The players are informed about these actions action != WALK) // by other messages @@ -692,6 +739,8 @@ void Being::update() // Check if being died if (getModifiedAttribute(ATTR_HP) <= 0 && mAction != DEAD) died(); + + processAttacks(); } void Being::inserted() @@ -707,3 +756,8 @@ void Being::setGender(BeingGender gender) { mGender = gender; } + +void Being::processAttack(Attack &attack) +{ + performAttack(mTarget, attack.getAttackInfo()->getDamage()); +} |