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; } } } }
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; }