diff options
Diffstat (limited to 'src/game-server/state.cpp')
-rw-r--r-- | src/game-server/state.cpp | 311 |
1 files changed, 160 insertions, 151 deletions
diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp index 3bb2e478..95e093c2 100644 --- a/src/game-server/state.cpp +++ b/src/game-server/state.cpp @@ -24,10 +24,11 @@ #include <cassert> #include "controller.h" +#include "defines.h" #include "map.h" -#include "mapcomposite.h" #include "point.h" #include "game-server/gamehandler.hpp" +#include "game-server/mapcomposite.hpp" #include "game-server/mapmanager.hpp" #include "game-server/state.hpp" #include "net/messageout.hpp" @@ -56,182 +57,190 @@ State::~State() } } -void -State::update() +void State::updateMap(MapComposite *map) { - /* - * Update game state (update AI, etc.) - */ - for (std::map< unsigned, MapComposite * >::iterator m = maps.begin(), - m_end = maps.end(); m != m_end; ++m) + // 1. update object status. + for (ObjectIterator i(map->getWholeMapIterator()); i; ++i) { - MapComposite *map = m->second; + (*i)->update(); + } - for (ObjectIterator o(map->getWholeMapIterator()); o; ++o) + // 2. perform attacks. + for (MovingObjectIterator i(map->getWholeMapIterator()); i; ++i) + { + MovingObject *o = *i; + if (o->getUpdateFlags() & ATTACK) { - (*o)->update(); - if ((*o)->getType() == OBJECT_PLAYER || (*o)->getType() == OBJECT_MONSTER) - { - static_cast< Being * >(*o)->clearHitsTaken(); - } + static_cast< Being * >(o)->performAttack(map); } + } + + // 3. move objects around and update zones. + for (MovingObjectIterator i(map->getWholeMapIterator()); i; ++i) + { + (*i)->move(); + } + map->update(); +} + +void State::informPlayer(MapComposite *map, Player *p) +{ + MessageOut moveMsg(GPMSG_BEINGS_MOVE); + MessageOut damageMsg(GPMSG_BEINGS_DAMAGE); + Point pold = p->getOldPosition(), ppos = p->getPosition(); + int pid = p->getPublicID(), pflags = p->getUpdateFlags(); + + for (MovingObjectIterator i(map->getAroundPlayerIterator(p, AROUND_AREA)); i; ++i) + { + MovingObject *o = *i; - for (MovingObjectIterator o(map->getWholeMapIterator()); o; ++o) + Point oold = o->getOldPosition(), opos = o->getPosition(); + int otype = o->getType(); + int oid = o->getPublicID(), oflags = o->getUpdateFlags(); + int flags = 0; + + // Send attack messages. + if ((oflags & ATTACK) && oid != pid && ppos.inRangeOf(opos)) { - if ((*o)->getUpdateFlags() & ATTACK) - { - static_cast< Being * >(*o)->performAttack(m->second); - } + MessageOut AttackMsg(GPMSG_BEING_ATTACK); + AttackMsg.writeShort(oid); + gameHandler->sendTo(p, AttackMsg); } - for (MovingObjectIterator o(map->getWholeMapIterator()); o; ++o) + // Send damage messages. + if (otype == OBJECT_PLAYER || otype == OBJECT_MONSTER) { - (*o)->move(); + Being *victim = static_cast< Being * >(o); + Hits const &hits = victim->getHitsTaken(); + for (Hits::const_iterator j = hits.begin(), + j_end = hits.end(); j != j_end; ++j) + { + damageMsg.writeShort(oid); + damageMsg.writeShort(*j); + } } - map->update(); + /* Check whether this player and this moving object were around + the last time and whether they will be around the next time. */ + bool wereInRange = pold.inRangeOf(oold) && + !((pflags | oflags) & NEW_ON_MAP); + bool willBeInRange = ppos.inRangeOf(opos); - /* - * Inform clients about changes in the game state - */ - for (PlayerIterator p(map->getWholeMapIterator()); p; ++p) + // Send enter/leaver messages. + if (!wereInRange) { - MessageOut moveMsg(GPMSG_BEINGS_MOVE); - MessageOut damageMsg(GPMSG_BEINGS_DAMAGE); - - for (MovingObjectIterator o(map->getAroundPlayerIterator(*p)); o; ++o) + // o was outside p's range. + if (!willBeInRange) { + // Nothing to report: o will not be inside p's range. + continue; + } + flags |= MOVING_DESTINATION; - Point os = (*o)->getOldPosition(); - Point on = (*o)->getPosition(); - - int flags = 0; - - // Send attack messages - if ( (*o)->getUpdateFlags() & ATTACK - && (*o)->getPublicID() != (*p)->getPublicID() - && (*p)->getPosition().inRangeOf(on) - ) + MessageOut enterMsg(GPMSG_BEING_ENTER); + enterMsg.writeByte(otype); + enterMsg.writeShort(oid); + switch (otype) { + case OBJECT_PLAYER: { - MessageOut AttackMsg (GPMSG_BEING_ATTACK); - AttackMsg.writeShort((*o)->getPublicID()); - - LOG_DEBUG("Sending attack packet from " << (*o)->getPublicID() - << " to " << (*p)->getPublicID(), 0); + Player *q = static_cast< Player * >(o); + enterMsg.writeString(q->getName()); + enterMsg.writeByte(q->getHairStyle()); + enterMsg.writeByte(q->getHairColor()); + enterMsg.writeByte(q->getGender()); + } break; + case OBJECT_MONSTER: + { + enterMsg.writeShort(0); // TODO: The monster ID + } break; + default: + assert(false); // TODO + } + gameHandler->sendTo(p, enterMsg); + } + else if (!willBeInRange) + { + // o is no longer visible from p. + MessageOut leaveMsg(GPMSG_BEING_LEAVE); + leaveMsg.writeShort(oid); + gameHandler->sendTo(p, leaveMsg); + continue; + } + else if (oold.x == opos.x && oold.y == opos.y) + { + // o does not move, nothing to report. + continue; + } - gameHandler->sendTo(*p, AttackMsg); - } + /* At this point, either o has entered p's range, either o is + moving inside p's range. Report o's movements. */ - // Send damage messages + Point odst = o->getDestination(); + if (opos.x != odst.x || opos.y != odst.y) + { + flags |= MOVING_POSITION; + if (oflags & NEW_DESTINATION) + { + flags |= MOVING_DESTINATION; + } + } + else + { + // No need to synchronize on the very last step. + flags |= MOVING_DESTINATION; + } - if ((*o)->getType() == OBJECT_PLAYER || (*o)->getType() == OBJECT_MONSTER) - { - Being *victim = static_cast< Being * >(*o); - Hits const &hits = victim->getHitsTaken(); - for (Hits::const_iterator i = hits.begin(), - i_end = hits.end(); i != i_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. - */ - bool wereInRange = (*p)->getOldPosition().inRangeOf(os) && - !(((*p)->getUpdateFlags() | (*o)->getUpdateFlags()) & NEW_ON_MAP); - bool willBeInRange = (*p)->getPosition().inRangeOf(on); - if (!wereInRange) - { - // o was outside p's range. - if (!willBeInRange) - { - // Nothing to report: o will not be inside p's range. - continue; - } - flags |= MOVING_DESTINATION; - - int type = (*o)->getType(); - MessageOut enterMsg(GPMSG_BEING_ENTER); - enterMsg.writeByte(type); - enterMsg.writeShort((*o)->getPublicID()); - switch (type) { - case OBJECT_PLAYER: - { - Player *q = static_cast< Player * >(*o); - enterMsg.writeString(q->getName()); - enterMsg.writeByte(q->getHairStyle()); - enterMsg.writeByte(q->getHairColor()); - enterMsg.writeByte(q->getGender()); - } break; - case OBJECT_MONSTER: - { - enterMsg.writeShort(0); // TODO: The monster ID - } break; - default: - assert(false); // TODO - } - gameHandler->sendTo(*p, enterMsg); - } - else if (!willBeInRange) - { - // o is no longer visible from p. - MessageOut leaveMsg(GPMSG_BEING_LEAVE); - leaveMsg.writeShort((*o)->getPublicID()); - gameHandler->sendTo(*p, leaveMsg); - continue; - } - else if (os.x == on.x && os.y == on.y) - { - // o does not move, nothing to report. - continue; - } + // Send move messages. + moveMsg.writeShort(oid); + moveMsg.writeByte(flags); + if (flags & MOVING_POSITION) + { + moveMsg.writeCoordinates(opos.x / 32, opos.y / 32); + } + if (flags & MOVING_DESTINATION) + { + moveMsg.writeShort(odst.x); + moveMsg.writeShort(odst.y); + } + } - /* At this point, either o has entered p's range, either o is - moving inside p's range. Report o's movements. */ + // Do not send a packet if nothing happened in p's range. + if (moveMsg.getLength() > 2) + gameHandler->sendTo(p, moveMsg); - Point od = (*o)->getDestination(); - if (on.x != od.x || on.y != od.y) - { - flags |= MOVING_POSITION; - if ((*o)->getUpdateFlags() & NEW_DESTINATION) - { - flags |= MOVING_DESTINATION; - } - } - else - { - // no need to synchronize on the very last step - flags |= MOVING_DESTINATION; - } + if (damageMsg.getLength() > 2) + gameHandler->sendTo(p, damageMsg); +} - moveMsg.writeShort((*o)->getPublicID()); - moveMsg.writeByte(flags); - if (flags & MOVING_POSITION) - { - moveMsg.writeCoordinates(on.x / 32, on.y / 32); - } - if (flags & MOVING_DESTINATION) - { - moveMsg.writeShort(od.x); - moveMsg.writeShort(od.y); - } - } +void State::update() +{ + /* + * Update game state (update AI, etc.) + */ + for (std::map< unsigned, MapComposite * >::iterator m = maps.begin(), + m_end = maps.end(); m != m_end; ++m) + { + MapComposite *map = m->second; - // Don't send a packet if nothing happened in p's range. - if (moveMsg.getLength() > 2) - gameHandler->sendTo(*p, moveMsg); + updateMap(map); - if (damageMsg.getLength() > 2) - gameHandler->sendTo(*p, damageMsg); + /* + * Inform clients about changes in the game state + */ + for (PlayerIterator p(map->getWholeMapIterator()); p; ++p) + { + informPlayer(map, *p); } - for (ObjectIterator o(map->getWholeMapIterator()); o; ++o) + for (ObjectIterator i(map->getWholeMapIterator()); i; ++i) { - (*o)->clearUpdateFlags(); + Object *o = *i; + o->clearUpdateFlags(); + int type = o->getType(); + if (type == OBJECT_PLAYER || type == OBJECT_MONSTER) + { + static_cast< Being * >(o)->clearHitsTaken(); + } } } } @@ -278,7 +287,7 @@ State::removeObject(ObjectPtr objectPtr) msg.writeShort(obj->getPublicID()); Point objectPos = obj->getPosition(); - for (PlayerIterator p(map->getAroundObjectIterator(obj)); p; ++p) + for (PlayerIterator p(map->getAroundObjectIterator(obj, AROUND_AREA)); p; ++p) { if (*p != obj && objectPos.inRangeOf((*p)->getPosition())) { @@ -321,7 +330,7 @@ void State::sayAround(Object *obj, std::string text) MapComposite *map = m->second; Point speakerPosition = obj->getPosition(); - for (PlayerIterator i(map->getAroundObjectIterator(obj)); i; ++i) + for (PlayerIterator i(map->getAroundObjectIterator(obj, AROUND_AREA)); i; ++i) { if (speakerPosition.inRangeOf((*i)->getPosition())) { |