summaryrefslogtreecommitdiffstats
path: root/src/game-server/monster.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game-server/monster.cpp')
-rw-r--r--src/game-server/monster.cpp170
1 files changed, 71 insertions, 99 deletions
diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp
index 30c38da..26dc95f 100644
--- a/src/game-server/monster.cpp
+++ b/src/game-server/monster.cpp
@@ -47,12 +47,20 @@ struct MonsterTargetEventDispatch: EventDispatch
static MonsterTargetEventDispatch monsterTargetEventDispatch;
+MonsterClass::~MonsterClass()
+{
+ for (std::vector<AttackInfo *>::iterator it = mAttacks.begin(),
+ it_end = mAttacks.end(); it != it_end; ++it)
+ {
+ delete *it;
+ }
+}
+
Monster::Monster(MonsterClass *specy):
Being(OBJECT_MONSTER),
mSpecy(specy),
mTargetListener(&monsterTargetEventDispatch),
- mOwner(NULL),
- mCurrentAttack(NULL)
+ mOwner(NULL)
{
LOG_DEBUG("Monster spawned! (id: " << mSpecy->getId() << ").");
@@ -89,11 +97,14 @@ Monster::Monster(MonsterClass *specy):
setAttribute(it2->first,
mutation ?
- attr * (100 + (rand()%(mutation << 1)) - mutation) / 100.0 :
+ attr * (100 + (rand() % (mutation * 2)) - mutation) / 100.0 :
attr);
}
}
+ mDamageMutation = mutation ?
+ (100 + (rand() % (mutation * 2)) - mutation) / 100.0 : 1;
+
setSize(specy->getSize());
setGender(specy->getGender());
@@ -104,6 +115,14 @@ Monster::Monster(MonsterClass *specy):
mAttackPositions.push_back(AttackPosition(0, -dist, DOWN));
mAttackPositions.push_back(AttackPosition(0, dist, UP));
+ // Take attacks from specy
+ std::vector<AttackInfo *> &attacks = specy->getAttackInfos();
+ for (std::vector<AttackInfo *>::iterator it = attacks.begin(),
+ it_end = attacks.end(); it != it_end; ++it)
+ {
+ addAttack(*it);
+ }
+
// Load default script
loadScript(specy->getScript());
}
@@ -143,47 +162,47 @@ void Monster::update()
script->execute();
}
- // Cancel the rest when we are currently performing an attack
- if (!mAttackTimeout.expired())
- return;
-
refreshTarget();
- if (!mTarget)
+ // Cancel the rest when we have a target
+ if (mTarget)
+ return;
+
+ // We have no target - let's wander around
+ if (mStrollTimeout.expired() && getPosition() == getDestination())
{
- // We have no target - let's wander around
- if (mStrollTimeout.expired() && getPosition() == getDestination())
+ if (mKillStealProtectedTimeout.expired())
{
- if (mKillStealProtectedTimeout.expired())
+ unsigned range = mSpecy->getStrollRange();
+ if (range)
{
- unsigned range = mSpecy->getStrollRange();
- if (range)
- {
- Point randomPos(rand() % (range * 2 + 1)
- - range + getPosition().x,
- rand() % (range * 2 + 1)
- - range + getPosition().y);
- // Don't allow negative destinations, to avoid rounding
- // problems when divided by tile size
- if (randomPos.x >= 0 && randomPos.y >= 0)
- setDestination(randomPos);
- }
- mStrollTimeout.set(10 + rand() % 10);
+ Point randomPos(rand() % (range * 2 + 1)
+ - range + getPosition().x,
+ rand() % (range * 2 + 1)
+ - range + getPosition().y);
+ // Don't allow negative destinations, to avoid rounding
+ // problems when divided by tile size
+ if (randomPos.x >= 0 && randomPos.y >= 0)
+ setDestination(randomPos);
}
+ mStrollTimeout.set(10 + rand() % 10);
}
}
-
- if (mAction == ATTACK)
- processAttack();
}
void Monster::refreshTarget()
{
+ // We are dead and sadly not possible to keep attacking :(
+ if (mAction == DEAD)
+ return;
+
// Check potential attack positions
- Being *bestAttackTarget = mTarget = NULL;
int bestTargetPriority = 0;
+ Being *bestTarget = 0;
Point bestAttackPosition;
- BeingDirection bestAttackDirection = DOWN;
+
+ // reset Target. We will find a new one if possible
+ mTarget = 0;
// Iterate through objects nearby
int aroundArea = Configuration::getValue("game_visualRange", 448);
@@ -229,60 +248,28 @@ void Monster::refreshTarget()
targetPriority);
if (posPriority > bestTargetPriority)
{
- bestAttackTarget = mTarget = target;
bestTargetPriority = posPriority;
+ bestTarget = target;
bestAttackPosition = attackPosition;
- bestAttackDirection = j->direction;
}
}
}
-
- // Check if an enemy has been found
- if (bestAttackTarget)
+ if (bestTarget)
{
- // Check which attacks have a chance to hit the target
- MonsterAttacks allAttacks = mSpecy->getAttacks();
- std::map<int, MonsterAttack *> workingAttacks;
- int prioritySum = 0;
-
- const int distX = getPosition().x - bestAttackTarget->getPosition().x;
- const int distY = getPosition().y - bestAttackTarget->getPosition().y;
- const int distSquare = (distX * distX + distY * distY);
-
- for (MonsterAttacks::iterator i = allAttacks.begin();
- i != allAttacks.end();
- i++)
+ mTarget = bestTarget;
+ if (bestAttackPosition == getPosition())
{
- int maxDist = (*i)->range + bestAttackTarget->getSize();
-
- if (maxDist * maxDist >= distSquare)
- {
- prioritySum += (*i)->priority;
- workingAttacks[prioritySum] = (*i);
- }
- }
-
- if (workingAttacks.empty() || !prioritySum)
- { //when no attack can hit move closer to attack position
- setDestination(bestAttackPosition);
+ mAction = ATTACK;
+ updateDirection(getPosition(), mTarget->getPosition());
}
else
{
- // Prepare for using a random attack which can hit the enemy
- // Stop movement
- setDestination(getPosition());
- // Turn into direction of enemy
- setDirection(bestAttackDirection);
- // Perform a random attack based on priority
- mCurrentAttack =
- workingAttacks.upper_bound(rand()%prioritySum)->second;
- setAction(ATTACK);
- raiseUpdateFlags(UPDATEFLAG_ATTACK);
+ setDestination(bestAttackPosition);
}
}
}
-void Monster::processAttack()
+void Monster::processAttack(Attack &attack)
{
if (!mTarget)
{
@@ -290,37 +277,25 @@ void Monster::processAttack()
return;
}
- if (!mCurrentAttack)
- return;
-
- mAttackTimeout.set(mCurrentAttack->aftDelay
- + mCurrentAttack->preDelay);
-
- float damageFactor = mCurrentAttack->damageFactor;
-
- Damage dmg;
+ Damage dmg = attack.getAttackInfo()->getDamage();
dmg.skill = 0;
- dmg.base = getModifiedAttribute(MOB_ATTR_PHY_ATK_MIN) * damageFactor;
- dmg.delta = getModifiedAttribute(MOB_ATTR_PHY_ATK_DELTA) * damageFactor;
- dmg.cth = getModifiedAttribute(ATTR_ACCURACY);
- dmg.element = mCurrentAttack->element;
- dmg.range = mCurrentAttack->range;
+ dmg.base *= mDamageMutation;
+ dmg.delta *= mDamageMutation;
+
+ int hit = performAttack(mTarget, attack.getAttackInfo()->getDamage());
- int hit = performAttack(mTarget, dmg);
+ const Script::Ref &scriptCallback =
+ attack.getAttackInfo()->getScriptCallback();
- if (!mCurrentAttack->scriptEvent.empty() && hit > -1)
+ if (scriptCallback.isValid() && hit > -1)
{
- Script::Ref function = mSpecy->getEventCallback(mCurrentAttack->scriptEvent);
- if (function.isValid())
- {
- Script *script = ScriptManager::currentState();
- script->setMap(getMap());
- script->prepare(function);
- script->push(this);
- script->push(mTarget);
- script->push(hit);
- script->execute();
- }
+ Script *script = ScriptManager::currentState();
+ script->setMap(getMap());
+ script->prepare(scriptCallback);
+ script->push(this);
+ script->push(mTarget);
+ script->push(hit);
+ script->execute();
}
}
@@ -513,9 +488,6 @@ bool Monster::recalculateBaseAttribute(unsigned int attr)
{
// Those a set only at load time.
case ATTR_MAX_HP:
- case MOB_ATTR_PHY_ATK_MIN:
- case MOB_ATTR_PHY_ATK_DELTA:
- case MOB_ATTR_MAG_ATK:
case ATTR_DODGE:
case ATTR_MAGIC_DODGE:
case ATTR_ACCURACY: