bool MapManager::raiseActive(int mapId) { Maps::iterator i = maps.find(mapId); assert(i != maps.end()); MapComposite *composite = i->second; if (composite->isActive()) { return true; } std::string file = "maps/" + composite->getName() + ".tmx"; if (!ResourceManager::exists(file)) { file += ".gz"; } if (MapReader::readMap(file, composite)) { LOG_INFO("Activated map \"" << file << "\" (id " << mapId << ")"); return true; } else { LOG_WARN("Couldn't activate invalid map \"" << file << "\" (id " << mapId << ")"); return false; } }
void AccountConnection::sendStatistics() { MessageOut msg(GAMSG_STATISTICS); const MapManager::Maps &maps = MapManager::getMaps(); for (MapManager::Maps::const_iterator i = maps.begin(), i_end = maps.end(); i != i_end; ++i) { MapComposite *m = i->second; if (!m->isActive()) continue; msg.writeInt16(i->first); int nbEntities = 0, nbMonsters = 0; typedef std::vector< Entity * > Entities; const Entities &things = m->getEverything(); std::vector< int > players; for (Entities::const_iterator j = things.begin(), j_end = things.end(); j != j_end; ++j) { Entity *t = *j; switch (t->getType()) { case OBJECT_CHARACTER: players.push_back (static_cast< Character * >(t)->getDatabaseID()); break; case OBJECT_MONSTER: ++nbMonsters; break; default: ++nbEntities; } } msg.writeInt16(nbEntities); msg.writeInt16(nbMonsters); msg.writeInt16(players.size()); for (std::vector< int >::const_iterator j = players.begin(), j_end = players.end(); j != j_end; ++j) { msg.writeInt32(*j); } } send(msg); }
bool GameState::insert(Entity *ptr) { assert(!dbgLockObjects); MapComposite *map = ptr->getMap(); assert(map && map->isActive()); /* Non-visible objects have neither position nor public ID, so their insertion cannot fail. Take care of them first. */ if (!ptr->isVisible()) { map->insert(ptr); ptr->signal_inserted.emit(ptr); return true; } // Check that coordinates are actually valid. Actor *obj = static_cast< Actor * >(ptr); Map *mp = map->getMap(); Point pos = obj->getPosition(); if ((int)pos.x / mp->getTileWidth() >= mp->getWidth() || (int)pos.y / mp->getTileHeight() >= mp->getHeight()) { LOG_ERROR("Tried to insert an actor at position " << pos.x << ',' << pos.y << " outside map " << map->getID() << '.'); // Set an arbitrary small position. pos = Point(100, 100); obj->setPosition(pos); } if (!map->insert(obj)) { // The map is overloaded, no room to add a new actor LOG_ERROR("Too many actors on map " << map->getID() << '.'); return false; } obj->signal_inserted.emit(obj); // DEBUG INFO switch (obj->getType()) { case OBJECT_ITEM: LOG_DEBUG("Item inserted: " << obj->getComponent<ItemComponent>()->getItemClass()->getDatabaseID()); break; case OBJECT_NPC: LOG_DEBUG("NPC inserted: " << obj->getComponent<NpcComponent>()->getNpcId()); break; case OBJECT_CHARACTER: LOG_DEBUG("Player inserted: " << static_cast<Being*>(obj)->getName()); break; case OBJECT_EFFECT: LOG_DEBUG("Effect inserted: " << obj->getComponent<EffectComponent>()->getEffectId()); break; case OBJECT_MONSTER: LOG_DEBUG("Monster inserted: " << static_cast<Monster*>(obj)->getSpecy()->getId()); break; case OBJECT_ACTOR: case OBJECT_OTHER: default: LOG_DEBUG("Entity inserted: " << obj->getType()); break; } obj->raiseUpdateFlags(UPDATEFLAG_NEW_ON_MAP); if (obj->getType() != OBJECT_CHARACTER) return true; /* Since the player does not know yet where in the world its character is, we send a map-change message, even if it is the first time it connects to this server. */ MessageOut mapChangeMessage(GPMSG_PLAYER_MAP_CHANGE); mapChangeMessage.writeString(map->getName()); mapChangeMessage.writeInt16(pos.x); mapChangeMessage.writeInt16(pos.y); gameHandler->sendTo(static_cast< Character * >(obj), mapChangeMessage); // update the online state of the character accountHandler->updateOnlineStatus( static_cast< Character * >(obj)->getDatabaseID(), true); return true; }
void GameState::update(int tick) { currentTick = tick; #ifndef NDEBUG dbgLockObjects = true; #endif ScriptManager::currentState()->update(); // Update game state (update AI, etc.) const MapManager::Maps &maps = MapManager::getMaps(); for (MapManager::Maps::const_iterator m = maps.begin(), m_end = maps.end(); m != m_end; ++m) { MapComposite *map = m->second; if (!map->isActive()) continue; map->update(); for (CharacterIterator p(map->getWholeMapIterator()); p; ++p) { informPlayer(map, *p); } for (ActorIterator it(map->getWholeMapIterator()); it; ++it) { Actor *a = *it; a->clearUpdateFlags(); if (a->canFight()) { static_cast< Being * >(a)->clearHitsTaken(); } } } # ifndef NDEBUG dbgLockObjects = false; # endif // Take care of events that were delayed because of their side effects. for (DelayedEvents::iterator it = delayedEvents.begin(), it_end = delayedEvents.end(); it != it_end; ++it) { const DelayedEvent &e = it->second; Actor *o = it->first; switch (e.type) { case EVENT_REMOVE: remove(o); if (o->getType() == OBJECT_CHARACTER) { Character *ch = static_cast< Character * >(o); ch->disconnected(); gameHandler->kill(ch); } delete o; break; case EVENT_INSERT: insertOrDelete(o); break; case EVENT_WARP: assert(o->getType() == OBJECT_CHARACTER); warp(static_cast< Character * >(o), e.map, e.x, e.y); break; } } delayedEvents.clear(); }
void GameState::update(int worldTime) { # ifndef NDEBUG dbgLockObjects = true; # endif // Update game state (update AI, etc.) const MapManager::Maps &maps = MapManager::getMaps(); for (MapManager::Maps::const_iterator m = maps.begin(), m_end = maps.end(); m != m_end; ++m) { MapComposite *map = m->second; if (!map->isActive()) { continue; } updateMap(map); for (CharacterIterator p(map->getWholeMapIterator()); p; ++p) { informPlayer(map, *p); /* sending the whole character is overhead for the database, it should be replaced by a syncbuffer. see: game-server/accountconnection: AccountConnection::syncChanges() if (worldTime % 2000 == 0) { accountHandler->sendCharacterData(*p); } */ } for (ActorIterator i(map->getWholeMapIterator()); i; ++i) { Actor *a = *i; a->clearUpdateFlags(); if (a->canFight()) { static_cast< Being * >(a)->clearHitsTaken(); } } } # ifndef NDEBUG dbgLockObjects = false; # endif // Take care of events that were delayed because of their side effects. for (DelayedEvents::iterator i = delayedEvents.begin(), i_end = delayedEvents.end(); i != i_end; ++i) { const DelayedEvent &e = i->second; Actor *o = i->first; switch (e.type) { case EVENT_REMOVE: remove(o); if (o->getType() == OBJECT_CHARACTER) { Character *ch = static_cast< Character * >(o); ch->disconnected(); gameHandler->kill(ch); } delete o; break; case EVENT_INSERT: insertSafe(o); break; case EVENT_WARP: assert(o->getType() == OBJECT_CHARACTER); warp(static_cast< Character * >(o), e.map, e.x, e.y); break; } } delayedEvents.clear(); }