From 3d404e743105bb9168c89e3451cf35d7d59120b1 Mon Sep 17 00:00:00 2001 From: Philipp Sehmisch Date: Fri, 29 Dec 2006 12:22:02 +0000 Subject: Implemented basic attack hit detection and damage notification. --- ChangeLog | 7 +++++ src/being.cpp | 22 ++++++++++++-- src/being.h | 35 +++++++++++++++++++++- src/defines.h | 3 +- src/gamehandler.cpp | 1 + src/mapcomposite.cpp | 26 +++++++++++++++++ src/mapcomposite.h | 11 +++++-- src/object.h | 34 +++++++++++++++++++++- src/player.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/player.h | 7 ++++- src/state.cpp | 76 +++++++++++++++++++++++++++++++++--------------- 11 files changed, 271 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 92bfe1c9..c0a64873 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2006-12-29 Philipp Sehmisch + + 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 * 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 #include #include @@ -121,6 +122,7 @@ struct RawStatistics unsigned short stats[NB_RSTAT]; }; + /** * Computed statistics of a Being. */ @@ -142,6 +144,16 @@ struct Statistics unsigned short stats[NB_CSTAT]; }; +/** + * Placeholder for a more complex damage structure + */ +typedef unsigned short Damage; + +/** + * Type definition for a list of hits + */ +typedef std::list 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 MapComposite::getObjectsOnTile(const Point &tile) const +{ + std::list 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 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 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. @@ -132,11 +135,21 @@ class Object 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) {} @@ -158,6 +171,19 @@ class MovingObject: public Object Point getOldPosition() const { return mOld; } + /** + * Sete object direction + */ + void setDirection(unsigned char direction) + { mDirection = direction; } + + /** + * Gets object direction + */ + + unsigned char getDirection() const + { return mDirection; } + /** * Sets object speed. */ @@ -169,6 +195,11 @@ class MovingObject: public Object */ void move(); + /** + * Performs an attack + */ + virtual void performAttack (MapComposite* map) = 0; + /** * Get public ID. * @@ -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 @@ -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 victimList; + std::list 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::iterator i = attackZone.begin(); i != attackZone.end(); ++i) + { + std::list 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::iterator i = victimList.begin(); i != victimList.end(); ++i) + { + if ((*i)->getType() == OBJECT_PLAYER || (*i)->getType() == OBJECT_MONSTER) + { + static_cast(&**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) { @@ -75,6 +77,14 @@ State::update() (*o)->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(); @@ -82,9 +92,13 @@ State::update() 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 (*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) -- cgit v1.2.3-70-g09d2