diff options
author | Erik Schilling <ablu.erikschilling@googlemail.com> | 2013-04-03 14:32:57 +0200 |
---|---|---|
committer | Erik Schilling <ablu.erikschilling@googlemail.com> | 2013-04-03 21:52:03 +0200 |
commit | 4b57962ee4c10e48956c2888199605bebdb17b8f (patch) | |
tree | 261b141a1ad61a64e93a7b99a8c68debfb48d055 /src/game-server | |
parent | 4a8080dcf73dab2b6e62b8500fec3bb996bcbf17 (diff) | |
download | manaserv-4b57962ee4c10e48956c2888199605bebdb17b8f.tar.gz manaserv-4b57962ee4c10e48956c2888199605bebdb17b8f.tar.xz manaserv-4b57962ee4c10e48956c2888199605bebdb17b8f.zip |
Moved the Monster class to a Component
Things done:
- Allowed to create new Attributes outside of the protected scope of Being
- Moved Monster to MonsterComponent
- Some minor cleanup in the Attribute setting code of monsters
Diffstat (limited to 'src/game-server')
-rw-r--r-- | src/game-server/being.cpp | 7 | ||||
-rw-r--r-- | src/game-server/being.h | 13 | ||||
-rw-r--r-- | src/game-server/combatcomponent.cpp | 2 | ||||
-rw-r--r-- | src/game-server/commandhandler.cpp | 3 | ||||
-rw-r--r-- | src/game-server/component.h | 1 | ||||
-rw-r--r-- | src/game-server/monster.cpp | 136 | ||||
-rw-r--r-- | src/game-server/monster.h | 27 | ||||
-rw-r--r-- | src/game-server/monstercombatcomponent.cpp | 20 | ||||
-rw-r--r-- | src/game-server/monstercombatcomponent.h | 4 | ||||
-rw-r--r-- | src/game-server/spawnareacomponent.cpp | 3 | ||||
-rw-r--r-- | src/game-server/state.cpp | 21 |
11 files changed, 135 insertions, 102 deletions
diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp index 42d3404..2237f6a 100644 --- a/src/game-server/being.cpp +++ b/src/game-server/being.cpp @@ -400,6 +400,13 @@ void Being::setAttribute(unsigned id, double value) } } +void Being::createAttribute(unsigned id, const AttributeManager::AttributeInfo + &attributeInfo) +{ + mAttributes.insert(std::pair<unsigned, Attribute> + (id,Attribute(attributeInfo))); +} + const Attribute *Being::getAttribute(unsigned id) const { AttributeMap::const_iterator ret = mAttributes.find(id); diff --git a/src/game-server/being.h b/src/game-server/being.h index ce45d59..41be5ff 100644 --- a/src/game-server/being.h +++ b/src/game-server/being.h @@ -140,6 +140,15 @@ class Being : public Actor void setAttribute(unsigned id, double value); /** + * Creates an Attribute that did not exist before + * + * @param id The id of the attribute + * @param attributeInfo The info that describes the attribute + */ + void createAttribute(unsigned id, const AttributeManager::AttributeInfo + &attributeInfo); + + /** * Gets an attribute or 0 if not existing. */ const Attribute *getAttribute(unsigned id) const; @@ -254,7 +263,6 @@ class Being : public Actor int getLastEmote() const { return mEmoteId; } - protected: /** * Update the being direction when moving so avoid directions desyncs * with other clients. @@ -262,8 +270,11 @@ class Being : public Actor void updateDirection(const Point ¤tPos, const Point &destPos); + protected: static const int TICKS_PER_HP_REGENERATION = 100; + /** Delay until move to next tile in miliseconds. */ + unsigned short mMoveTime; BeingAction mAction; AttributeMap mAttributes; StatusEffects mStatus; diff --git a/src/game-server/combatcomponent.cpp b/src/game-server/combatcomponent.cpp index 199126f..469569b 100644 --- a/src/game-server/combatcomponent.cpp +++ b/src/game-server/combatcomponent.cpp @@ -41,7 +41,7 @@ CombatComponent::~CombatComponent() void CombatComponent::update(Entity &entity) { - // Temponary for as long as Being is not split into Components + // Temporary for as long as Being is not split into Components // Prevents to implement all at once // TODO: remove this as soon as possible Being &being = static_cast<Being&>(entity); diff --git a/src/game-server/commandhandler.cpp b/src/game-server/commandhandler.cpp index 68899e3..3596828 100644 --- a/src/game-server/commandhandler.cpp +++ b/src/game-server/commandhandler.cpp @@ -732,7 +732,8 @@ static void handleSpawn(Character *player, std::string &args) // create the monsters and put them on the map for (int i = 0; i < value; ++i) { - Being *monster = new Monster(mc); + Being *monster = new Being(OBJECT_MONSTER); + monster->addComponent(new MonsterComponent(*monster, mc)); monster->setMap(map); monster->setPosition(pos); monster->clearDestination(); diff --git a/src/game-server/component.h b/src/game-server/component.h index 47e9dd0..974cad0 100644 --- a/src/game-server/component.h +++ b/src/game-server/component.h @@ -28,6 +28,7 @@ enum ComponentType CT_Effect, CT_Fighting, CT_Item, + CT_Monster, CT_Npc, CT_SpawnArea, CT_TriggerArea, diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp index 25abb68..9e45bb1 100644 --- a/src/game-server/monster.cpp +++ b/src/game-server/monster.cpp @@ -53,27 +53,22 @@ double MonsterClass::getVulnerability(Element element) const return it->second; } -Monster::Monster(MonsterClass *specy): - Being(OBJECT_MONSTER), +MonsterComponent::MonsterComponent(Being &being, MonsterClass *specy): mSpecy(specy), mOwner(NULL) { LOG_DEBUG("Monster spawned! (id: " << mSpecy->getId() << ")."); - setWalkMask(Map::BLOCKMASK_WALL | Map::BLOCKMASK_CHARACTER); - setBlockType(BLOCKTYPE_MONSTER); + being.setWalkMask(Map::BLOCKMASK_WALL | Map::BLOCKMASK_CHARACTER); + being.setBlockType(BLOCKTYPE_MONSTER); /* * Initialise the attribute structures. */ - const AttributeManager::AttributeScope &mobAttr = - attributeManager->getAttributeScope(MonsterScope); - for (AttributeManager::AttributeScope::const_iterator it = mobAttr.begin(), - it_end = mobAttr.end(); it != it_end; ++it) + for (auto attrInfo : attributeManager->getAttributeScope(MonsterScope)) { - mAttributes.insert(std::pair< unsigned, Attribute > - (it->first, Attribute(*it->second))); + being.createAttribute(attrInfo.first, *attrInfo.second); } /* @@ -83,24 +78,22 @@ Monster::Monster(MonsterClass *specy): int mutation = specy->getMutation(); - for (AttributeMap::iterator it2 = mAttributes.begin(), - it2_end = mAttributes.end(); it2 != it2_end; ++it2) + for (auto &attribute : specy->getAttributes()) { - double attr = 0.0f; - - if (specy->hasAttribute(it2->first)) + double attributeValue = attribute.second; + if (mutation != 0) { - attr = specy->getAttribute(it2->first); - - setAttribute(it2->first, - mutation ? - attr * (100 + (rand() % (mutation * 2)) - mutation) / 100.0 : - attr); + double factor = 100 + (rand() % (mutation * 2)) - mutation; + attributeValue = attributeValue * factor / 100.0; } + being.setAttribute(attribute.first, attributeValue); } - setSize(specy->getSize()); - setGender(specy->getGender()); + being.setSize(specy->getSize()); + being.setGender(specy->getGender()); + + being.signal_died.connect(sigc::mem_fun(this, + &MonsterComponent::monsterDied)); // Set positions relative to target from which the monster can attack int dist = specy->getAttackDistance(); @@ -110,33 +103,34 @@ Monster::Monster(MonsterClass *specy): mAttackPositions.push_back(AttackPosition(0, dist, UP)); MonsterCombatComponent *combatComponent = - new MonsterCombatComponent(*this); - addComponent(combatComponent); + new MonsterCombatComponent(being, specy); + being.addComponent(combatComponent); double damageMutation = mutation ? (100.0 + (rand() % (mutation * 2)) - mutation) / 100.0 : 1.0; combatComponent->setDamageMutation(damageMutation); combatComponent->signal_damaged.connect( - sigc::mem_fun(this, &Monster::receivedDamage)); + sigc::mem_fun(this, &MonsterComponent::receivedDamage)); } -Monster::~Monster() +MonsterComponent::~MonsterComponent() { } -void Monster::update() +void MonsterComponent::update(Entity &entity) { - Being::update(); - if (mKillStealProtectedTimeout.justFinished()) mOwner = NULL; + // Temporary until all depedencies are available as component + Being &being = static_cast<Being &>(entity); + // If dead, remove it - if (mAction == DEAD) + if (being.getAction() == DEAD) { if (mDecayTimeout.expired()) - GameState::enqueueRemove(this); + GameState::enqueueRemove(&being); return; } @@ -145,18 +139,19 @@ void Monster::update() { Script *script = ScriptManager::currentState(); script->prepare(mSpecy->getUpdateCallback()); - script->push(this); - script->execute(getMap()); + script->push(&entity); + script->execute(entity.getMap()); } - refreshTarget(); + refreshTarget(entity); // Cancel the rest when we have a target - if (getComponent<CombatComponent>()->getTarget()) + if (entity.getComponent<CombatComponent>()->getTarget()) return; // We have no target - let's wander around - if (mStrollTimeout.expired() && getPosition() == getDestination()) + if (mStrollTimeout.expired() && + being.getPosition() == being.getDestination()) { if (mKillStealProtectedTimeout.expired()) { @@ -164,23 +159,26 @@ void Monster::update() if (range) { Point randomPos(rand() % (range * 2 + 1) - - range + getPosition().x, + - range + being.getPosition().x, rand() % (range * 2 + 1) - - range + getPosition().y); + - range + being.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); + being.setDestination(randomPos); } mStrollTimeout.set(10 + rand() % 10); } } } -void Monster::refreshTarget() +void MonsterComponent::refreshTarget(Entity &entity) { + // Temporary until all depedencies are available as component + Being &being = static_cast<Being &>(entity); + // We are dead and sadly not possible to keep attacking :( - if (mAction == DEAD) + if (being.getAction() == DEAD) return; // Check potential attack positions @@ -189,11 +187,12 @@ void Monster::refreshTarget() Point bestAttackPosition; // reset Target. We will find a new one if possible - getComponent<CombatComponent>()->clearTarget(); + entity.getComponent<CombatComponent>()->clearTarget(); // Iterate through objects nearby int aroundArea = Configuration::getValue("game_visualRange", 448); - for (BeingIterator i(getMap()->getAroundBeingIterator(this, aroundArea)); + for (BeingIterator i(entity.getMap()->getAroundBeingIterator(&being, + aroundArea)); i; ++i) { // We only want to attack player characters @@ -231,7 +230,8 @@ void Monster::refreshTarget() attackPosition.x += j->x; attackPosition.y += j->y; - int posPriority = calculatePositionPriority(attackPosition, + int posPriority = calculatePositionPriority(entity, + attackPosition, targetPriority); if (posPriority > bestTargetPriority) { @@ -243,26 +243,32 @@ void Monster::refreshTarget() } if (bestTarget) { - getComponent<CombatComponent>()->setTarget(bestTarget); - if (bestAttackPosition == getPosition()) + entity.getComponent<CombatComponent>()->setTarget(bestTarget); + if (bestAttackPosition == being.getPosition()) { - mAction = ATTACK; - updateDirection(getPosition(), bestTarget->getPosition()); + being.setAction(ATTACK); + being.updateDirection(being.getPosition(), + bestTarget->getPosition()); } else { - setDestination(bestAttackPosition); + being.setDestination(bestAttackPosition); } } } -int Monster::calculatePositionPriority(Point position, int targetPriority) +int MonsterComponent::calculatePositionPriority(Entity &entity, + Point position, + int targetPriority) { - Point thisPos = getPosition(); + // Temporary until all depedencies are available as component + Actor &actor = static_cast<Actor &>(entity); + + Point thisPos = actor.getPosition(); unsigned range = mSpecy->getTrackRange(); - Map *map = getMap()->getMap(); + Map *map = entity.getMap()->getMap(); int tileWidth = map->getTileWidth(); int tileHeight = map->getTileHeight(); @@ -276,7 +282,7 @@ int Monster::calculatePositionPriority(Point position, int targetPriority) Path path; path = map->findPath(thisPos.x / tileWidth, thisPos.y / tileHeight, position.x / tileWidth, position.y / tileHeight, - getWalkMask(), + actor.getWalkMask(), range); if (path.empty() || path.size() >= range) @@ -289,7 +295,7 @@ int Monster::calculatePositionPriority(Point position, int targetPriority) } } -void Monster::forgetTarget(Entity *entity) +void MonsterComponent::forgetTarget(Entity *entity) { Being *b = static_cast< Being * >(entity); { @@ -307,7 +313,7 @@ void Monster::forgetTarget(Entity *entity) } } -void Monster::changeAnger(Actor *target, int amount) +void MonsterComponent::changeAnger(Actor *target, int amount) { const EntityType type = target->getType(); if (type != OBJECT_MONSTER && type != OBJECT_CHARACTER) @@ -327,13 +333,13 @@ void Monster::changeAnger(Actor *target, int amount) // Forget target either when it's removed or died, whichever // happens first. aggressionInfo.removedConnection = - being->signal_removed.connect(sigc::mem_fun(this, &Monster::forgetTarget)); + being->signal_removed.connect(sigc::mem_fun(this, &MonsterComponent::forgetTarget)); aggressionInfo.diedConnection = - being->signal_died.connect(sigc::mem_fun(this, &Monster::forgetTarget)); + being->signal_died.connect(sigc::mem_fun(this, &MonsterComponent::forgetTarget)); } } -std::map<Being *, int> Monster::getAngerList() const +std::map<Being *, int> MonsterComponent::getAngerList() const { std::map<Being *, int> result; std::map<Being *, AggressionInfo>::const_iterator i, i_end; @@ -347,12 +353,8 @@ std::map<Being *, int> Monster::getAngerList() const return result; } -void Monster::died() +void MonsterComponent::monsterDied(Being *monster) { - if (mAction == DEAD) - return; - - Being::died(); mDecayTimeout.set(DECAY_TIME); if (mExpReceivers.size() > 0) @@ -366,8 +368,8 @@ void Monster::died() if (p <= drop.probability) { - Actor *item = Item::create(getMap(), - getPosition(), + Actor *item = Item::create(monster->getMap(), + monster->getPosition(), drop.item, 1); GameState::enqueueInsert(item); } @@ -403,7 +405,7 @@ void Monster::died() } -void Monster::receivedDamage(Being *source, const Damage &damage, int hpLoss) +void MonsterComponent::receivedDamage(Being *source, const Damage &damage, int hpLoss) { if (source) changeAnger(source, hpLoss); diff --git a/src/game-server/monster.h b/src/game-server/monster.h index 3bd34a9..d1c8e90 100644 --- a/src/game-server/monster.h +++ b/src/game-server/monster.h @@ -139,6 +139,9 @@ class MonsterClass bool hasAttribute(int attribute) const { return (mAttributes.find(attribute) != mAttributes.end()); } + const std::map<int, double> &getAttributes() const + { return mAttributes; } + /** Sets collision circle radius. */ void setSize(int size) { mSize = size; } @@ -246,7 +249,7 @@ class MonsterClass Script::Ref mDamageCallback; friend class MonsterManager; - friend class Monster; + friend class MonsterComponent; }; /** @@ -267,16 +270,18 @@ struct AttackPosition }; /** - * The class for a fightable monster with its own AI + * The component for a fightable monster with its own AI */ -class Monster : public Being +class MonsterComponent : public Component { public: + static const ComponentType type = CT_Monster; + /** Time in game ticks until ownership of a monster can change. */ static const int KILLSTEAL_PROTECTION_TIME = 100; - Monster(MonsterClass *); - ~Monster(); + MonsterComponent(Being &being, MonsterClass *); + ~MonsterComponent(); /** * Returns monster specy. @@ -287,14 +292,14 @@ class Monster : public Being /** * Performs one step of controller logic. */ - void update(); + void update(Entity &entity); - void refreshTarget(); + void refreshTarget(Entity &entity); /** - * Kills the being. + * Signal handler */ - void died(); + void monsterDied(Being *monster); void receivedDamage(Being *attacker, const Damage &damage, int hpLoss); @@ -313,7 +318,9 @@ class Monster : public Being private: static const int DECAY_TIME = 50; - int calculatePositionPriority(Point position, int targetPriority); + int calculatePositionPriority(Entity &entity, + Point position, + int targetPriority); MonsterClass *mSpecy; diff --git a/src/game-server/monstercombatcomponent.cpp b/src/game-server/monstercombatcomponent.cpp index dc66955..0fc0b48 100644 --- a/src/game-server/monstercombatcomponent.cpp +++ b/src/game-server/monstercombatcomponent.cpp @@ -23,16 +23,14 @@ #include "game-server/monster.h" #include "scripting/scriptmanager.h" -MonsterCombatComponent::MonsterCombatComponent(Monster &monster): +MonsterCombatComponent::MonsterCombatComponent(Being &monster, + MonsterClass *specy): CombatComponent(monster), mDamageMutation(0) { - // Take attacks from specy - std::vector<AttackInfo *> &attacks = monster.getSpecy()->getAttackInfos(); - for (std::vector<AttackInfo *>::iterator it = attacks.begin(), - it_end = attacks.end(); it != it_end; ++it) + for (auto &attack : specy->getAttackInfos()) { - addAttack(*it); + addAttack(attack); } } @@ -72,13 +70,11 @@ void MonsterCombatComponent::processAttack(Being *source, Attack &attack) * Calls the damage function in Being and updates the aggro list */ int MonsterCombatComponent::damage(Being &target, - Being *source, - const Damage &damage) + Being *source, + const Damage &damage) { - // Temporarily depend on monster as long as it does not exist as a component - Monster &monster = static_cast<Monster &>(target); Damage newDamage = damage; - MonsterClass *specy = monster.getSpecy(); + MonsterClass *specy = target.getComponent<MonsterComponent>()->getSpecy(); float factor = specy->getVulnerability(newDamage.element); newDamage.base = newDamage.base * factor; newDamage.delta = newDamage.delta * factor; @@ -93,7 +89,7 @@ int MonsterCombatComponent::damage(Being &target, script->push(source); script->push(hpLoss); // TODO: add exact damage parameters as well - script->execute(monster.getMap()); + script->execute(target.getMap()); } return hpLoss; } diff --git a/src/game-server/monstercombatcomponent.h b/src/game-server/monstercombatcomponent.h index 766c773..b65c48f 100644 --- a/src/game-server/monstercombatcomponent.h +++ b/src/game-server/monstercombatcomponent.h @@ -26,12 +26,12 @@ #include "game-server/attack.h" #include "game-server/being.h" -class Monster; +class MonsterClass; class MonsterCombatComponent: public CombatComponent { public: - MonsterCombatComponent(Monster &monster); + MonsterCombatComponent(Being &monster, MonsterClass *specy); void processAttack(Being *source, Attack &attack); int damage(Being &target, Being *source, const Damage &damage); diff --git a/src/game-server/spawnareacomponent.cpp b/src/game-server/spawnareacomponent.cpp index d71c250..557a2da 100644 --- a/src/game-server/spawnareacomponent.cpp +++ b/src/game-server/spawnareacomponent.cpp @@ -67,7 +67,8 @@ void SpawnAreaComponent::update(Entity &entity) const int width = mZone.w; const int height = mZone.h; - Being *being = new Monster(mSpecy); + Being *being = new Being(OBJECT_MONSTER); + being->addComponent(new MonsterComponent(*being, mSpecy)); if (being->getModifiedAttribute(ATTR_MAX_HP) <= 0) { diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp index d3a2986..74bd87e 100644 --- a/src/game-server/state.cpp +++ b/src/game-server/state.cpp @@ -270,9 +270,10 @@ static void informPlayer(MapComposite *map, Character *p) case OBJECT_MONSTER: { - Monster *q = static_cast< Monster * >(o); - enterMsg.writeInt16(q->getSpecy()->getId()); - enterMsg.writeString(q->getName()); + MonsterComponent *monsterComponent = + o->getComponent<MonsterComponent>(); + enterMsg.writeInt16(monsterComponent->getSpecy()->getId()); + enterMsg.writeString(o->getName()); } break; case OBJECT_NPC: @@ -567,10 +568,13 @@ bool GameState::insert(Entity *ptr) break; case OBJECT_MONSTER: + { + MonsterComponent *monsterComponent = + obj->getComponent<MonsterComponent>(); LOG_DEBUG("Monster inserted: " - << static_cast<Monster*>(obj)->getSpecy()->getId()); + << monsterComponent->getSpecy()->getId()); break; - + } case OBJECT_ACTOR: case OBJECT_OTHER: default: @@ -641,10 +645,13 @@ void GameState::remove(Entity *ptr) break; case OBJECT_MONSTER: + { + MonsterComponent *monsterComponent = + ptr->getComponent<MonsterComponent>(); LOG_DEBUG("Monster removed: " - << static_cast<Monster*>(ptr)->getSpecy()->getId()); + << monsterComponent->getSpecy()->getId()); break; - + } case OBJECT_ACTOR: case OBJECT_OTHER: default: |