예제 #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
void GameHandler::handlePickup(GameClient &client, MessageIn &message)
{
    const int x = message.readInt16();
    const int y = message.readInt16();
    const Point ppos =
            client.character->getComponent<ActorComponent>()->getPosition();

    // TODO: use a less arbitrary value.
    if (std::abs(x - ppos.x) + std::abs(y - ppos.y) < 48)
    {
        MapComposite *map = client.character->getMap();
        Point ipos(x, y);
        for (FixedActorIterator i(map->getAroundPointIterator(ipos, 0)); i; ++i)
        {
            Entity *o = *i;
            Point opos = o->getComponent<ActorComponent>()->getPosition();

            if (o->getType() == OBJECT_ITEM && opos.x == x && opos.y == y)
            {
                ItemComponent *item = o->getComponent<ItemComponent>();
                ItemClass *ic = item->getItemClass();
                int amount = item->getAmount();

                if (!Inventory(client.character).insert(ic->getDatabaseID(),
                                                        amount))
                {
                    GameState::remove(o);

                    // We only do this when items are to be kept in memory
                    // between two server restart.
                    if (!Configuration::getValue("game_floorItemDecayTime", 0))
                    {
                        // Remove the floor item from map
                        accountHandler->removeFloorItems(map->getID(),
                                                         ic->getDatabaseID(),
                                                         amount, x, y);
                    }

                    // log transaction
                    std::stringstream str;
                    str << "User picked up item " << ic->getDatabaseID()
                        << " at " << opos.x << "x" << opos.y;
                    auto *characterComponent = client.character
                            ->getComponent<CharacterComponent>();
                    accountHandler->sendTransaction(
                            characterComponent->getDatabaseID(),
                            TRANS_ITEM_PICKUP, str.str()
                                                   );
                }
                break;
            }
        }
    }
}
예제 #3
0
static Being *findBeingNear(Actor *p, int id)
{
    MapComposite *map = p->getMap();
    const Point &ppos = p->getPosition();
    // See map.h for tiles constants
    const int pixelDist = DEFAULT_TILE_LENGTH * TILES_TO_BE_NEAR;
    for (BeingIterator i(map->getAroundPointIterator(ppos, pixelDist)); i; ++i)
    {
        Being *b = *i;
        if (b->getPublicID() != id)
            continue;
        return ppos.inRangeOf(b->getPosition(), pixelDist) ? b : 0;
    }
    return 0;
}
예제 #4
0
static Actor *findActorNear(Actor *p, int id)
{
    MapComposite *map = p->getMap();
    const Point &ppos = p->getPosition();
    // See map.hpp for tiles constants
    const int pixelDist = DEFAULT_TILE_WIDTH * TILES_TO_BE_NEAR;
    for (ActorIterator i(map->getAroundPointIterator(ppos, pixelDist)); i; ++i)
    {
        Actor *a = *i;
        if (a->getPublicID() != id)
            continue;
        return ppos.inRangeOf(a->getPosition(), pixelDist) ? a : 0;
    }
    return 0;
}
예제 #5
0
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);
}
예제 #6
0
static Entity *findCharacterNear(Entity *p, int id)
{
    MapComposite *map = p->getMap();
    const Point &ppos = p->getComponent<ActorComponent>()->getPosition();
    // See map.h for tiles constants
    const int pixelDist = DEFAULT_TILE_LENGTH * TILES_TO_BE_NEAR;
    for (CharacterIterator i(map->getAroundPointIterator(ppos,
                                                         pixelDist)); i; ++i)
    {
        Entity *c = *i;
        if (c->getComponent<ActorComponent>()->getPublicID() != id)
            continue;

        if (ppos.inRangeOf(c->getComponent<ActorComponent>()->getPosition(),
                           pixelDist))
            return c;

        return  0;
    }
    return 0;
}
예제 #7
0
void GameHandler::handlePartyInvite(GameClient &client, MessageIn &message)
{
    MapComposite *map = client.character->getMap();
    const int visualRange = Configuration::getValue("game_visualRange", 448);
    std::string invitee = message.readString();

    if (invitee == client.character->getComponent<BeingComponent>()->getName())
        return;

    for (CharacterIterator it(map->getWholeMapIterator()); it; ++it)
    {
        if ((*it)->getComponent<BeingComponent>()->getName() == invitee)
        {
            // calculate if the invitee is within the visual range
            auto *inviterComponent =
                    client.character->getComponent<ActorComponent>();
            auto *inviteeComponent = (*it)->getComponent<ActorComponent>();
            const Point &inviterPosition = inviterComponent->getPosition();
            const Point &inviteePosition = inviteeComponent->getPosition();
            const int dx = std::abs(inviterPosition.x - inviteePosition.x);
            const int dy = std::abs(inviterPosition.y - inviteePosition.y);
            if (visualRange > std::max(dx, dy))
            {
                MessageOut out(GCMSG_PARTY_INVITE);
                out.writeString(client.character
                                ->getComponent<BeingComponent>()->getName());
                out.writeString(invitee);
                accountHandler->send(out);
                return;
            }
            break;
        }
    }

    // Invitee was not found or is too far away
    MessageOut out(GPMSG_PARTY_INVITE_ERROR);
    out.writeString(invitee);
    client.send(out);
}
예제 #8
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");
            }
        }
    }
}
예제 #9
0
void GameState::remove(Entity *ptr)
{
    assert(!dbgLockObjects);
    MapComposite *map = ptr->getMap();
    int visualRange = Configuration::getValue("game_visualRange", 448);

    ptr->signal_removed.emit(ptr);

    // DEBUG INFO
    switch (ptr->getType())
    {
        case OBJECT_ITEM:
            LOG_DEBUG("Item removed: "
                   << ptr->getComponent<ItemComponent>()->getItemClass()->getDatabaseID());
            break;

        case OBJECT_NPC:
            LOG_DEBUG("NPC removed: " << ptr->getComponent<NpcComponent>()->getNpcId());
            break;

        case OBJECT_CHARACTER:
            LOG_DEBUG("Player removed: "
                      << static_cast<Being*>(ptr)->getName());
            break;

        case OBJECT_EFFECT:
            LOG_DEBUG("Effect removed: "
                      << ptr->getComponent<EffectComponent>()->getEffectId());
            break;

        case OBJECT_MONSTER:
            LOG_DEBUG("Monster removed: "
                      << static_cast<Monster*>(ptr)->getSpecy()->getId());
            break;

        case OBJECT_ACTOR:
        case OBJECT_OTHER:
        default:
            LOG_DEBUG("Entity removed: " << ptr->getType());
            break;
    }

    if (ptr->canMove())
    {
        if (ptr->getType() == OBJECT_CHARACTER)
        {
            static_cast< Character * >(ptr)->cancelTransaction();

            // remove characters online status
            accountHandler->updateOnlineStatus(
                static_cast< Character * >(ptr)->getDatabaseID(), false);
        }

        Actor *obj = static_cast< Actor * >(ptr);
        MessageOut msg(GPMSG_BEING_LEAVE);
        msg.writeInt16(obj->getPublicID());
        Point objectPos = obj->getPosition();

        for (CharacterIterator p(map->getAroundActorIterator(obj, visualRange));
             p; ++p)
        {
            if (*p != obj && objectPos.inRangeOf((*p)->getPosition(),
                visualRange))
            {
                gameHandler->sendTo(*p, msg);
            }
        }
    }
    else if (ptr->getType() == OBJECT_ITEM)
    {
        Actor *actor = static_cast<Actor*>(ptr);
        Point pos = actor->getPosition();
        MessageOut msg(GPMSG_ITEMS);
        msg.writeInt16(0);
        msg.writeInt16(pos.x);
        msg.writeInt16(pos.y);

        for (CharacterIterator p(map->getAroundActorIterator(actor, visualRange)); p; ++p)
        {
            if (pos.inRangeOf((*p)->getPosition(), visualRange))
            {
                gameHandler->sendTo(*p, msg);
            }
        }
    }

    map->remove(ptr);
}
예제 #10
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;
}
예제 #11
0
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();
}
예제 #12
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");
            }
        }
    }
}
예제 #13
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());
}
예제 #14
0
파일: state.cpp 프로젝트: Ablu/invertika
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();
}
예제 #15
0
void AccountConnection::processMessage(MessageIn &msg)
{
    LOG_DEBUG("Received message " << msg << " from account server");

    switch (msg.getId())
    {
        case AGMSG_REGISTER_RESPONSE:
        {
            if (msg.readInt16() != DATA_VERSION_OK)
            {
                LOG_ERROR("Item database is outdated! Please update to "
                          "prevent inconsistencies");
                stop();  // Disconnect gracefully from account server.
                // Stop gameserver to prevent inconsistencies.
                exit(EXIT_DB_EXCEPTION);
            }
            else
            {
                LOG_DEBUG("Local item database is "
                          "in sync with account server.");
            }
            if (msg.readInt16() != PASSWORD_OK)
            {
                LOG_ERROR("This game server sent a invalid password");
                stop();
                exit(EXIT_BAD_CONFIG_PARAMETER);
            }

            // read world state variables
            while (msg.getUnreadLength())
            {
                std::string key = msg.readString();
                std::string value = msg.readString();
                if (!key.empty() && !value.empty())
                {
                    GameState::setVariableFromDbserver(key, value);
                }
            }

        } break;

        case AGMSG_PLAYER_ENTER:
        {
            std::string token = msg.readString(MAGIC_TOKEN_LENGTH);
            Character *ptr = new Character(msg);
            gameHandler->addPendingCharacter(token, ptr);
        } break;

        case AGMSG_ACTIVE_MAP:
        {
            int mapId = msg.readInt16();
            if (MapManager::activateMap(mapId))
            {
                // Set map variables
                MapComposite *m = MapManager::getMap(mapId);
                int mapVarsNumber = msg.readInt16();
                for(int i = 0; i < mapVarsNumber; ++i)
                {
                    std::string key = msg.readString();
                    std::string value = msg.readString();
                    if (!key.empty() && !value.empty())
                        m->setVariableFromDbserver(key, value);
                }

                // Recreate potential persistent floor items
                LOG_DEBUG("Recreate persistant items on map " << mapId);
                int floorItemsNumber = msg.readInt16();

                for (int i = 0; i < floorItemsNumber; ++i)
                {
                    int itemId = msg.readInt32();
                    int amount = msg.readInt16();
                    int posX = msg.readInt16();
                    int posY = msg.readInt16();

                    if (ItemClass *ic = itemManager->getItem(itemId))
                    {
                        Item *item = new Item(ic, amount);
                        item->setMap(m);
                        Point dst(posX, posY);
                        item->setPosition(dst);

                        if (!GameState::insertOrDelete(item))
                        {
                            // The map is full.
                            LOG_WARN("Couldn't add floor item(s) " << itemId
                                << " into map " << mapId);
                            return;
                        }
                    }
                }
            }
        } break;

        case AGMSG_SET_VAR_WORLD:
        {
            std::string key = msg.readString();
            std::string value = msg.readString();
            GameState::setVariableFromDbserver(key, value);
            LOG_DEBUG("Global variable \"" << key << "\" has changed to \""
                      << value << "\"");
        } break;

        case AGMSG_REDIRECT_RESPONSE:
        {
            int id = msg.readInt32();
            std::string token = msg.readString(MAGIC_TOKEN_LENGTH);
            std::string address = msg.readString();
            int port = msg.readInt16();
            gameHandler->completeServerChange(id, token, address, port);
        } break;

        case AGMSG_GET_VAR_CHR_RESPONSE:
        {
            int id = msg.readInt32();
            std::string name = msg.readString();
            std::string value = msg.readString();
            recoveredQuestVar(id, name, value);
        } break;

        case CGMSG_CHANGED_PARTY:
        {
            // Character DB id
            int charid = msg.readInt32();
            // Party id, 0 for none
            int partyid = msg.readInt32();
            gameHandler->updateCharacter(charid, partyid);
        } break;

        case CGMSG_POST_RESPONSE:
        {
            // get the character
            Character *character = postMan->getCharacter(msg.readInt32());

            // check character is still valid
            if (!character)
            {
                break;
            }

            std::string sender = msg.readString();
            std::string letter = msg.readString();

            postMan->gotPost(character, sender, letter);

        } break;

        case CGMSG_STORE_POST_RESPONSE:
        {
            // get character
            Character *character = postMan->getCharacter(msg.readInt32());

            // check character is valid
            if (!character)
            {
                break;
            }

            // TODO: Get NPC to tell character if the sending of post
            // was successful or not

        } break;

        default:
            LOG_WARN("Invalid message type");
            break;
    }
}
예제 #16
0
void GameHandler::processMessage(NetComputer *comp, MessageIn &message)
{
    GameClient &computer = *static_cast< GameClient * >(comp);
    MessageOut result;

    if (computer.status == CLIENT_LOGIN)
    {
        if (message.getId() != PGMSG_CONNECT)
            return;

        std::string magic_token = message.readString(MAGIC_TOKEN_LENGTH);
        computer.status = CLIENT_QUEUED; // Before the addPendingClient
        mTokenCollector.addPendingClient(magic_token, &computer);
        return;
    }
    else if (computer.status != CLIENT_CONNECTED)
    {
        return;
    }

    switch (message.getId())
    {
        case PGMSG_SAY:
        {
            std::string say = message.readString();
            if (say.empty()) break;

            if (say[0] == '@')
            {
                CommandHandler::handleCommand(computer.character, say);
                break;
            }
            GameState::sayAround(computer.character, say);
            std::string msg = computer.character->getName() + " said " + say;
            accountHandler->sendTransaction(computer.character->getDatabaseID(), TRANS_MSG_PUBLIC, msg);
        } break;

        case PGMSG_NPC_TALK:
        case PGMSG_NPC_TALK_NEXT:
        case PGMSG_NPC_SELECT:
        case PGMSG_NPC_NUMBER:
        case PGMSG_NPC_STRING:
        {
            int id = message.readShort();
            Actor *o = findActorNear(computer.character, id);
            if (!o || o->getType() != OBJECT_NPC)
            {
                sendError(comp, id, "Not close enough to NPC\n");
                break;
            }

            NPC *q = static_cast< NPC * >(o);
            if (message.getId() == PGMSG_NPC_SELECT)
            {
                q->select(computer.character, message.readByte());
            }
            else if (message.getId() == PGMSG_NPC_NUMBER)
            {
                q->integerReceived(computer.character, message.readLong());
            }
            else if (message.getId() == PGMSG_NPC_STRING)
            {
                q->stringReceived(computer.character, message.readString());
            }
            else
            {
                q->prompt(computer.character, message.getId() == PGMSG_NPC_TALK);
            }
        } break;

        case PGMSG_PICKUP:
        {
            int x = message.readShort();
            int y = message.readShort();
            Point ppos = computer.character->getPosition();

            // TODO: use a less arbitrary value.
            if (std::abs(x - ppos.x) + std::abs(y - ppos.y) < 48)
            {
                MapComposite *map = computer.character->getMap();
                Point ipos(x, y);
                for (FixedActorIterator i(map->getAroundPointIterator(ipos, 0)); i; ++i)
                {
                    Actor *o = *i;
                    Point opos = o->getPosition();
                    if (o->getType() == OBJECT_ITEM && opos.x == x && opos.y == y)
                    {
                        Item *item = static_cast< Item * >(o);
                        ItemClass *ic = item->getItemClass();
                        Inventory(computer.character)
                            .insert(ic->getDatabaseID(), item->getAmount());
                        GameState::remove(item);
                        // log transaction
                        std::stringstream str;
                        str << "User picked up item " << ic->getDatabaseID()
                            << " at " << opos.x << "x" << opos.y;
                        accountHandler->sendTransaction(computer.character->getDatabaseID(),
                            TRANS_ITEM_PICKUP, str.str());
                        break;
                    }
                }
            }
        } break;

        case PGMSG_USE_ITEM:
        {
            int slot = message.readByte();
            Inventory inv(computer.character);
            if (ItemClass *ic = ItemManager::getItem(inv.getItem(slot)))
            {
                if (ic->use(computer.character))
                {
                    inv.removeFromSlot(slot, 1);
                    // log transaction
                    std::stringstream str;
                    str << "User used item " << ic->getDatabaseID()
                        << " from slot " << slot;
                    accountHandler->sendTransaction(computer.character->getDatabaseID(),
                        TRANS_ITEM_USED, str.str());
                }
            }
        } break;

        case PGMSG_DROP:
        {
            int slot = message.readByte();
            int amount = message.readByte();
            Inventory inv(computer.character);
            if (ItemClass *ic = ItemManager::getItem(inv.getItem(slot)))
            {
                int nb = inv.removeFromSlot(slot, amount);
                Item *item = new Item(ic, amount - nb);
                item->setMap(computer.character->getMap());
                item->setPosition(computer.character->getPosition());
                if (!GameState::insert(item))
                {
                    // The map is full. Put back into inventory.
                    inv.insert(ic->getDatabaseID(), amount - nb);
                    delete item;
                    break;
                }
                // log transaction
                Point pt = computer.character->getPosition();
                std::stringstream str;
                str << "User dropped item " << ic->getDatabaseID()
                    << " at " << pt.x << "x" << pt.y;
                accountHandler->sendTransaction(computer.character->getDatabaseID(),
                    TRANS_ITEM_DROP, str.str());
            }
        } break;

        case PGMSG_WALK:
        {
            handleWalk(&computer, message);
        } break;

        case PGMSG_EQUIP:
        {
            int slot = message.readByte();
            Inventory(computer.character).equip(slot);
        } break;

        case PGMSG_UNEQUIP:
        {
            int slot = message.readByte();
            if (slot >= 0 && slot < EQUIP_PROJECTILE_SLOT)
            {
                Inventory(computer.character).unequip(slot);
            }
        } break;

        case PGMSG_MOVE_ITEM:
        {
            int slot1 = message.readByte();
            int slot2 = message.readByte();
            int amount = message.readByte();
            Inventory(computer.character).move(slot1, slot2, amount);
            // log transaction
            std::stringstream str;
            str << "User moved item "
                << " from slot " << slot1 << " to slot " << slot2;
            accountHandler->sendTransaction(computer.character->getDatabaseID(),
                TRANS_ITEM_MOVE, str.str());
        } break;

        case PGMSG_ATTACK:
        {
            int id = message.readShort();
            LOG_DEBUG("Character " << computer.character->getPublicID()
                      << " attacked being " << id);

            Actor *o = findActorNear(computer.character, id);
            if (o && o->getType() != OBJECT_NPC)
            {
                Being *being = static_cast<Being*>(o);
                computer.character->setTarget(being);
                computer.character->setAction(Being::ATTACK);
            }
        } break;

        case PGMSG_USE_SPECIAL:
        {
            int specialID = message.readByte();
            LOG_DEBUG("Character " << computer.character->getPublicID()
                      << " tries to use his special attack "<<specialID);
            computer.character->useSpecial(specialID);
        }

        case PGMSG_ACTION_CHANGE:
        {
            Being::Action action = (Being::Action)message.readByte();
            Being::Action current = (Being::Action)computer.character->getAction();
            bool logActionChange = true;

            switch (action)
            {
                case Being::STAND:
                {
                    if (current == Being::SIT)
                    {
                        computer.character->setAction(Being::STAND);
                        logActionChange = false;
                    }
                } break;
                case Being::SIT:
                {
                    if (current == Being::STAND)
                    {
                        computer.character->setAction(Being::SIT);
                        logActionChange = false;
                    }
                } break;
                default:
                    break;
            }

            // Log the action change only when this is relevant.
            if (logActionChange)
            {
                // log transaction
                std::stringstream str;
                str << "User changed action from " << current
                    << " to " << action;
                accountHandler->sendTransaction(
                    computer.character->getDatabaseID(),
                    TRANS_ACTION_CHANGE, str.str());
            }

        } break;

        case PGMSG_DIRECTION_CHANGE:
        {
            computer.character->setDirection(message.readByte());
        } break;

        case PGMSG_DISCONNECT:
        {
            bool reconnectAccount = (bool) message.readByte();

            result.writeShort(GPMSG_DISCONNECT_RESPONSE);
            result.writeByte(ERRMSG_OK); // It is, when control reaches here

            if (reconnectAccount)
            {
                std::string magic_token(utils::getMagicToken());
                result.writeString(magic_token, MAGIC_TOKEN_LENGTH);
                // No accountserver data, the client should remember that
                accountHandler->playerReconnectAccount(
                                   computer.character->getDatabaseID(),
                                   magic_token);
            }
            // TODO: implement a delayed remove
            GameState::remove(computer.character);

            accountHandler->sendCharacterData(computer.character);

            // Done with the character
            computer.character->disconnected();
            delete computer.character;
            computer.character = NULL;
            computer.status = CLIENT_LOGIN;
        } break;

        case PGMSG_TRADE_REQUEST:
        {
            int id = message.readShort();

            if (Trade *t = computer.character->getTrading())
            {
                if (t->request(computer.character, id)) break;
            }

            Character *q = findCharacterNear(computer.character, id);
            if (!q || q->isBusy())
            {
                result.writeShort(GPMSG_TRADE_CANCEL);
                break;
            }

            new Trade(computer.character, q);

            // log transaction
            std::string str;
            str = "User requested trade with " + q->getName();
            accountHandler->sendTransaction(computer.character->getDatabaseID(),
                TRANS_TRADE_REQUEST, str);
        } break;

        case PGMSG_TRADE_CANCEL:
        case PGMSG_TRADE_AGREED:
        case PGMSG_TRADE_CONFIRM:
        case PGMSG_TRADE_ADD_ITEM:
        case PGMSG_TRADE_SET_MONEY:
        {
            std::stringstream str;
            Trade *t = computer.character->getTrading();
            if (!t) break;

            switch (message.getId())
            {
                case PGMSG_TRADE_CANCEL:
                    t->cancel();
                    break;
                case PGMSG_TRADE_CONFIRM:
                    t->confirm(computer.character);
                    break;
                case PGMSG_TRADE_AGREED:
                    t->agree(computer.character);
                    // log transaction
                    accountHandler->sendTransaction(computer.character->getDatabaseID(),
                        TRANS_TRADE_END, "User finished trading");
                    break;
                case PGMSG_TRADE_SET_MONEY:
                {
                    int money = message.readLong();
                    t->setMoney(computer.character, money);
                    // log transaction
                    str << "User added " << money << " money to trade.";
                    accountHandler->sendTransaction(computer.character->getDatabaseID(),
                        TRANS_TRADE_MONEY, str.str());
                } break;
                case PGMSG_TRADE_ADD_ITEM:
                {
                    int slot = message.readByte();
                    t->addItem(computer.character, slot, message.readByte());
                    // log transaction
                    str << "User add item from slot " << slot;
                    accountHandler->sendTransaction(computer.character->getDatabaseID(),
                        TRANS_TRADE_ITEM, str.str());
                } break;
            }
        } break;

        case PGMSG_NPC_BUYSELL:
        {
            BuySell *t = computer.character->getBuySell();
            if (!t) break;
            int id = message.readShort();
            int amount = message.readShort();
            t->perform(id, amount);
        } break;

        case PGMSG_RAISE_ATTRIBUTE:
        {
            int attribute = message.readByte();
            AttribmodResponseCode retCode;
            retCode = computer.character->useCharacterPoint(attribute);
            result.writeShort(GPMSG_RAISE_ATTRIBUTE_RESPONSE);
            result.writeByte(retCode);
            result.writeByte(attribute);

            if (retCode == ATTRIBMOD_OK )
            {
                accountHandler->updateCharacterPoints(
                    computer.character->getDatabaseID(),
                    computer.character->getCharacterPoints(),
                    computer.character->getCorrectionPoints(),
                    attribute,
                    computer.character->getAttribute(attribute));

                // log transaction
                std::stringstream str;
                str << "User increased attribute " << attribute;
                accountHandler->sendTransaction(computer.character->getDatabaseID(),
                    TRANS_ATTR_INCREASE, str.str());
            }
        } break;

        case PGMSG_LOWER_ATTRIBUTE:
        {
            int attribute = message.readByte();
            AttribmodResponseCode retCode;
            retCode = computer.character->useCorrectionPoint(attribute);
            result.writeShort(GPMSG_LOWER_ATTRIBUTE_RESPONSE);
            result.writeByte(retCode);
            result.writeByte(attribute);

            if (retCode == ATTRIBMOD_OK )
            {
                accountHandler->updateCharacterPoints(
                    computer.character->getDatabaseID(),
                    computer.character->getCharacterPoints(),
                    computer.character->getCorrectionPoints(),
                    attribute,
                    computer.character->getAttribute(attribute));

                // log transaction
                std::stringstream str;
                str << "User decreased attribute " << attribute;
                accountHandler->sendTransaction(computer.character->getDatabaseID(),
                    TRANS_ATTR_DECREASE, str.str());
            }
        } break;

        case PGMSG_RESPAWN:
        {
            computer.character->respawn(); // plausibility check is done by character class
        } break;

        case PGMSG_NPC_POST_SEND:
        {
            handleSendPost(&computer, message);
        } break;

        default:
            LOG_WARN("Invalid message type");
            result.writeShort(XXMSG_INVALID);
            break;
    }

    if (result.getLength() > 0)
        computer.send(result);
}