summaryrefslogtreecommitdiff
path: root/src/game-server/attack.cpp
diff options
context:
space:
mode:
authorErik Schilling <ablu.erikschilling@googlemail.com>2012-06-10 15:11:01 +0200
committerErik Schilling <ablu.erikschilling@googlemail.com>2012-07-07 21:56:14 +0200
commit4cf22065e9f2b24eb481959aa65667ef1bd0724d (patch)
treeb7bfe1214fd1a0c6bfe99be35204c537a050cac9 /src/game-server/attack.cpp
parent576431fb11a3dbc256fbd1f5a853a5be719f1879 (diff)
downloadmanaserv-4cf22065e9f2b24eb481959aa65667ef1bd0724d.tar.gz
manaserv-4cf22065e9f2b24eb481959aa65667ef1bd0724d.tar.bz2
manaserv-4cf22065e9f2b24eb481959aa65667ef1bd0724d.tar.xz
manaserv-4cf22065e9f2b24eb481959aa65667ef1bd0724d.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/attack.cpp')
-rw-r--r--src/game-server/attack.cpp122
1 files changed, 89 insertions, 33 deletions
diff --git a/src/game-server/attack.cpp b/src/game-server/attack.cpp
index 4f04255f..e807df6a 100644
--- a/src/game-server/attack.cpp
+++ b/src/game-server/attack.cpp
@@ -20,58 +20,114 @@
#include "attack.h"
-void Attacks::add(const Attack &attack)
+#include "common/defines.h"
+
+#include "game-server/character.h"
+#include "game-server/skillmanager.h"
+
+AttackInfo *AttackInfo::readAttackNode(xmlNodePtr node)
{
- mAttacks.push_back(attack);
- // Slow, but safe.
- mAttacks.sort();
+ std::string skill = XML::getProperty(node, "skill", std::string());
+ unsigned skillId;
+ if (utils::isNumeric(skill))
+ {
+ skillId = utils::stringToInt(skill);
+ }
+ else
+ {
+ skillId = skillManager->getId(skill);
+ if (skillId == 0)
+ {
+ LOG_WARN("Error parsing Attack node: Invalid skill " << skill
+ << " taking default skill");
+ skillId = skillManager->getDefaultSkillId();
+ }
+ }
+ unsigned id = XML::getProperty(node, "id", 0);
+ unsigned priority = XML::getProperty(node, "priority", 0);
+ unsigned warmupTime = XML::getProperty(node, "warmuptime", 0);
+ unsigned cooldownTime = XML::getProperty(node, "cooldowntime", 0);
+ unsigned reuseTime = XML::getProperty(node, "reusetime", 0);
+ unsigned short baseDamange = XML::getProperty(node, "basedamage", 0);
+ unsigned short deltaDamage = XML::getProperty(node, "deltadamage", 0);
+ unsigned short chanceToHit = XML::getProperty(node, "chancetohit", 0);
+ unsigned short range = XML::getProperty(node, "range", 0);
+ Element element = elementFromString(
+ XML::getProperty(node, "element", "neutral"));
+ DamageType type = damageTypeFromString(
+ XML::getProperty(node, "type", "other"));
+
+ Damage dmg;
+ dmg.id = id;
+ dmg.base = baseDamange;
+ dmg.delta = deltaDamage;
+ dmg.cth = chanceToHit;
+ dmg.range = range;
+ dmg.element = element;
+ dmg.type = type;
+ AttackInfo *attack = new AttackInfo(priority, dmg, warmupTime, cooldownTime,
+ reuseTime);
+ return attack;
}
-void Attacks::clear()
+void Attacks::add(AttackInfo *attackInfo)
{
- mAttacks.clear();
+ mAttacks.push_back(Attack(attackInfo));
}
-void Attacks::stop()
+void Attacks::remove(AttackInfo *attackInfo)
{
- for (std::list<Attack>::iterator it = mAttacks.begin();
- it != mAttacks.end(); ++it)
+ for (std::vector<Attack>::iterator it = mAttacks.begin(),
+ it_end = mAttacks.end(); it != it_end; ++it)
{
- it->halt();
+ if ((*it).getAttackInfo() == attackInfo)
+ {
+ if (mCurrentAttack && mCurrentAttack->getAttackInfo() == attackInfo)
+ mCurrentAttack = 0;
+ mAttacks.erase(it);
+ return;
+ }
}
- mActive = false;
}
-void Attacks::start()
+void Attacks::markAttackAsTriggered()
{
- for (std::list<Attack>::iterator it = mAttacks.begin();
- it != mAttacks.end(); ++it)
- {
- // If the attack is inactive, we hard reset it.
- if (!it->getTimer())
- it->reset();
- else
- it->softReset();
- }
- mActive = true;
+ mCurrentAttack->markAsTriggered();
+ mCurrentAttack = 0;
+}
+
+Attack *Attacks::getTriggerableAttack()
+{
+ if (!mCurrentAttack)
+ return 0;
+
+ int warmupTime = mCurrentAttack->getAttackInfo()->getWarmupTime();
+ if (mAttackTimer.remaining() <= warmupTime)
+ return mCurrentAttack;
+
+ return 0;
+}
+
+void Attacks::startAttack(Attack *attack)
+{
+ mCurrentAttack = attack;
+ mAttackTimer.set(attack->getAttackInfo()->getWarmupTime() +
+ attack->getAttackInfo()->getCooldownTime());
}
-void Attacks::tick(std::list<Attack> *ret)
+void Attacks::tick(std::vector<Attack *> *ret)
{
- for (std::list<Attack>::iterator it = mAttacks.begin();
+ // we have a current Attack
+ if (!mAttackTimer.expired() && mCurrentAttack)
+ return;
+ for (std::vector<Attack>::iterator it = mAttacks.begin();
it != mAttacks.end(); ++it)
{
- if (it->tick())
- {
- if (mActive)
- it->reset();
- else
- it->halt();
- }
+ Attack &attack = *it;
- if (ret && it->isReady())
+ if (ret && attack.isUsuable())
{
- ret->push_back(*it);
+ ret->push_back(&attack);
}
}
}