예제 #1
0
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;
    }
}
예제 #2
0
/**
 * 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");
            }
        }
    }
}
예제 #3
0
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;
}
예제 #4
0
/**
 * 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");
            }
        }
    }
}
예제 #5
0
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());
}