summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilipp Sehmisch <tmw@crushnet.org>2006-12-29 12:22:02 +0000
committerPhilipp Sehmisch <tmw@crushnet.org>2006-12-29 12:22:02 +0000
commit3d404e743105bb9168c89e3451cf35d7d59120b1 (patch)
tree39389b921d054d508a5dee7d0ed7f4f3c5e7d29e /src
parent4bfa5b213257416f997d01b087c9e8bbb91cb3b9 (diff)
downloadmanaserv-3d404e743105bb9168c89e3451cf35d7d59120b1.tar.gz
manaserv-3d404e743105bb9168c89e3451cf35d7d59120b1.tar.bz2
manaserv-3d404e743105bb9168c89e3451cf35d7d59120b1.tar.xz
manaserv-3d404e743105bb9168c89e3451cf35d7d59120b1.zip
Implemented basic attack hit detection and damage notification.
Diffstat (limited to 'src')
-rw-r--r--src/being.cpp22
-rw-r--r--src/being.h35
-rw-r--r--src/defines.h3
-rw-r--r--src/gamehandler.cpp1
-rw-r--r--src/mapcomposite.cpp26
-rw-r--r--src/mapcomposite.h11
-rw-r--r--src/object.h34
-rw-r--r--src/player.cpp82
-rw-r--r--src/player.h7
-rw-r--r--src/state.cpp76
10 files changed, 264 insertions, 33 deletions
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)