diff options
author | Philipp Sehmisch <tmw@crushnet.org> | 2008-09-27 03:55:19 +0000 |
---|---|---|
committer | Philipp Sehmisch <tmw@crushnet.org> | 2008-09-27 03:55:19 +0000 |
commit | 29ae6d3f42ac55e7bc8c5ad0b044c7b0e662d358 (patch) | |
tree | 41ca7bb0f8b557e096a2b783f6c94ea4d3e5006a /src | |
parent | c27d73abc52bdc463a029a5f6a95e1db5df5abf6 (diff) | |
download | manaserv-29ae6d3f42ac55e7bc8c5ad0b044c7b0e662d358.tar.gz manaserv-29ae6d3f42ac55e7bc8c5ad0b044c7b0e662d358.tar.bz2 manaserv-29ae6d3f42ac55e7bc8c5ad0b044c7b0e662d358.tar.xz manaserv-29ae6d3f42ac55e7bc8c5ad0b044c7b0e662d358.zip |
Implemented getting the attack zone of weapons from the item database and implemented single target attacks useful for projectile weapons like bows.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/game-server/attackzone.cpp | 0 | ||||
-rw-r--r-- | src/game-server/attackzone.hpp | 46 | ||||
-rw-r--r-- | src/game-server/being.cpp | 59 | ||||
-rw-r--r-- | src/game-server/being.hpp | 3 | ||||
-rw-r--r-- | src/game-server/character.cpp | 12 | ||||
-rw-r--r-- | src/game-server/character.hpp | 2 | ||||
-rw-r--r-- | src/game-server/item.cpp | 6 | ||||
-rw-r--r-- | src/game-server/item.hpp | 18 | ||||
-rw-r--r-- | src/game-server/itemmanager.cpp | 41 | ||||
-rw-r--r-- | src/game-server/monster.cpp | 4 | ||||
-rw-r--r-- | src/game-server/monster.hpp | 5 | ||||
-rw-r--r-- | src/game-server/monstermanager.cpp | 9 |
13 files changed, 187 insertions, 21 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index bbfa5d52..936fd7b9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -83,6 +83,8 @@ tmwserv_game_SOURCES = \ common/inventorydata.hpp \ game-server/accountconnection.hpp \ game-server/accountconnection.cpp \ + game-server/attackzone.hpp \ + game-server/attackzone.cpp \ game-server/being.hpp \ game-server/being.cpp \ game-server/buysell.hpp \ @@ -191,4 +193,3 @@ if BUILD_LUA tmwserv_game_SOURCES += \ scripting/lua.cpp endif - diff --git a/src/game-server/attackzone.cpp b/src/game-server/attackzone.cpp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/game-server/attackzone.cpp diff --git a/src/game-server/attackzone.hpp b/src/game-server/attackzone.hpp new file mode 100644 index 00000000..2bdf3b14 --- /dev/null +++ b/src/game-server/attackzone.hpp @@ -0,0 +1,46 @@ +/* + * The Mana World Server + * Copyright 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id$ + */ + +#ifndef _TMWSERV_ATTACKZONE +#define _TMWSERV_ATTACKZONE + + +/** + * Enumeration of different types of attack damage zones + */ +enum AttackZoneShape +{ + ATTZONESHAPE_CONE + //yes, there is currently only one but it is planned to add different kinds of attack zones +}; + +struct AttackZone +{ + AttackZoneShape shape; + bool multiTarget; + int range; + int angle; +}; + + +#endif // _TMWSERV_ATTACKZONE diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp index a6ba4023..bcbbc6d9 100644 --- a/src/game-server/being.cpp +++ b/src/game-server/being.cpp @@ -25,6 +25,7 @@ #include "game-server/being.hpp" #include "defines.h" +#include "game-server/attackzone.hpp" #include "game-server/collisiondetection.hpp" #include "game-server/eventlistener.hpp" #include "game-server/mapcomposite.hpp" @@ -126,7 +127,7 @@ void Being::move() } } -void Being::performAttack(Damage const &damage, int range, int angle) +void Being::performAttack(Damage const &damage, AttackZone const *attackZone) { Point ppos = getPosition(); int dir = getDirection(); @@ -151,8 +152,10 @@ void Being::performAttack(Damage const &damage, int range, int angle) break; } + std::list<Being *> victims; + for (MovingObjectIterator - i(getMap()->getAroundObjectIterator(this, range)); i; ++i) + i(getMap()->getAroundObjectIterator(this, attackZone->range)); i; ++i) { MovingObject *o = *i; if (o == this) continue; @@ -163,13 +166,55 @@ void Being::performAttack(Damage const &damage, int range, int angle) Point opos = o->getPosition(); - if (Collision::diskWithCircleSector( - opos, o->getSize(), - ppos, range, angle, attackAngle) - ) + switch (attackZone->shape) + { + case ATTZONESHAPE_CONE: + if (Collision::diskWithCircleSector( + opos, o->getSize(), + ppos, attackZone->range, + attackZone->angle/2, attackAngle) + ) + { + victims.push_back(static_cast< Being * >(o)); + } + break; + default: + break; + } + } + + if (attackZone->multiTarget) + { + // damage everyone + for (std::list<Being *>::iterator i = victims.begin(); + i != victims.end(); + i++) + { + (*i)->damage(this, damage); + } + } + else + { + // find the closest and damage this one + Being* closestVictim = NULL; + int closestDistance = INT_MAX; + for (std::list<Being *>::iterator i = victims.begin(); + i != victims.end(); + i++) { - static_cast< Being * >(o)->damage(this, damage); + Point opos = (*i)->getPosition(); + int distance = abs(opos.x - ppos.x) + abs(opos.y - ppos.y); + /* not using pythagoras here is a) faster and b) results in more natural + target selection because targets closer to the center line of the + attack angle are prioritized + */ + if (distance < closestDistance) + { + closestVictim = (*i); + closestDistance = distance; + } } + if (closestVictim) closestVictim->damage(this, damage); } } diff --git a/src/game-server/being.hpp b/src/game-server/being.hpp index 870fd78a..58535487 100644 --- a/src/game-server/being.hpp +++ b/src/game-server/being.hpp @@ -31,6 +31,7 @@ class Being; class MapComposite; +class AttackZone; /** * Beings and actors directions @@ -158,7 +159,7 @@ class Being : public MovingObject /** * Performs an attack. */ - void performAttack(Damage const &, int range, int angle); + void performAttack(Damage const &, AttackZone const *attackZone); /** * Sets the current action. diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp index 37fb3b8c..8758b64e 100644 --- a/src/game-server/character.cpp +++ b/src/game-server/character.cpp @@ -28,6 +28,7 @@ #include "game-server/character.hpp" #include "defines.h" +#include "game-server/attackzone.hpp" #include "game-server/buysell.hpp" #include "game-server/eventlistener.hpp" #include "game-server/inventory.hpp" @@ -48,6 +49,7 @@ const float Character::EXPCURVE_EXPONENT = 3.0f; const float Character::EXPCURVE_FACTOR = 10.0f; const float Character::LEVEL_SKILL_PRECEDENCE_FACTOR = 0.75f; +const AttackZone Character::UNARMED_ATTACK_ZONE = {ATTZONESHAPE_CONE, true, 32, 90}; Character::Character(MessageIn &msg): Being(OBJECT_CHARACTER, 65535), @@ -102,21 +104,21 @@ void Character::perform() damage.cth = getModifiedAttribute(BASE_ATTR_HIT) + getModifiedAttribute(CHAR_SKILL_WEAPON_BEGIN + type); damage.usedSkill = CHAR_SKILL_WEAPON_BEGIN + type; - if (type) + + if (ic) { + // weapon fighting ItemModifiers const &mods = ic->getModifiers(); damage.element = mods.getValue(MOD_ELEMENT_TYPE); + performAttack(damage, ic->getAttackZone()); } else { // No-weapon fighting. damage.element = ELEMENT_NEUTRAL; + performAttack(damage, &UNARMED_ATTACK_ZONE); } - int attackRange = 60; //TODO: get from weapon - int attackAngle = 30; //TODO: get from weapon - - performAttack(damage, attackRange, attackAngle); } void Character::respawn() diff --git a/src/game-server/character.hpp b/src/game-server/character.hpp index d3b31276..30914344 100644 --- a/src/game-server/character.hpp +++ b/src/game-server/character.hpp @@ -288,6 +288,8 @@ class Character : public Being static const int CORRECTIONPOINTS_PER_LEVELUP = 2; static const int CORRECTIONPOINTS_MAX = 10; + static const AttackZone UNARMED_ATTACK_ZONE; + /** * Advances the character by one level; */ diff --git a/src/game-server/item.cpp b/src/game-server/item.cpp index f14374b6..4d0530f8 100644 --- a/src/game-server/item.cpp +++ b/src/game-server/item.cpp @@ -27,6 +27,7 @@ #include "game-server/item.hpp" +#include "game-server/attackzone.hpp" #include "game-server/being.hpp" WeaponType weaponTypeFromString (const std::string &name) @@ -136,6 +137,11 @@ void ItemModifiers::cancelAttributes(Being *b) const } } +ItemClass::~ItemClass() +{ + if (mAttackZone) delete mAttackZone; +} + bool ItemClass::use(Being *itemUser) { if (mType != ITEM_USABLE) return false; diff --git a/src/game-server/item.hpp b/src/game-server/item.hpp index 7b21ad87..e0d8943f 100644 --- a/src/game-server/item.hpp +++ b/src/game-server/item.hpp @@ -28,6 +28,7 @@ #include "game-server/object.hpp" +class AttackZone; class Being; /** @@ -175,9 +176,11 @@ class ItemClass { public: ItemClass(int id, ItemType type) - : mDatabaseID(id), mType(type) + : mDatabaseID(id), mType(type), mAttackZone(NULL) {} + ~ItemClass(); + /** * Applies the modifiers of an item to a given user. * @return true if the item was sucessfully used and should be removed. @@ -256,6 +259,18 @@ class ItemClass int getSpriteID() { return mSpriteID; } + /** + * Set attack zone (only needed when the item is a weapon) + */ + void setAttackZone(AttackZone* attackZone) { mAttackZone = attackZone; } + + /** + * Gets attack zone of weapon (returns NULL for non-weapon items) + */ + AttackZone const *getAttackZone() const + { return mAttackZone ; } + + private: // Item reference information @@ -266,6 +281,7 @@ class ItemClass unsigned short mCost; /**< Unit cost the item. */ unsigned short mMaxPerSlot; /**< Max item amount per slot in inventory. */ ItemModifiers mModifiers; /**< Item modifiers. */ + AttackZone *mAttackZone; /**< attack zone when used as a weapon */ }; class Item: public Object diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp index 211334ff..159b8356 100644 --- a/src/game-server/itemmanager.cpp +++ b/src/game-server/itemmanager.cpp @@ -27,6 +27,7 @@ #include "game-server/itemmanager.hpp" #include "defines.h" +#include "game-server/attackzone.hpp" #include "game-server/item.hpp" #include "game-server/resourcemanager.hpp" #include "utils/logger.h" @@ -122,6 +123,10 @@ void ItemManager::reload() int maxPerSlot = XML::getProperty(node, "max-per-slot", 0); int sprite = XML::getProperty(node, "sprite_id", 0); std::string scriptName = XML::getProperty(node, "script_name", std::string()); + std::string attackShape = XML::getProperty(node, "attack-shape", "cone"); + std::string attackTarget = XML::getProperty(node, "attack-target", "multi"); + int attackRange = XML::getProperty(node, "attack-range", 32); + int attackAngle = XML::getProperty(node, "attack-angle", 90); ItemModifiers modifiers; if (itemType == ITEM_EQUIPMENT_ONE_HAND_WEAPON || @@ -182,6 +187,42 @@ void ItemManager::reload() item->setSpriteID(sprite ? sprite : id); ++nbItems; + if (itemType == ITEM_EQUIPMENT_ONE_HAND_WEAPON || + itemType == ITEM_EQUIPMENT_TWO_HANDS_WEAPON) + { + AttackZone *zone = new AttackZone; + + if (attackShape == "cone") + { + zone->shape = ATTZONESHAPE_CONE; + } + else + { + LOG_WARN("Item Manager: Unknown attack zone shape \"" << attackShape + <<"\" for weapon " << id << " in " << itemReferenceFile << '.'); + zone->shape = ATTZONESHAPE_CONE; + } + + if (attackTarget == "multi") + { + zone->multiTarget = true; + } + else if (attackTarget == "single") + { + zone->multiTarget = false; + } + else + { + LOG_WARN("Item Manager: Unknown target mode \"" << attackTarget + <<"\" for weapon " << id << " in " << itemReferenceFile << '.'); + zone->multiTarget = true; + } + zone->range = attackRange; + zone->angle = attackAngle; + + item->setAttackZone(zone); + } + LOG_DEBUG("Item: ID: " << id << ", itemType: " << itemType << ", weight: " << weight << ", value: " << value << ", scriptName: " << scriptName << ", maxPerSlot: " << maxPerSlot << "."); diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp index d782eae0..f9cb1794 100644 --- a/src/game-server/monster.cpp +++ b/src/game-server/monster.cpp @@ -125,7 +125,7 @@ void Monster::perform() damage.element = mCurrentAttack->element; damage.type = mCurrentAttack->type; damage.usedSkill = 0; - performAttack(damage, mCurrentAttack->range, mCurrentAttack->angle); + performAttack(damage, &mCurrentAttack->attackZone); } if (!mAttackTime) { @@ -240,7 +240,7 @@ void Monster::update() } if (Collision::diskWithCircleSector( bestAttackTarget->getPosition(), bestAttackTarget->getSize(), - getPosition(), (*i)->range, (*i)->angle, attackAngle)) + getPosition(), (*i)->attackZone.range, (*i)->attackZone.angle, attackAngle)) { prioritySum += (*i)->priority; workingAttacks[prioritySum] = (*i); diff --git a/src/game-server/monster.hpp b/src/game-server/monster.hpp index 0a614081..c17dfb7e 100644 --- a/src/game-server/monster.hpp +++ b/src/game-server/monster.hpp @@ -26,9 +26,11 @@ #include <map> #include <vector> +#include "game-server/attackzone.hpp" #include "game-server/being.hpp" #include "game-server/eventlistener.hpp" +class attackZone; class ItemClass; class MapComposite; @@ -55,8 +57,7 @@ struct MonsterAttack int type; int preDelay; int aftDelay; - int range; - int angle; + AttackZone attackZone; }; typedef std::vector< MonsterAttack *> MonsterAttacks; diff --git a/src/game-server/monstermanager.cpp b/src/game-server/monstermanager.cpp index d7a840e7..a6d22750 100644 --- a/src/game-server/monstermanager.cpp +++ b/src/game-server/monstermanager.cpp @@ -26,6 +26,7 @@ #include "game-server/monstermanager.hpp" #include "defines.h" +#include "game-server/attackzone.hpp" #include "game-server/itemmanager.hpp" #include "game-server/monster.hpp" #include "game-server/resourcemanager.hpp" @@ -223,13 +224,17 @@ void MonsterManager::reload() else if (xmlStrEqual(subnode->name, BAD_CAST "attack")) { MonsterAttack *att = new MonsterAttack; + AttackZone attackZone; att->id = XML::getProperty(subnode, "id", 0); att->priority = XML::getProperty(subnode, "priority", 1); att->damageFactor = XML::getFloatProperty(subnode, "damage-factor", 1.0f); att->preDelay = XML::getProperty(subnode, "pre-delay", 1); att->aftDelay = XML::getProperty(subnode, "aft-delay", 0); - att->range = XML::getProperty(subnode, "range", 1); - att->angle = XML::getProperty(subnode, "angle", 1); + attackZone.multiTarget = true; + attackZone.shape = ATTZONESHAPE_CONE; + attackZone.range = XML::getProperty(subnode, "range", 1); + attackZone.angle = XML::getProperty(subnode, "angle", 1); + att->attackZone = attackZone; std::string sElement = XML::getProperty(subnode, "element", "neutral"); att->element = elementFromString(sElement); std::string sType = XML::getProperty(subnode, "type", "physical"); |