summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog29
-rw-r--r--src/defines.h2
-rw-r--r--src/game-server/accountconnection.cpp1
-rw-r--r--src/game-server/being.cpp21
-rw-r--r--src/game-server/being.hpp8
-rw-r--r--src/game-server/character.cpp2
-rw-r--r--src/game-server/deathlistener.hpp5
-rw-r--r--src/game-server/map.cpp47
-rw-r--r--src/game-server/map.hpp22
-rw-r--r--src/game-server/mapcomposite.cpp8
-rw-r--r--src/game-server/mapreader.cpp3
-rw-r--r--src/game-server/monster.cpp192
-rw-r--r--src/game-server/monster.hpp64
-rw-r--r--src/game-server/spawnarea.cpp45
-rw-r--r--src/game-server/spawnarea.hpp2
-rw-r--r--src/game-server/state.cpp3
-rw-r--r--src/game-server/thing.hpp16
17 files changed, 398 insertions, 72 deletions
diff --git a/ChangeLog b/ChangeLog
index 8fe0f0c7..8fc0e46e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,31 @@
-2007-06-16 Guillaume Melquiond <guillaume.melquiong@gmail.com>
+2007-06-28 Philipp Sehmisch <tmw@crushnet.org>
+
+ * src/defines.h, src/game-server/state.cpp: Attack direction is now
+ included in being attack messages.
+ * src/game-server/accountconnection.cpp: Player characters are now
+ spawned with full hit points (todo: save current hit points in
+ database when a character logs out so that players can't heal by
+ logging in and out).
+ * src/game-server/being.cpp, src/game-server/deathlistener.hpp,
+ src/game-server/spawnarea.hpp: Death listeners are now informed when
+ a being object is deleted.
+ * src/game-server/being.hpp: Being::damage() now returns the resulting
+ loss of hit points.
+ * src/game-server/character.cpp: Characters hit circle size is now
+ initialized properly.
+ * src/game-server/map.cpp, src/game-server/map.hpp,
+ src/game-server/mapcomposite.cpp, src/game-server/mapcomposite.hpp,
+ src/game-server/mapreader.cpp, src/state.cpp: Pathfinding now takes
+ the tiles that are occupied by beings into account. Map::find_path()
+ now has an optional argument that sets the maximum path cost.
+ * src/game-server/monster.cpp, src/game-server/monster.hpp,
+ src/game-server/spawnarea.cpp, src/game-server/thing.hpp: Implemented
+ monster attacking and provisoric monster AI. Monster now chase and
+ attack players that hurt them.
+ * src/game-server/spawnarea.cpp: Monsters are no longer spawned on
+ unwalkable tiles.
+
+2007-06-28 Guillaume Melquiond <guillaume.melquiong@gmail.com>
* src/game-server/spawnarea.cpp: Delegated creature insertion to the
State class so that it does not disturb object updating.
diff --git a/src/defines.h b/src/defines.h
index 73e50ed3..de5d1025 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -159,7 +159,7 @@ enum {
GPMSG_BEINGS_MOVE = 0x0280, // { W being id, B flags [, C position] [, W*2 destination] }*
GPMSG_ITEMS = 0x0281, // { W item id, W*2 position }*
PGMSG_ATTACK = 0x0290, // B direction
- GPMSG_BEING_ATTACK = 0x0291, // W being id
+ GPMSG_BEING_ATTACK = 0x0291, // W being id, B direction
PGMSG_SAY = 0x02A0, // S text
GPMSG_SAY = 0x02A1, // W being id, S text
PGMSG_USE_ITEM = 0x0300, // L item id
diff --git a/src/game-server/accountconnection.cpp b/src/game-server/accountconnection.cpp
index e9ea2256..3ae5816e 100644
--- a/src/game-server/accountconnection.cpp
+++ b/src/game-server/accountconnection.cpp
@@ -72,6 +72,7 @@ void AccountConnection::processMessage(MessageIn &msg)
std::string token = msg.readString(MAGIC_TOKEN_LENGTH);
Character *ptr = new Character(msg);
ptr->setSpeed(150); // TODO
+ ptr->fillHitpoints();// TODO: the current hit points should be saved in the database. Otherwise players could heal their characters by logging in and out again.
gameHandler->mTokenCollector.addPendingConnect(token, ptr);
} break;
diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp
index 82457524..5bb608c6 100644
--- a/src/game-server/being.cpp
+++ b/src/game-server/being.cpp
@@ -36,11 +36,20 @@ Being::Being(int type, int id):
}
Being::~Being()
-{}
+{
+ // Notify death listeners
+ DeathListeners::iterator i_end = mDeathListeners.end();
+ DeathListeners::iterator i;
+ for (i = mDeathListeners.begin(); i != i_end; ++i)
+ {
+ (*i)->deleted(this);
+ }
-void Being::damage(Damage damage)
+}
+
+int Being::damage(Damage damage)
{
- if (mAction == DEAD) return;
+ if (mAction == DEAD) return 0;
// TODO: Implement dodge chance
@@ -73,6 +82,8 @@ void Being::damage(Damage damage)
LOG_INFO("Being " << getPublicID() << " got hit");
if (mHitpoints == 0) die();
+
+ return HPloss;
}
void Being::die()
@@ -109,8 +120,8 @@ void Being::move()
void Being::performAttack(MapComposite *map)
{
- int SHORT_RANGE = 64;
- int SMALL_ANGLE = 45;
+ int SHORT_RANGE = 60;
+ int SMALL_ANGLE = 35;
Point ppos = getPosition();
int dir = getDirection();
diff --git a/src/game-server/being.hpp b/src/game-server/being.hpp
index e0d064bd..3872e661 100644
--- a/src/game-server/being.hpp
+++ b/src/game-server/being.hpp
@@ -60,7 +60,7 @@ enum Element
/**
* Beings and actors directions
*/
-enum
+enum Direction
{
DIRECTION_DOWN = 1,
DIRECTION_UP,
@@ -154,7 +154,7 @@ class Being : public MovingObject
* stats, deducts the result from the hitpoints and adds the result to
* the HitsTaken list.
*/
- void damage(Damage);
+ virtual int damage(Damage damage);
/**
* Kills the being
@@ -239,15 +239,13 @@ class Being : public MovingObject
int mHitpoints; /**< Hitpoints of the being */
Action mAction;
-
std::vector<unsigned short> mAttributes;
+ std::list<DeathListener*> mDeathListeners;
private:
Being(Being const &rhs);
Being &operator=(Being const &rhs);
- std::list<DeathListener*> mDeathListeners;
-
Hits mHitsTaken; /**< List of punches taken since last update */
};
diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp
index f05ebf1e..c33300b0 100644
--- a/src/game-server/character.cpp
+++ b/src/game-server/character.cpp
@@ -49,6 +49,8 @@ Character::Character(MessageIn & msg):
deserialize(msg);
// give the player 10 weapon skill for testing purpose
setAttribute(CHAR_SKILL_WEAPON_UNARMED, 10);
+
+ setSize(16);
}
/**
* Update the internal status.
diff --git a/src/game-server/deathlistener.hpp b/src/game-server/deathlistener.hpp
index b220b846..462f36da 100644
--- a/src/game-server/deathlistener.hpp
+++ b/src/game-server/deathlistener.hpp
@@ -42,6 +42,11 @@ class DeathListener
* Called when a being died.
*/
virtual void died(Being *being) = 0;
+
+ /**
+ * Called when a being is deleted.
+ */
+ virtual void deleted(Being *being) = 0;
};
typedef std::list<DeathListener*> DeathListeners;
diff --git a/src/game-server/map.cpp b/src/game-server/map.cpp
index 6ca447ae..447bc810 100644
--- a/src/game-server/map.cpp
+++ b/src/game-server/map.cpp
@@ -73,33 +73,34 @@ Map::setSize(int width, int height)
}
void
-Map::setWalk(int x, int y, bool walkable)
+Map::setPermWalk(int x, int y, bool walkable)
{
- metaTiles[x + y * width].walkable = walkable;
+ metaTiles[x + y * width].permWalkable = walkable;
}
-bool
-Map::getWalk(int x, int y)
+void
+Map::setTempWalk(int x, int y, bool walkable)
{
- // If walkable, check for colliding into a being
- if (!tileCollides(x, y))
+ metaTiles[x + y * width].tempWalkable = walkable;
+}
+
+void
+Map::resetTempWalk()
+{
+ for (int i = 0; i < width * height; i++)
{
- /*
- std::list<Being*>::iterator i = beings.begin();
- while (i != beings.end()) {
- Being *being = (*i);
- // Collision when non-portal being is found at this location
- if (being->x == x && being->y == y && being->job != 45) {
- return false;
- }
- i++;
- }
- */
- return true;
+ metaTiles[i].tempWalkable = metaTiles[i].permWalkable;
}
- else {
+}
+
+bool
+Map::getWalk(int x, int y)
+{
+ // You can't walk outside of the map
+ if (x < 0 || y < 0 || x >= width || y >= height) {
return false;
}
+ return metaTiles[x + y * width].tempWalkable;
}
bool
@@ -111,7 +112,7 @@ Map::tileCollides(int x, int y)
}
// Check if the tile is walkable
- return !metaTiles[x + y * width].walkable;
+ return !metaTiles[x + y * width].permWalkable;
}
MetaTile*
@@ -123,7 +124,7 @@ Map::getMetaTile(int x, int y)
static int const basicCost = 100;
std::list<PATH_NODE>
-Map::findPath(int startX, int startY, int destX, int destY)
+Map::findPath(int startX, int startY, int destX, int destY, int maxCost)
{
// Path to be built up (empty by default)
std::list<PATH_NODE> path;
@@ -194,7 +195,7 @@ Map::findPath(int startX, int startY, int destX, int destY)
MetaTile *t1 = getMetaTile(curr.x, curr.y + dy);
MetaTile *t2 = getMetaTile(curr.x + dx, curr.y);
- if (!(t1->walkable && t2->walkable))
+ if (!(t1->tempWalkable && t2->tempWalkable))
{
continue;
}
@@ -220,7 +221,7 @@ Map::findPath(int startX, int startY, int destX, int destY)
// Skip if Gcost becomes too much
// Warning: probably not entirely accurate
- if (Gcost > 20 * basicCost)
+ if (Gcost > maxCost * basicCost)
{
continue;
}
diff --git a/src/game-server/map.hpp b/src/game-server/map.hpp
index a7c1fe2a..b0840b2c 100644
--- a/src/game-server/map.hpp
+++ b/src/game-server/map.hpp
@@ -57,7 +57,8 @@ class MetaTile
int whichList; /**< No list, open list or closed list */
int parentX; /**< X coordinate of parent tile */
int parentY; /**< Y coordinate of parent tile */
- bool walkable; /**< Can beings walk on this tile */
+ bool permWalkable; /**< Can beings normally walk on this tile */
+ bool tempWalkable; /**< Can beings walk on this tile this tick? */
};
/**
@@ -114,10 +115,22 @@ class Map
getMetaTile(int x, int y);
/**
- * Set walkability flag for a tile
+ * Set permanent walkability flag for a tile
*/
void
- setWalk(int x, int y, bool walkable);
+ setPermWalk(int x, int y, bool walkable);
+
+ /**
+ * Set temporary walkability flag for a tile
+ */
+ void
+ setTempWalk(int x, int y, bool walkable);
+
+ /**
+ * Resets the temporary walkable status of all tiles to the permanent
+ * walkable status.
+ */
+ void resetTempWalk();
/**
* Tell if a tile is walkable or not, includes checking beings.
@@ -159,8 +172,7 @@ class Map
* Find a path from one location to the next.
*/
std::list<PATH_NODE>
- findPath(int startX, int startY,
- int destX, int destY);
+ findPath(int startX, int startY, int destX, int destY, int maxCost = 20);
private:
int width, height;
diff --git a/src/game-server/mapcomposite.cpp b/src/game-server/mapcomposite.cpp
index 5ca2330b..027db924 100644
--- a/src/game-server/mapcomposite.cpp
+++ b/src/game-server/mapcomposite.cpp
@@ -29,6 +29,8 @@
#include "game-server/mapcomposite.hpp"
#include "game-server/character.hpp"
+#include "utils/logger.h"
+
/* TODO: Implement overlapping map zones instead of strict partitioning.
Purpose: to decrease the number of zone changes, as overlapping allows for
hysteresis effect and prevents an object from changing zone each server
@@ -481,6 +483,7 @@ bool MapComposite::insert(Thing *ptr)
zones[(pos.x / zoneDiam) + (pos.y / zoneDiam) * mapWidth].insert(obj);
}
+ ptr->setMap(this);
things.push_back(ptr);
return true;
}
@@ -514,6 +517,8 @@ void MapComposite::remove(Thing *ptr)
void MapComposite::update()
{
+ map->resetTempWalk();
+
for (int i = 0; i < mapHeight * mapWidth; ++i)
{
zones[i].destinations.clear();
@@ -531,6 +536,9 @@ void MapComposite::update()
Point const &pos1 = obj->getOldPosition(),
&pos2 = obj->getPosition();
+
+ map->setTempWalk(pos2.x / 32, pos2.y / 32, false);
+
int src = (pos1.x / zoneDiam) + (pos1.y / zoneDiam) * mapWidth,
dst = (pos2.x / zoneDiam) + (pos2.y / zoneDiam) * mapWidth;
if (src != dst)
diff --git a/src/game-server/mapreader.cpp b/src/game-server/mapreader.cpp
index cc26f03f..db16cc3e 100644
--- a/src/game-server/mapreader.cpp
+++ b/src/game-server/mapreader.cpp
@@ -141,6 +141,7 @@ static Map *readMap(xmlNodePtr node, std::string const &path)
// Clean up tilesets
tilesetFirstGids.clear();
+ map->resetTempWalk();
return map;
}
@@ -258,5 +259,5 @@ static void setTileWithGid(Map *map, int x, int y, int gid)
set = *i;
}
- map->setWalk(x, y, gid == set);
+ map->setPermWalk(x, y, gid == set);
}
diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp
index de277ee7..4881a9b7 100644
--- a/src/game-server/monster.cpp
+++ b/src/game-server/monster.cpp
@@ -22,24 +22,145 @@
#include "game-server/monster.hpp"
+#include "game-server/collisiondetection.hpp"
+#include "game-server/mapcomposite.hpp"
+
#include "utils/logger.h"
Monster::Monster():
Being(OBJECT_MONSTER, 65535),
- mCountDown(0)
+ mCountDown(0),
+ mAttackTime(0),
+ mAttackPreDelay(5),
+ mAttackAftDelay(10)
{
LOG_DEBUG("Monster spawned!");
+ mAgressive = false; // TODO: get from monster database
+ mAgressionRange = 10; // TODO: get from monster database
mAttributes.resize(NB_ATTRIBUTES_CONTROLLED, 1); // TODO: fill with the real attributes
+
+ // some bogus values for testing monster attacks on players
+ setAttribute(BASE_ATTR_STRENGTH, 10);
+ setAttribute(MONSTER_SKILL_WEAPON, 3);
+
+ // set positions relative to target from which the monster can attack
+ mAttackPositions.push_back(AttackPosition(+32, 0, DIRECTION_LEFT));
+ mAttackPositions.push_back(AttackPosition(-32, 0, DIRECTION_RIGHT));
+ mAttackPositions.push_back(AttackPosition(0, +32, DIRECTION_DOWN));
+ mAttackPositions.push_back(AttackPosition(0, -32, DIRECTION_UP));
+}
+
+Monster::~Monster()
+{
+ // deactivate death listeners
+ std::map<Being *, int>::iterator i;
+ for (i = mAnger.begin(); i != mAnger.end(); i++)
+ {
+ i->first->removeDeathListener(this);
+ }
}
void Monster::update()
{
- /* Temporary "AI" behaviour that is purely artificial and not at all
- * intelligent.
- */
- if (mCountDown == 0)
+ // if dead do nothing but rot
+ if (mAction == DEAD)
+ {
+ mCountDown--;
+ if (mCountDown <= 0)
+ {
+ raiseUpdateFlags(UPDATEFLAG_REMOVE);
+ }
+ return;
+ }
+
+ // if currently attacking finish attack;
+ if (mAttackTime)
+ {
+ if (mAttackTime == mAttackAftDelay)
+ {
+ mAction = ATTACK;
+ raiseUpdateFlags(UPDATEFLAG_ATTACK);
+ }
+ mAttackTime--;
+ return;
+ }
+
+ // check potential attack positions
+ Being *bestAttackTarget = NULL;
+ int bestTargetPriority = 0;
+ Point bestAttackPosition;
+ Direction bestAttackDirection = DIRECTION_DOWN;
+
+ // iterate through objects nearby
+ for (MovingObjectIterator i(mMap->getAroundCharacterIterator(this, AROUND_AREA)); i; ++i)
+ {
+ // we only want to attack player characters
+ if ((*i)->getType() != OBJECT_CHARACTER) continue;
+
+ Being *target = static_cast<Being *> (*i);
+
+ // dead characters are ignored
+ if (target->getAction() == DEAD) continue;
+
+ // determine how much we hate the target
+ int targetPriority = 0;
+ std::map<Being *, int, std::greater<Being *> >::iterator angerIterator;
+ angerIterator = mAnger.find(target);
+ if (angerIterator != mAnger.end())
+ {
+ targetPriority = angerIterator->second;
+ }
+ else if (mAgressive)
+ {
+ targetPriority = 1;
+ }
+ else
+ {
+ continue;
+ }
+
+ // check all attack positions
+ for (std::list<AttackPosition>::iterator j = mAttackPositions.begin();
+ j != mAttackPositions.end();
+ j++)
+ {
+ Point attackPosition = (*i)->getPosition();
+ attackPosition.x += (*j).x;
+ attackPosition.y += (*j).y;
+
+ int posPriority = calculatePositionPriority(attackPosition,
+ targetPriority);
+ if (posPriority > bestTargetPriority)
+ {
+ bestAttackTarget = target;
+ bestTargetPriority = posPriority;
+ bestAttackPosition = attackPosition;
+ bestAttackDirection = (*j).direction;
+ }
+ }
+ }
+
+ // check if an attack position has been found
+ if (bestAttackTarget)
+ {
+ // check if we are there
+ if (bestAttackPosition == getPosition())
+ {
+ // we are there - let's get ready to beat the crap out of the target
+ setDirection(bestAttackDirection);
+ mAttackTime = mAttackPreDelay + mAttackAftDelay;
+ }
+ else
+ {
+ // we aren't there yet - let's move
+ setDestination(bestAttackPosition);
+ }
+ }
+ else
{
- if (mAction != DEAD)
+ // we have no target - let's wander around
+ mCountDown--;
+ if (mCountDown <= 0)
{
Point randomPos(rand() % 160 - 80 + getPosition().x,
rand() % 160 - 80 + getPosition().y);
@@ -49,20 +170,67 @@ void Monster::update()
LOG_DEBUG("Setting new random destination " << randomPos.x << ","
<< randomPos.y << " for being " << getPublicID());
}
- else
- {
- raiseUpdateFlags(UPDATEFLAG_REMOVE);
- }
+ }
+}
+
+int Monster::calculatePositionPriority(Point position, int targetPriority)
+{
+ Point thisPos = getPosition();
+
+ // check if we already are on this position
+ if (thisPos.x / 32 == position.x / 32 &&
+ thisPos.y / 32 == position.y / 32)
+ {
+ return targetPriority *= mAgressionRange;
+ }
+
+ std::list<PATH_NODE> path;
+ path = mMap->getMap()->findPath(thisPos.x / 32,
+ thisPos.y / 32,
+ position.x / 32,
+ position.y / 32,
+ mAgressionRange);
+
+ if (path.empty() || path.size() >= mAgressionRange)
+ {
+ return 0;
}
else
{
- mCountDown--;
+ return targetPriority * (mAgressionRange - path.size());
+ }
+}
+
+void Monster::died (Being *being)
+{
+ mAnger.erase(being);
+ mDeathListeners.remove((DeathListener *)being);
+}
+
+int Monster::damage(Damage damage)
+{
+ int HPLoss = Being::damage(damage);
+ if ( HPLoss
+ && damage.source
+ && damage.source->getType() == OBJECT_CHARACTER
+ )
+ {
+ if (mAnger.find(damage.source) == mAnger.end())
+ {
+ damage.source->addDeathListener(this);
+ mAnger[damage.source] = HPLoss;
+ }
+ else
+ {
+ mAnger[damage.source] += HPLoss;
+ }
}
+ return HPLoss;
}
void Monster::die()
{
- mCountDown = 50; //sets remove time to 5 seconds
+ mCountDown = 50; // sets remove time to 5 seconds
Being::die();
}
diff --git a/src/game-server/monster.hpp b/src/game-server/monster.hpp
index c92a7698..616aa9d4 100644
--- a/src/game-server/monster.hpp
+++ b/src/game-server/monster.hpp
@@ -23,12 +23,35 @@
#ifndef _TMWSERV_MONSTER_H_
#define _TMWSERV_MONSTER_H_
+#include <map>
+
#include "game-server/being.hpp"
+#include "game-server/deathlistener.hpp"
+
+class MapComposite;
+class MovingObject;
+
+/**
+ * Structure holding possible positions relative to the target from which
+ * the monster can attack
+ */
+struct AttackPosition
+{
+ AttackPosition(int posX, int posY, Direction dir):
+ x(posX),
+ y(posY),
+ direction(dir)
+ {};
+
+ int x;
+ int y;
+ Direction direction;
+};
/**
* The class for a fightable monster with its own AI
*/
-class Monster : public Being
+class Monster : public Being, public DeathListener
{
public:
/**
@@ -37,6 +60,11 @@ class Monster : public Being
Monster();
/**
+ * Destructor.
+ */
+ ~Monster();
+
+ /**
* Performs one step of controller logic.
*/
void update();
@@ -46,6 +74,25 @@ class Monster : public Being
*/
virtual void die();
+ /**
+ * Calls the damage function in Being and updates the aggro list
+ */
+ virtual int damage(Damage damage);
+
+ /**
+ * Getting informed that a being that might be on the target list died
+ */
+ virtual void died(Being *being);
+
+ /**
+ * Getting informed that a being that might be on the target list is
+ * deleted
+ */
+ virtual void deleted(Being *being)
+ {
+ died(being);
+ }
+
protected:
/**
* Gets the stats of the currently equipped weapon that are relevant
@@ -59,8 +106,19 @@ class Monster : public Being
void calculateDerivedAttributes();
private:
- /** Count down till next random movement (temporary). */
- unsigned int mCountDown;
+ int calculatePositionPriority(Point position, int targetPriority);
+
+ int mCountDown; /**< Count down till next random movement (temporary). */
+ std::map<Being *, int> mAnger; /**< Aggression towards other beings */
+ int mAttackTime; /**< Delay until monster can attack */
+ // TODO: the following vars should all be the same for all monsters of
+ // the same type. So they should be put into some central data structure
+ // to save memory.
+ int mAttackPreDelay; /**< time between decision to make an attack and performing the attack */
+ int mAttackAftDelay; /**< time it takes to perform an attack */
+ bool mAgressive; /**< Does the monster attack without being provoked? */
+ unsigned mAgressionRange; /**< Distance the monster tracks enemies in */
+ std::list<AttackPosition> mAttackPositions; /**< set positions relative to target from which the monster can attack */
};
#endif // _TMWSERV_MONSTER_H_
diff --git a/src/game-server/spawnarea.cpp b/src/game-server/spawnarea.cpp
index 9d7687ff..780e3e65 100644
--- a/src/game-server/spawnarea.cpp
+++ b/src/game-server/spawnarea.cpp
@@ -23,6 +23,7 @@
#include "spawnarea.hpp"
+#include "game-server/mapcomposite.hpp"
#include "game-server/monster.hpp"
#include "game-server/state.hpp"
@@ -53,22 +54,40 @@ SpawnArea::update()
if (mNextSpawn == 0)
{
- Being *being = new Monster();
- being->addDeathListener(this);
+ //find a free spawn location. Give up after 10 tries
+ int c = 10;
+ Point position;
+ do
+ {
+ position = Point(mZone.x + rand() % mZone.w,
+ mZone.y + rand() % mZone.h);
+ c--;
+ } while (! mMap->getMap()->getWalk(position.x / 32, position.y / 32)
+ && c);
- // some bogus stats for testing
- being->setSpeed(150);
- being->setSize(8);
- being->setAttribute(BASE_ATTR_VITALITY, 10);
- being->fillHitpoints();
+ if (c >= 0)
+ {
+ Being *being = new Monster();
+ being->addDeathListener(this);
- being->setMapId(1);
- being->setPosition(Point(mZone.x + rand() % mZone.w,
- mZone.y + rand() % mZone.h));
- DelayedEvent e = { EVENT_INSERT };
- gameState->enqueueEvent(being, e);
+ // some bogus stats for testing
+ being->setSpeed(150);
+ being->setSize(8);
+ being->setAttribute(BASE_ATTR_VITALITY, 10);
+ being->fillHitpoints();
- mNumBeings++;
+ being->setMapId(1);
+ being->setPosition(position);
+ DelayedEvent e = { EVENT_INSERT };
+ gameState->enqueueEvent(being, e);
+
+ mNumBeings++;
+ }
+ else {
+ //TODO: This log message should have more information when
+ // more flexibility is added to the spawn area
+ LOG_WARN("Unable to find a free spawn location for monster");
+ }
}
}
diff --git a/src/game-server/spawnarea.hpp b/src/game-server/spawnarea.hpp
index 1debb1b3..2f8ff51a 100644
--- a/src/game-server/spawnarea.hpp
+++ b/src/game-server/spawnarea.hpp
@@ -45,6 +45,8 @@ class SpawnArea : public Thing, public DeathListener
virtual void died(Being *being);
+ virtual void deleted(Being *being) {};
+
protected:
Rectangle mZone;
int mMaxBeings; /**< Maximum population of this area. */
diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp
index 929d4304..c27f9209 100644
--- a/src/game-server/state.cpp
+++ b/src/game-server/state.cpp
@@ -69,7 +69,7 @@ void State::updateMap(MapComposite *map)
(*i)->move();
}
- // 4. remove dead beings
+ // 4. remove dead beings.
for (MovingObjectIterator i(map->getWholeMapIterator()); i; ++i)
{
if ((*i)->getUpdateFlags() & UPDATEFLAG_REMOVE)
@@ -79,6 +79,7 @@ void State::updateMap(MapComposite *map)
}
}
+ // 5. update the map itself.
map->update();
}
diff --git a/src/game-server/thing.hpp b/src/game-server/thing.hpp
index 547885c4..1d95c23f 100644
--- a/src/game-server/thing.hpp
+++ b/src/game-server/thing.hpp
@@ -23,6 +23,8 @@
#ifndef _TMWSERV_THING_H_
#define _TMWSERV_THING_H_
+class MapComposite;
+
/**
* Object type enumeration.
*/
@@ -50,7 +52,8 @@ class Thing
* Constructor.
*/
Thing(int type)
- : mType(type)
+ : mMap(NULL),
+ mType(type)
{}
/**
@@ -100,11 +103,20 @@ class Thing
{ return mMapId; }
/**
- * Sets the map this thing is located on.
+ * Sets the map ID this thing is located on.
*/
void setMapId(int mapId)
{ mMapId = mapId; }
+ /**
+ * Sets the map this thing is located on.
+ */
+ void setMap(MapComposite *map)
+ { mMap = map; }
+
+ protected:
+ MapComposite *mMap; /**< Map the thing is on */
+
private:
unsigned short mMapId; /**< ID of the map this thing is on. */
char mType; /**< Type of this thing. */