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; } }
/** * Initializes the map content. This creates the warps, spawn areas, npcs and * other scripts. */ void MapComposite::initializeContent() { mContent = new MapContent(mMap); const std::vector<MapObject *> &objects = mMap->getObjects(); for (size_t i = 0; i < objects.size(); ++i) { const MapObject *object = objects.at(i); const std::string &type = object->getType(); if (utils::compareStrI(type, "WARP") == 0) { const std::string destMapName = object->getProperty("DEST_MAP"); const Rectangle &sourceBounds = object->getBounds(); MapComposite *destMap = MapManager::getMap(destMapName); // check destination map if (!destMap) { if (destMapName.empty()) { // this must be a one way warp target continue; } LOG_ERROR("Warp \"" << object->getName() << "\" targets missing map \"" << destMapName << "\" in " << getName()); continue; } TriggerAction* action; if (object->hasProperty("DEST_NAME")) { // warp to an object // get destination object name const std::string destMapObjectName = object->getProperty("DEST_NAME"); // get target object and validate it const MapObject *destination = destMap->findMapObject(destMapObjectName, "WARP"); if (!destination) { LOG_ERROR("Warp \"" << object->getName() << "\" from map " << getName() << " targets missing warp \"" << destMapObjectName << "\" " << " on map " << destMap->getName()); continue; } const Rectangle &destinationBounds = destination->getBounds(); const std::string &exit = destination->getProperty("EXIT_DIRECTION"); if (exit.empty()) { // old style WARP, warp to center of that object int destX = destinationBounds.x + destinationBounds.w / 2; int destY = destinationBounds.y + destinationBounds.h / 2; action = new WarpAction(destMap, Point(destX, destY)); } else { // newer and cooler warp AutowarpAction::ExitDirection exitDir; // find the exit direction if (utils::compareStrI(exit, "NORTH") == 0) { exitDir = AutowarpAction::ExitNorth; } else if (utils::compareStrI(exit, "EAST") == 0) { exitDir = AutowarpAction::ExitEast; } else if (utils::compareStrI(exit, "SOUTH") == 0) { exitDir = AutowarpAction::ExitSouth; } else if (utils::compareStrI(exit, "WEST") == 0) { exitDir = AutowarpAction::ExitWest; } else { // invalid or missing exit direction if (exit.empty()) { LOG_ERROR("Warp target \"" << destMapObjectName << "\" on map " << destMap->getName() << " is missing exit direction!"); } else { LOG_ERROR("Warp target \"" << destMapObjectName << "\" on map " << destMap->getName() << " has an invalid exit direction \"" << exit << "\"!"); } continue; } action = new AutowarpAction(destMap, sourceBounds, destinationBounds, exitDir); } } else if (object->hasProperty("DEST_X") && object->hasProperty("DEST_Y")) { // warp to absolute position int destX = utils::stringToInt(object->getProperty("DEST_X")); int destY = utils::stringToInt(object->getProperty("DEST_Y")); action = new WarpAction(destMap, Point(destX, destY)); } else { LOG_ERROR("Warp \"" << object->getName() << "\" on map " << getName() << " is invalid!"); continue; } // add this trigger to the map Entity *entity = new Entity(OBJECT_OTHER, this); entity->addComponent( new TriggerAreaComponent( sourceBounds, action, false ) ); insert(entity); } else if (utils::compareStrI(type, "SPAWN") == 0) { MonsterClass *monster = 0; int maxBeings = utils::stringToInt(object->getProperty("MAX_BEINGS")); int spawnRate = utils::stringToInt(object->getProperty("SPAWN_RATE")); std::string monsterName = object->getProperty("MONSTER_ID"); int monsterId = utils::stringToInt(monsterName); if (monsterId) { monster = monsterManager->getMonster(monsterId); if (!monster) { LOG_WARN("Couldn't find monster ID " << monsterId << " for spawn area"); } } else { monster = monsterManager->getMonsterByName(monsterName); if (!monster) { LOG_WARN("Couldn't find monster " << monsterName << " for spawn area"); } } if (monster && maxBeings && spawnRate) { Entity *entity = new Entity(OBJECT_OTHER, this); SpawnAreaComponent *spawnArea = new SpawnAreaComponent(monster, object->getBounds(), maxBeings, spawnRate); entity->addComponent(spawnArea); insert(entity); } } else if (utils::compareStrI(type, "NPC") == 0) { int npcId = utils::stringToInt(object->getProperty("NPC_ID")); std::string gender = object->getProperty("GENDER"); std::string scriptText = object->getProperty("SCRIPT"); if (npcId && !scriptText.empty()) { Script *script = ScriptManager::currentState(); script->loadNPC(object->getName(), npcId, ManaServ::getGender(gender), object->getX(), object->getY(), scriptText.c_str(), this); } else { LOG_WARN("Unrecognized format for npc"); } } else if (utils::compareStrI(type, "SCRIPT") == 0) { std::string scriptFilename = object->getProperty("FILENAME"); std::string scriptText = object->getProperty("TEXT"); Script *script = ScriptManager::currentState(); Script::Context context; context.map = this; if (!scriptFilename.empty()) { script->loadFile(scriptFilename, context); } else if (!scriptText.empty()) { std::string name = "'" + object->getName() + "'' in " + mName; script->load(scriptText.c_str(), name.c_str(), context); } else { LOG_WARN("Unrecognized format for script"); } } } }
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; }
/** * Initializes the map content. This creates the warps, spawn areas, npcs and * other scripts. */ void MapComposite::initializeContent() { mContent = new MapContent(mMap); const std::vector<MapObject *> &objects = mMap->getObjects(); for (size_t i = 0; i < objects.size(); ++i) { const MapObject *object = objects.at(i); const std::string &type = object->getType(); if (utils::compareStrI(type, "WARP") == 0) { std::string destMapName = object->getProperty("DEST_MAP"); std::string destMapObjectName = object->getProperty("DEST_NAME"); MapComposite *destMap = MapManager::getMap(destMapName); int destX = 0; int destY = 0; if (destMap && !destMapObjectName.empty()) { const MapObject *obj = destMap->findMapObject(destMapObjectName, "WARP"); if (obj) { const Rectangle &rect = obj->getBounds(); destX = rect.x + rect.w / 2; destY = rect.y + rect.h / 2; } else { LOG_ERROR("Warp target \"" << destMapObjectName << "\" " << "was not found on the map " << destMap->getName()); } } else { destX = utils::stringToInt(object->getProperty("DEST_X")); destY = utils::stringToInt(object->getProperty("DEST_Y")); } if (destMap && destX && destY) { Entity *entity = new Entity(OBJECT_OTHER, this); WarpAction *action = new WarpAction(destMap, destX, destY); entity->addComponent( new TriggerAreaComponent(object->getBounds(), action, false)); insert(entity); } else { LOG_WARN("Unrecognized warp format on map " << mName); } } else if (utils::compareStrI(type, "SPAWN") == 0) { MonsterClass *monster = 0; int maxBeings = utils::stringToInt(object->getProperty("MAX_BEINGS")); int spawnRate = utils::stringToInt(object->getProperty("SPAWN_RATE")); std::string monsterName = object->getProperty("MONSTER_ID"); int monsterId = utils::stringToInt(monsterName); if (monsterId) { monster = monsterManager->getMonster(monsterId); if (!monster) { LOG_WARN("Couldn't find monster ID " << monsterId << " for spawn area"); } } else { monster = monsterManager->getMonsterByName(monsterName); if (!monster) { LOG_WARN("Couldn't find monster " << monsterName << " for spawn area"); } } if (monster && maxBeings && spawnRate) { Entity *entity = new Entity(OBJECT_OTHER, this); SpawnAreaComponent *spawnArea = new SpawnAreaComponent(monster, object->getBounds(), maxBeings, spawnRate); entity->addComponent(spawnArea); insert(entity); } } else if (utils::compareStrI(type, "NPC") == 0) { int npcId = utils::stringToInt(object->getProperty("NPC_ID")); std::string gender = object->getProperty("GENDER"); std::string scriptText = object->getProperty("SCRIPT"); if (npcId && !scriptText.empty()) { Script *script = ScriptManager::currentState(); script->loadNPC(object->getName(), npcId, ManaServ::getGender(gender), object->getX(), object->getY(), scriptText.c_str(), this); } else { LOG_WARN("Unrecognized format for npc"); } } else if (utils::compareStrI(type, "SCRIPT") == 0) { std::string scriptFilename = object->getProperty("FILENAME"); std::string scriptText = object->getProperty("TEXT"); Script *script = ScriptManager::currentState(); Script::Context context; context.map = this; if (!scriptFilename.empty()) { script->loadFile(scriptFilename, context); } else if (!scriptText.empty()) { std::string name = "'" + object->getName() + "'' in " + mName; script->load(scriptText.c_str(), name.c_str(), context); } else { LOG_WARN("Unrecognized format for script"); } } } }
static void handleCharWarp(Character *player, std::string &args) { int x, y; MapComposite *map; Character *other; // get the arguments std::string character = getArgument(args); std::string mapstr = getArgument(args); std::string xstr = getArgument(args); std::string ystr = getArgument(args); // if any of them are empty strings, no argument was given if (character.empty() || mapstr.empty() || xstr.empty() || ystr.empty()) { say("Invalid number of arguments given.", player); say("Usage: @warp <character> <map> <x> <y>", player); return; } // if it contains # then it means the player if (character == "#") { other = player; } else { // check for valid player other = gameHandler->getCharacterByNameSlow(character); if (!other) { say("Invalid or offline character <" + character + ">.", player); return; } } // if it contains # then it means the player's map if (mapstr == "#") { map = player->getMap(); } else { if (mapstr[0] == '#') { mapstr = mapstr.substr(1); // check for valid map id int id; if (!utils::isNumeric(mapstr)) { say("Invalid map", player); return; } id = utils::stringToInt(mapstr); // get the map map = MapManager::getMap(id); if (!map) { say("Invalid map", player); return; } } else { map = MapManager::getMap(mapstr); if (!map) { say("Invalid map", player); return; } } } if (!utils::isNumeric(xstr)) { say("Invalid x", player); return; } if (!utils::isNumeric(ystr)) { say("Invalid y", player); return; } // change the x and y to integers x = utils::stringToInt(xstr); y = utils::stringToInt(ystr); // now warp the player GameState::warp(other, map, x, y); // log transaction std::stringstream ss; ss << "User warped " << other->getName() << " to " << map->getName() << " (" << x << ", " << y << ")"; accountHandler->sendTransaction(player->getDatabaseID(), TRANS_CMD_WARP, ss.str()); }