diff options
author | Philipp Sehmisch <tmw@crushnet.org> | 2006-12-29 12:22:02 +0000 |
---|---|---|
committer | Philipp Sehmisch <tmw@crushnet.org> | 2006-12-29 12:22:02 +0000 |
commit | 3d404e743105bb9168c89e3451cf35d7d59120b1 (patch) | |
tree | 39389b921d054d508a5dee7d0ed7f4f3c5e7d29e | |
parent | 4bfa5b213257416f997d01b087c9e8bbb91cb3b9 (diff) | |
download | manaserv-3d404e743105bb9168c89e3451cf35d7d59120b1.tar.gz manaserv-3d404e743105bb9168c89e3451cf35d7d59120b1.tar.bz2 manaserv-3d404e743105bb9168c89e3451cf35d7d59120b1.tar.xz manaserv-3d404e743105bb9168c89e3451cf35d7d59120b1.zip |
Implemented basic attack hit detection and damage notification.
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | src/being.cpp | 22 | ||||
-rw-r--r-- | src/being.h | 35 | ||||
-rw-r--r-- | src/defines.h | 3 | ||||
-rw-r--r-- | src/gamehandler.cpp | 1 | ||||
-rw-r--r-- | src/mapcomposite.cpp | 26 | ||||
-rw-r--r-- | src/mapcomposite.h | 11 | ||||
-rw-r--r-- | src/object.h | 34 | ||||
-rw-r--r-- | src/player.cpp | 82 | ||||
-rw-r--r-- | src/player.h | 7 | ||||
-rw-r--r-- | src/state.cpp | 76 |
11 files changed, 271 insertions, 33 deletions
@@ -1,3 +1,10 @@ +2006-12-29 Philipp Sehmisch <tmw@crushnet.org> + + src/being.cpp, src/being.h, src/defines.h, src/gamehandler.cpp, + src/mapcomposite.cpp, src/mapcomposite.h, src/object.h, src/player.cpp, + src/player.h, src/state.cpp: + Implemented basic attack hit detection and damage notification. + 2006-12-27 Philipp Sehmisch <tmw@crushnet.org> * src/defines.h, src/gamehandler.cpp, src/object.h, src/player.cpp, diff --git a/src/being.cpp b/src/being.cpp index 512d682b..1f57b0b2 100644 --- a/src/being.cpp +++ b/src/being.cpp @@ -29,5 +29,23 @@ void Being::update() { if (mController) - mController->update(); -} + mController->update();
+
+ mHitsTaken.clear(); +}
+
+void Being::damage(Damage damage)
+{
+ int HPloss;
+
+ HPloss = damage; // TODO: Implement complex damage calculation here
+
+ mHitpoints -= HPloss;
+ mHitsTaken.push_back(HPloss);
+ LOG_DEBUG("Being " << getPublicID() << " got hit", 0);
+}
+
+void Being::performAttack(MapComposite* map)
+{
+ //Monster attack
+}
diff --git a/src/being.h b/src/being.h index fb6e837a..bf35d9fc 100644 --- a/src/being.h +++ b/src/being.h @@ -23,6 +23,7 @@ #ifndef _TMWSERV_BEING_H_ #define _TMWSERV_BEING_H_ +#include <list> #include <string> #include <vector> @@ -121,6 +122,7 @@ struct RawStatistics unsigned short stats[NB_RSTAT]; }; + /** * Computed statistics of a Being. */ @@ -143,6 +145,16 @@ struct Statistics }; /** + * Placeholder for a more complex damage structure + */ +typedef unsigned short Damage; + +/** + * Type definition for a list of hits + */ +typedef std::list<unsigned int> Hits; + +/** * Generic Being (living object). * Used for players & monsters (all animated objects). */ @@ -175,11 +187,28 @@ class Being : public MovingObject { return mStats.stats[numStat]; } /** + * Takes a damage structure, computes the real damage based on the + * stats, deducts the result from the hitpoints and adds the result to + * the HitsTaken list + */ + virtual void damage(Damage); + + /** + * Get the damage list + */ + Hits getHitsTaken() const + { return mHitsTaken; } + + /** + * Clears the hit list. * When a controller is set, updates the controller. */ - void + virtual void update(); + virtual void + performAttack(MapComposite*); + /** * Notification that this being is now possessed by the given * controller. This means that events regarding what happens to this @@ -195,6 +224,10 @@ class Being : public MovingObject Statistics mStats; /**< stats modifiers or computed stats */ Controller *mController; + + int mHitpoints; /**< Hitpoints of the being */ + + Hits mHitsTaken; /**< List of punches taken since last update */ }; /** diff --git a/src/defines.h b/src/defines.h index dc594311..2024e66f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -153,12 +153,13 @@ enum { GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position] [, W*2 destination] }* PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // W being id, S text - PGMSG_ATTACK = 0x0290, // - + PGMSG_ATTACK = 0x0290, // B direction GPMSG_BEING_ATTACK = 0x0291, // W being id PGMSG_USE_ITEM = 0x0300, // L item id GPMSG_USE_RESPONSE = 0x0301, // B error PGMSG_EQUIP = 0x0302, // L item id, B slot GPMSG_EQUIP_RESPONSE = 0x0303, // B error + GPMSG_BEINGS_DAMAGE = 0x0310, // { W being id, W ammount }* // Chat CPMSG_ERROR = 0x0401, // B error diff --git a/src/gamehandler.cpp b/src/gamehandler.cpp index e2a37e32..6d323642 100644 --- a/src/gamehandler.cpp +++ b/src/gamehandler.cpp @@ -225,6 +225,7 @@ void GameHandler::processMessage(NetComputer *comp, MessageIn &message) computer.getCharacter()->getPublicID() << " attacks", 0); + computer.getCharacter()->setDirection(message.readByte()); computer.getCharacter()->setAttacking(true); } break; diff --git a/src/mapcomposite.cpp b/src/mapcomposite.cpp index 1e40ae06..8cda81a3 100644 --- a/src/mapcomposite.cpp +++ b/src/mapcomposite.cpp @@ -395,6 +395,32 @@ ZoneIterator MapComposite::getAroundPlayerIterator(Player *obj) const } fillRegion(r2, obj->getPosition()); return ZoneIterator(r2, this); +}
+
+std::list<ObjectPtr> MapComposite::getObjectsOnTile(const Point &tile) const
+{
+ std::list<ObjectPtr> objectList;
+
+ Objects::const_iterator i;
+
+ // convert pixel coordinates to tile coordinates
+ int tX = (int)((tile.x) / 32);
+ int tY = (int)((tile.y) / 32);
+
+ for (i = objects.begin(); i != objects.end(); ++i)
+ {
+ // convert object coordinates to tile coordinates
+ Point objectPoint = (*i)->getPosition();
+ int oX = (int)((objectPoint.x) / 32);
+ int oY = (int)((objectPoint.y) / 32);
+
+ if (oX == tX && oY == tY)
+ {
+ objectList.push_back (*i);
+ }
+ }
+
+ return objectList;
} bool MapComposite::insert(ObjectPtr obj) diff --git a/src/mapcomposite.h b/src/mapcomposite.h index 94931029..7384aa37 100644 --- a/src/mapcomposite.h +++ b/src/mapcomposite.h @@ -25,7 +25,9 @@ #define _TMW_SERVER_MAPCOMPOSITE_ #include "object.h" -#include "player.h" +#include "player.h"
+
+#include <list> class Map; class MapComposite; @@ -178,7 +180,12 @@ class MapComposite { /** * Gets an iterator on the objects around a given object. */ - ZoneIterator getAroundObjectIterator(Object *) const; + ZoneIterator getAroundObjectIterator(Object *) const;
+
+ /**
+ * Gets all objects on a tile
+ */
+ std::list<ObjectPtr> MapComposite::getObjectsOnTile(const Point &) const; /** * Gets an iterator on the objects around the old and new positions of diff --git a/src/object.h b/src/object.h index 63d6c115..0b019239 100644 --- a/src/object.h +++ b/src/object.h @@ -30,6 +30,8 @@ #include "point.h" #include "utils/countedptr.h" +class MapComposite; + enum { NEW_ON_MAP = 1, @@ -37,6 +39,7 @@ enum ATTACK = 4 }; + /** * Generic in-game object definition. * Base class for in-game objects. @@ -133,10 +136,20 @@ class MovingObject: public Object { public: /** + * Directions, to be used as bitmask values + */ + static const char DOWN = 1; + static const char LEFT = 2; + static const char UP = 4; + static const char RIGHT = 8; + + /** * Proxy constructor. */ MovingObject(int type, int id) - : Object(type), mPublicID(id), + : Object(type), + mDirection(DOWN), + mPublicID(id), mActionTime(0) {} @@ -159,6 +172,19 @@ class MovingObject: public Object { return mOld; } /** + * Sete object direction + */ + void setDirection(unsigned char direction) + { mDirection = direction; } + + /** + * Gets object direction + */ + + unsigned char getDirection() const + { return mDirection; } + + /** * Sets object speed. */ void setSpeed(unsigned s) @@ -170,6 +196,11 @@ class MovingObject: public Object void move(); /** + * Performs an attack + */ + virtual void performAttack (MapComposite* map) = 0; + + /** * Get public ID. * * @return the public ID, 65535 if none yet. @@ -186,6 +217,7 @@ class MovingObject: public Object protected: unsigned short mActionTime; /**< delay until next action */ + unsigned char mDirection; /**< Facing direction */ private: unsigned short mPublicID; /**< Object ID sent to clients (unique with respect to the map) */ diff --git a/src/player.cpp b/src/player.cpp index 14882712..4cd0da53 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -23,6 +23,7 @@ #include "player.h" #include "defines.h" +#include "mapcomposite.h" #include <cassert> @@ -51,15 +52,92 @@ void Player::update() // plausibility check of attack command if (mActionTime <= 0) { - // perform attack + // request perform attack mActionTime = 1000; mIsAttacking = false; raiseUpdateFlags (ATTACK); - //TODO: attack mechanics } } + + Being::update(); } +void Player::performAttack (MapComposite* map) +{ + std::list<ObjectPtr> victimList; + std::list<Point> attackZone; + + + Point attackPoint = getPosition(); + + unsigned char direction= getDirection(); + if (direction & UP) + { + attackPoint.y -= 32; + attackPoint.x -= 32; + attackZone.push_back(attackPoint); + attackPoint.x += 32; + attackZone.push_back(attackPoint); + attackPoint.x += 32; + attackZone.push_back(attackPoint); + } + else if (direction & RIGHT) + { + attackPoint.x += 32; + attackPoint.y -= 32; + attackZone.push_back(attackPoint); + attackPoint.y += 32; + attackZone.push_back(attackPoint); + attackPoint.y += 32; + attackZone.push_back(attackPoint); + } + else if (direction & DOWN) + { + attackPoint.y += 32; + attackPoint.x -= 32; + attackZone.push_back(attackPoint); + attackPoint.x += 32; + attackZone.push_back(attackPoint); + attackPoint.x += 32; + attackZone.push_back(attackPoint); + } + else { + attackPoint.x -= 32; + attackPoint.y -= 32; + attackZone.push_back(attackPoint); + attackPoint.y += 32; + attackZone.push_back(attackPoint); + attackPoint.y += 32; + attackZone.push_back(attackPoint); + } + + attackZone.push_back(attackPoint); //point player is facing + + //get enemies to hurt + for (std::list<Point>::iterator i = attackZone.begin(); i != attackZone.end(); ++i) + { + std::list<ObjectPtr> newVictimList = map->getObjectsOnTile((*i)); + victimList.splice(victimList.end(), newVictimList); + } + + // apply damage to victims + Damage damage; + + /* TODO: calculate real attack power and damage properties based on + * character equipment and stats + */ + damage = 1; + + for (std::list<ObjectPtr>::iterator i = victimList.begin(); i != victimList.end(); ++i) + { + if ((*i)->getType() == OBJECT_PLAYER || (*i)->getType() == OBJECT_MONSTER) + { + static_cast<Being*>(&**i)->damage(damage); + } + } + +}; + void Player::setInventory(const Inventory &inven) { inventory = inven; diff --git a/src/player.h b/src/player.h index f3d1c35e..f953c207 100644 --- a/src/player.h +++ b/src/player.h @@ -155,7 +155,12 @@ class Player : public Being /** * Updates the internal status. */ - void update(); + void update();
+
+ /**
+ * Performs an attack
+ */
+ virtual void performAttack (MapComposite* map); /** * Sets inventory. diff --git a/src/state.cpp b/src/state.cpp index b4853f68..a3fbda1f 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -64,7 +64,9 @@ State::~State() void State::update() { - // update game state (update AI, etc.) + /* + * Update game state (update AI, etc.) + */ for (std::map< unsigned, MapComposite * >::iterator m = maps.begin(), m_end = maps.end(); m != m_end; ++m) { @@ -77,14 +79,26 @@ State::update() for (MovingObjectIterator o(map->getWholeMapIterator()); o; ++o) { + if ((*o)->getUpdateFlags() & ATTACK) + { + (*o)->performAttack(m->second); + } + } + + for (MovingObjectIterator o(map->getWholeMapIterator()); o; ++o) + { (*o)->move(); } map->update(); + /* + * Inform clients about changes in the game state + */ for (PlayerIterator p(map->getWholeMapIterator()); p; ++p) { - MessageOut msg(GPMSG_BEINGS_MOVE); + MessageOut moveMsg(GPMSG_BEINGS_MOVE); + MessageOut damageMsg(GPMSG_BEINGS_DAMAGE); for (MovingObjectIterator o(map->getAroundPlayerIterator(*p)); o; ++o) { @@ -94,7 +108,7 @@ State::update() int flags = 0; - // Handle attacking + // Send attack messages if ( (*o)->getUpdateFlags() & ATTACK && (*o)->getPublicID() != (*p)->getPublicID() && (*p)->getPosition().inRangeOf(on) @@ -113,7 +127,20 @@ State::update() gameHandler->sendTo(*p, AttackMsg); } - // Handle moving + // Send damage messages + + if ((*o)->getType() == OBJECT_PLAYER || (*o)->getType() == OBJECT_MONSTER) + { + Being *victim = static_cast<Being*> (*o); + Hits hits = victim->getHitsTaken(); + for (Hits::iterator i = hits.begin(); i != hits.end(); i++) + { + damageMsg.writeShort(victim->getPublicID()); + damageMsg.writeShort((*i)); + } + } + + // Send move messages /* Check whether this player and this moving object were around * the last time and whether they will be around the next time. @@ -132,33 +159,33 @@ State::update() flags |= MOVING_DESTINATION; int type = (*o)->getType(); - MessageOut msg2(GPMSG_BEING_ENTER); - msg2.writeByte(type); - msg2.writeShort((*o)->getPublicID()); + MessageOut enterMsg(GPMSG_BEING_ENTER); + enterMsg.writeByte(type); + enterMsg.writeShort((*o)->getPublicID()); switch (type) { case OBJECT_PLAYER: { Player *q = static_cast< Player * >(*o); - msg2.writeString(q->getName()); - msg2.writeByte(q->getHairStyle()); - msg2.writeByte(q->getHairColor()); - msg2.writeByte(q->getGender()); + enterMsg.writeString(q->getName()); + enterMsg.writeByte(q->getHairStyle()); + enterMsg.writeByte(q->getHairColor()); + enterMsg.writeByte(q->getGender()); } break; case OBJECT_MONSTER: { - msg2.writeShort(0); // TODO: The monster ID + enterMsg.writeShort(0); // TODO: The monster ID } break; default: assert(false); // TODO } - gameHandler->sendTo(*p, msg2); + gameHandler->sendTo(*p, enterMsg); } else if (!willBeInRange) { // o is no longer visible from p. - MessageOut msg2(GPMSG_BEING_LEAVE); - msg2.writeShort((*o)->getPublicID()); - gameHandler->sendTo(*p, msg2); + MessageOut leaveMsg(GPMSG_BEING_LEAVE); + leaveMsg.writeShort((*o)->getPublicID()); + gameHandler->sendTo(*p, leaveMsg); continue; } else if (os.x == on.x && os.y == on.y) @@ -185,22 +212,25 @@ State::update() flags |= MOVING_DESTINATION; } - msg.writeShort((*o)->getPublicID()); - msg.writeByte(flags); + moveMsg.writeShort((*o)->getPublicID()); + moveMsg.writeByte(flags); if (flags & MOVING_POSITION) { - msg.writeCoordinates(on.x / 32, on.y / 32); + moveMsg.writeCoordinates(on.x / 32, on.y / 32); } if (flags & MOVING_DESTINATION) { - msg.writeShort(od.x); - msg.writeShort(od.y); + moveMsg.writeShort(od.x); + moveMsg.writeShort(od.y); } } // Don't send a packet if nothing happened in p's range. - if (msg.getLength() > 2) - gameHandler->sendTo(*p, msg); + if (moveMsg.getLength() > 2) + gameHandler->sendTo(*p, moveMsg); + + if (damageMsg.getLength() > 2) + gameHandler->sendTo(*p, damageMsg); } for (ObjectIterator o(map->getWholeMapIterator()); o; ++o) |