예제 #1
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;
            }
        }
    }
}
예제 #2
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;
}
예제 #3
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;
}
예제 #4
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;
}
예제 #5
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);
}