void BeingHandler::handleBeingsDamageMessage(Net::MessageIn &msg) { while (msg.getUnreadLength()) { Being *being = actorSpriteManager->findBeing(msg.readInt16()); int damage = msg.readInt16(); if (being) { being->takeDamage(0, damage, Being::HIT); } } }
void MapComposite::update() { // Update object status const std::vector< Entity * > &entities = getEverything(); for (std::vector< Entity * >::const_iterator it = entities.begin(), it_end = entities.end(); it != it_end; ++it) { (*it)->update(); } if (mUpdateCallback.isValid()) { Script *s = ScriptManager::currentState(); s->setMap(this); s->prepare(mUpdateCallback); s->push(mID); s->execute(); } // Move objects around and update zones. for (BeingIterator it(getWholeMapIterator()); it; ++it) { (*it)->move(); } for (int i = 0; i < mContent->mapHeight * mContent->mapWidth; ++i) { mContent->zones[i].destinations.clear(); } // Cannot use a WholeMap iterator as objects will change zones under its feet. for (std::vector< Entity * >::iterator i = mContent->entities.begin(), i_end = mContent->entities.end(); i != i_end; ++i) { if (!(*i)->canMove()) continue; Being *obj = static_cast< Being * >(*i); const Point &pos1 = obj->getOldPosition(), &pos2 = obj->getPosition(); MapZone &src = mContent->getZone(pos1), &dst = mContent->getZone(pos2); if (&src != &dst) { addZone(src.destinations, &dst - mContent->zones); src.remove(obj); dst.insert(obj); } } }
void GameHandler::handleAttack(GameClient &client, MessageIn &message) { int id = message.readInt16(); LOG_DEBUG("Character " << client.character->getPublicID() << " attacked being " << id); Being *being = findBeingNear(client.character, id); if (being && being->getType() != OBJECT_NPC) { client.character->setTarget(being); client.character->setAction(ATTACK); } }
void Monster::forgetTarget(Entity *t) { Being *b = static_cast< Being * >(t); mAnger.erase(b); b->removeListener(&mTargetListener); if (b->getType() == OBJECT_CHARACTER) { Character *c = static_cast< Character * >(b); mExpReceivers.erase(c); mLegalExpReceivers.erase(c); } }
void BeingHandler::handleBeingLooksChangeMessage(Net::MessageIn &msg) { Being *being = actorSpriteManager->findBeing(msg.readInt16()); if (!being || being->getType() != ActorSprite::PLAYER) return; handleLooks(being, msg); if (msg.getUnreadLength()) { int style = msg.readInt16(); int color = msg.readInt16(); being->setSprite(SPRITE_HAIR, style * -1, ColorDB::get(color)); } }
void BeingHandler::handleBeingAttackMessage(Net::MessageIn &msg) { Being *being = actorSpriteManager->findBeing(msg.readInt16()); const BeingDirection direction = (BeingDirection) msg.readInt8(); const int attackType = msg.readInt8(); if (!being) return; being->setDirection(direction); being->setAction(Being::ATTACK, attackType); }
Being *BeingManager::findBeingByName(const std::string &name, Being::Type type) const { for (Beings::const_iterator i = mBeings.begin(), i_end = mBeings.end(); i != i_end; ++i) { Being *being = (*i); if (being->getName() == name && (type == Being::UNKNOWN || type == being->getType())) return being; } return NULL; }
void DebugWindow::draw(gcn::Graphics *g) { Window::draw(g); if (player_node) { Being *target = player_node->getTarget(); if (target) { Graphics *g2 = static_cast<Graphics*>(g); target->draw(g2, -target->getPixelX() + 16 + getWidth() / 2, -target->getPixelY() + 32 + getHeight() / 2); } } }
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; }
Command Interface::detailspage(Being & b) { Command c; bool viewingplayer = false; do { Being & viewed = (viewingplayer ? GAME.being[0] : b); displaydetails(viewed); if (viewed.isplayer) { if (b.isplayer) msg("Viewing your system details. Press any key..."); else { char msgbuf[128]; strcpy(msgbuf, "\ Viewing your system details. Press d to view "); strcat(msgbuf, b.getname()); strcat(msgbuf, "'s systems."); msg(msgbuf); } } else { char msgbuf[128]; strcpy(msgbuf, "Viewing "); strcat(msgbuf, viewed.getname()); strcat(msgbuf, "'s system details. Press d to view your systems."); msg(msgbuf); } c = getcommand(); if (c == COMMAND_DETAILS) if (b.isplayer) c = COMMAND_UNDEFINED; else viewingplayer = !viewingplayer; } while (c == COMMAND_DETAILS);
void BuySellHandler::handleMessage(Net::MessageIn &msg) { Being *being = actorSpriteManager->findBeing(msg.readInt16()); if (!being || being->getType() != ActorSprite::NPC) { return; } int npcId = being->getId(); switch (msg.getId()) { case GPMSG_NPC_BUY: { BuyDialog* dialog = new BuyDialog(npcId); dialog->reset(); dialog->setMoney(PlayerInfo::getAttribute(MONEY)); while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int amount = msg.readInt16(); int value = msg.readInt16(); dialog->addItem(itemId, amount, value); } break; } case GPMSG_NPC_SELL: { SellDialog* dialog = new SellDialog(npcId); dialog->reset(); dialog->setMoney(PlayerInfo::getAttribute(MONEY)); while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int amount = msg.readInt16(); int value = msg.readInt16(); dialog->addItem(new Item(itemId, amount, false), value); } break; } } }
void Monster::changeAnger(Actor *target, int amount) { if (target && (target->getType() == OBJECT_MONSTER || target->getType() == OBJECT_CHARACTER)) { Being *t = static_cast< Being * >(target); if (mAnger.find(t) != mAnger.end()) { mAnger[t] += amount; } else { mAnger[t] = amount; t->addListener(&mTargetListener); } } }
void Being::showName() { delete mDispName; mDispName = 0; std::string mDisplayName(mName); Being* player = static_cast<Being*>(this); if (player) { if (config.getBoolValue("showgender")) { if (getGender() == GENDER_FEMALE) mDisplayName += " \u2640"; else if (getGender() == GENDER_MALE) mDisplayName += " \u2642"; } // Display the IP when under tmw-Athena (GM only). if (Net::getNetworkType() == ServerInfo::TMWATHENA && local_player && local_player->getShowIp() && player->getIp()) { mDisplayName += strprintf(" %s", ipToString(player->getIp())); } } if (getType() == MONSTER) { if (config.getBoolValue("showMonstersTakedDamage")) { mDisplayName += ", " + toString(getDamageTaken()); } } gcn::Font *font = 0; if (local_player && local_player->getTarget() == this && getType() != MONSTER) { font = boldFont; } mDispName = new FlashText(mDisplayName, getPixelX(), getPixelY(), gcn::Graphics::CENTER, mNameColor, font); updateCoords(); }
static void spawn(Character *from, MonsterClass *specy, int nb) { MapComposite *map = from->getMap(); const Point &pos = from->getPosition(); for (int i = 0; i < nb; ++i) { Being *monster = new Monster(specy); monster->setMap(map); monster->setPosition(pos); monster->clearDestination(); if (!GameState::insertSafe(monster)) { // The map is full. Break out. break; } } }
void BeingManager::getPlayerNames(std::vector<std::string> &names, bool npcNames) { Beings::iterator i = mBeings.begin(); names.clear(); while (i != mBeings.end()) { Being *being = (*i); if ((being->getType() == Being::PLAYER || (being->getType() == Being::NPC && npcNames)) && being->getName() != "") { names.push_back(being->getName()); } ++i; } }
bool operator() (ActorSprite *actor) { if (actor->getType() == ActorSprite::FLOOR_ITEM) return false; Game *game = Game::instance(); if (!game) return false; Being* b = static_cast<Being*>(actor); uint16_t other_y = y + ((b->getType() == ActorSprite::NPC) ? 1 : 0); const Vector &pos = b->getPosition(); return ((int) pos.x / game->getCurrentTileWidth() == x && ((int) pos.y / game->getCurrentTileHeight() == y || (int) pos.y / game->getCurrentTileHeight() == other_y) && b->isAlive() && (type == ActorSprite::UNKNOWN || b->getType() == type)); }
void BeingManager::logic() { Beings::iterator i = mBeings.begin(); while (i != mBeings.end()) { Being *being = (*i); being->logic(); if (being->mAction == Being::DEAD && being->mFrame >= 20) { destroy(being); i = mBeings.erase(i); } else ++i; } }
static Being *findBeing(const std::string &name, const bool npc) { if (!localPlayer || !actorManager) return nullptr; Being *being = nullptr; if (name.empty()) { being = localPlayer->getTarget(); } else { being = actorManager->findBeingByName( name, ActorType::Unknown); } if (!being && npc) { being = actorManager->findNearestLivingBeing( localPlayer, 1, ActorType::Npc, AllowSort_true); if (being) { if (abs(being->getTileX() - localPlayer->getTileX()) > 1 || abs(being->getTileY() - localPlayer->getTileY()) > 1) { being = nullptr; } } } if (!being && npc) { being = actorManager->findNearestLivingBeing( localPlayer, 1, ActorType::Player, AllowSort_true); if (being) { if (abs(being->getTileX() - localPlayer->getTileX()) > 1 || abs(being->getTileY() - localPlayer->getTileY()) > 1) { being = nullptr; } } } return being; }
void PartyHandler::processPartyLeave(Net::MessageIn &msg) { int id = msg.readInt32(); std::string nick = msg.readString(24); msg.readInt8(); // fail if (!player_node) return; if (id == player_node->getId()) { if (Ea::taParty) { Ea::taParty->removeFromMembers(); Ea::taParty->clearMembers(); } SERVER_NOTICE(_("You have left the party.")) delete Ea::partyTab; Ea::partyTab = nullptr; if (socialWindow && Ea::taParty) socialWindow->removeTab(Ea::taParty); player_node->setPartyName(""); } else { if (Ea::partyTab) { Ea::partyTab->chatLog(strprintf( _("%s has left your party."), nick.c_str()), BY_SERVER); } if (actorSpriteManager) { Being *b = actorSpriteManager->findBeing(id); if (b && b->getType() == Being::PLAYER) { b->setParty(nullptr); b->setPartyName(""); } } if (Ea::taParty) Ea::taParty->removeMember(id); } }
void PartyHandler::processPartyInvited(Net::MessageIn &msg) { int id = msg.readInt32(); std::string partyName = msg.readString(24); std::string nick(""); Being *being; if (actorSpriteManager) { if ((being = actorSpriteManager->findBeing(id))) { if (being && being->getType() == Being::PLAYER) nick = being->getName(); } } if (socialWindow) socialWindow->showPartyInvite(partyName, nick); }
void BuySellHandler::handleMessage(MessageIn &msg) { Being *being = beingManager->findBeing(msg.readInt16()); if (!being || being->getType() != Being::NPC) { return; } current_npc = being->getId(); switch (msg.getId()) { case GPMSG_NPC_BUY: buyDialog->reset(); buyDialog->setMoney(player_node->getMoney()); buyDialog->setVisible(true); while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int amount = msg.readInt16(); int value = msg.readInt16(); buyDialog->addItem(itemId, amount, value); } break; case GPMSG_NPC_SELL: sellDialog->setMoney(player_node->getMoney()); sellDialog->reset(); sellDialog->setVisible(true); while (msg.getUnreadLength()) { int itemId = msg.readInt16(); int amount = msg.readInt16(); int value = msg.readInt16(); sellDialog->addItem(new Item(itemId, amount, false), value); } break; } }
Being *BeingManager::findBeingByPixel(int x, int y) const { Beings::const_iterator itr = mBeings.begin(); Beings::const_iterator itr_end = mBeings.end(); for (; itr != itr_end; ++itr) { Being *being = (*itr); int xtol = being->getWidth() / 2; int uptol = being->getHeight(); if ((being->isAlive()) && (being != player_node) && (being->getPixelX() - xtol <= x) && (being->getPixelX() + xtol >= x) && (being->getPixelY() - uptol <= y) && (being->getPixelY() >= y)) { return being; } } return NULL; }
void BeingManager::logic() { Beings::iterator i = mBeings.begin(); while (i != mBeings.end()) { Being *being = (*i); being->logic(); if (!being->isAlive() && Net::getGameHandler()->removeDeadBeings() && being->getCurrentFrame() >= 20) { delete being; i = mBeings.erase(i); } else { ++i; } } }
void BeingHandler::handleBeingActionChangeMessage(Net::MessageIn &msg) { Being *being = actorSpriteManager->findBeing(msg.readInt16()); Being::Action action = (Being::Action) msg.readInt8(); if (!being) return; being->setAction(action); if (action == Being::DEAD && being == player_node) { static char const *const deadMsg[] = { _("You are dead."), _("We regret to inform you that your character was killed in " "battle."), _("You are not that alive anymore."), _("The cold hands of the grim reaper are grabbing for your soul."), _("Game Over!"), _("No, kids. Your character did not really die. It... err... " "went to a better place."), _("Your plan of breaking your enemies weapon by bashing it with " "your throat failed."), _("I guess this did not run too well."), _("Do you want your possessions identified?"), // Nethack reference _("Sadly, no trace of you was ever found..."), // Secret of Mana reference _("Annihilated."), // Final Fantasy VI reference _("Looks like you got your head handed to you."), // Earthbound reference _("You screwed up again, dump your body down the tubes and get " "you another one.") // Leisure Suit Larry 1 Reference }; std::string message(deadMsg[rand()%13]); message.append(std::string(" ") + _("Press OK to respawn.")); OkDialog *dlg = new OkDialog(_("You Died"), message, false); dlg->addActionListener(&(ManaServ::respawnListener)); } }
void ChatHandler::handleGameChatMessage(Net::MessageIn &msg) { short id = msg.readInt16(); std::string chatMsg = msg.readString(); if (id == 0) { localChatTab->chatLog(chatMsg, BY_SERVER); return; } Being *being = beingManager->findBeing(id); std::string mes; if (being) { mes = being->getName() + " : " + chatMsg; being->setSpeech(chatMsg, SPEECH_TIME); } else mes = "Unknown : " + chatMsg; localChatTab->chatLog(mes, being == player_node ? BY_PLAYER : BY_OTHER); }
int Interface::selectitem(char * question, Being & viewed) { int ret; bool done = false; bool readcommand = true; Command c; while (!done) { if (readcommand) { query(question); c = getcommand(); } else readcommand = true; switch (c) { case COMMAND_CANCEL: ret = -1; done = true; break; case COMMAND_1: ret = 0; done = true; break; case COMMAND_2: ret = 1; done = true; break; case COMMAND_3: ret = 2; done = true; break; case COMMAND_4: ret = 3; done = true; break; case COMMAND_5: ret = 4; done = true; break; case COMMAND_6: ret = 5; done = true; break; case COMMAND_7: ret = 6; done = true; break; case COMMAND_8: ret = 7; done = true; break; case COMMAND_DETAILS: c = detailspage(viewed); GAME.normaldisplay(); viewed.displaystatus(); readcommand = false; break;; default: break; } } return ret; }
void GraphicsMap::Draw() { ScreenGame->clear(); // First draw the map objects onto the graphical map for (int x = 0; x < MapWidth; x++) for (int y = 0; y < MapHeight; y++) { if (FOVMap.map[x][y]) DrawDisplayTile(x, y, ToDraw->GetMapCell(x,y)->GetTile(), ScreenGame); else DrawDisplayTile(x, y, DisplayTile(' ', TCODColor::black, TCODColor::black), ScreenGame); } // Draw the items to the graphical map for (unsigned int i = 0; i < (ToDraw->Items.size()); i++) { // Get the item from the map Item* itm = ToDraw->Items[i]; // If it's in the FOV, draw it if (FOVMap.map[itm->GetX()][itm->GetY()]) DrawDisplayTile(itm->GetX(), itm->GetY(), itm->GetTile(), ScreenGame); else DrawDisplayTile(itm->GetX(), itm->GetY(), DisplayTile(' ', TCODColor::black, TCODColor::black), ScreenGame); } // Draw the beings to the graphical map for (unsigned int i = 0; i < (ToDraw->Beings.size()); i++) { // Get the being from the map Being* b = ToDraw->Beings[i]; if (FOVMap.map[b->GetX()][b->GetY()]) DrawDisplayTile(b->GetX(), b->GetY(), b->GetTile(), ScreenGame); else DrawDisplayTile(b->GetX(), b->GetY(), DisplayTile(' ', TCODColor::black, TCODColor::black), ScreenGame); } }
/** * Informs a player of what happened around the character. */ static void informPlayer(MapComposite *map, Character *p) { MessageOut moveMsg(GPMSG_BEINGS_MOVE); MessageOut damageMsg(GPMSG_BEINGS_DAMAGE); const Point &pold = p->getOldPosition(), ppos = p->getPosition(); int pid = p->getPublicID(), pflags = p->getUpdateFlags(); int visualRange = Configuration::getValue("game_visualRange", 448); // Inform client about activities of other beings near its character for (BeingIterator it(map->getAroundBeingIterator(p, visualRange)); it; ++it) { Being *o = *it; const Point &oold = o->getOldPosition(), opos = o->getPosition(); int otype = o->getType(); int oid = o->getPublicID(), oflags = o->getUpdateFlags(); int flags = 0; // Check if the character p and the moving object o are around. bool wereInRange = pold.inRangeOf(oold, visualRange) && !((pflags | oflags) & UPDATEFLAG_NEW_ON_MAP); bool willBeInRange = ppos.inRangeOf(opos, visualRange); if (!wereInRange && !willBeInRange) { // Nothing to report: o and p are far away from each other. continue; } if (wereInRange && willBeInRange) { // Send attack messages. if ((oflags & UPDATEFLAG_ATTACK) && oid != pid) { MessageOut AttackMsg(GPMSG_BEING_ATTACK); AttackMsg.writeInt16(oid); AttackMsg.writeInt8(o->getDirection()); AttackMsg.writeInt8(static_cast< Being * >(o)->getAttackId()); gameHandler->sendTo(p, AttackMsg); } // Send action change messages. if ((oflags & UPDATEFLAG_ACTIONCHANGE)) { MessageOut ActionMsg(GPMSG_BEING_ACTION_CHANGE); ActionMsg.writeInt16(oid); ActionMsg.writeInt8(static_cast< Being * >(o)->getAction()); gameHandler->sendTo(p, ActionMsg); } // Send looks change messages. if (oflags & UPDATEFLAG_LOOKSCHANGE) { MessageOut LooksMsg(GPMSG_BEING_LOOKS_CHANGE); LooksMsg.writeInt16(oid); Character * c = static_cast<Character * >(o); serializeLooks(c, LooksMsg); LooksMsg.writeInt16(c->getHairStyle()); LooksMsg.writeInt16(c->getHairColor()); LooksMsg.writeInt16(c->getGender()); gameHandler->sendTo(p, LooksMsg); } // Send emote messages. if (oflags & UPDATEFLAG_EMOTE) { int emoteId = o->getLastEmote(); if (emoteId > -1) { MessageOut EmoteMsg(GPMSG_BEING_EMOTE); EmoteMsg.writeInt16(oid); EmoteMsg.writeInt16(emoteId); gameHandler->sendTo(p, EmoteMsg); } } // Send direction change messages. if (oflags & UPDATEFLAG_DIRCHANGE) { MessageOut DirMsg(GPMSG_BEING_DIR_CHANGE); DirMsg.writeInt16(oid); DirMsg.writeInt8(o->getDirection()); gameHandler->sendTo(p, DirMsg); } // Send damage messages. if (o->canFight()) { Being *victim = static_cast< Being * >(o); const Hits &hits = victim->getHitsTaken(); for (Hits::const_iterator j = hits.begin(), j_end = hits.end(); j != j_end; ++j) { damageMsg.writeInt16(oid); damageMsg.writeInt16(*j); } } if (oold == opos) { // o does not move, nothing more to report. continue; } } if (!willBeInRange) { // o is no longer visible from p. Send leave message. MessageOut leaveMsg(GPMSG_BEING_LEAVE); leaveMsg.writeInt16(oid); gameHandler->sendTo(p, leaveMsg); continue; } if (!wereInRange) { // o is now visible by p. Send enter message. MessageOut enterMsg(GPMSG_BEING_ENTER); enterMsg.writeInt8(otype); enterMsg.writeInt16(oid); enterMsg.writeInt8(static_cast< Being *>(o)->getAction()); enterMsg.writeInt16(opos.x); enterMsg.writeInt16(opos.y); enterMsg.writeInt8(o->getDirection()); enterMsg.writeInt8(o->getGender()); switch (otype) { case OBJECT_CHARACTER: { Character *q = static_cast< Character * >(o); enterMsg.writeString(q->getName()); enterMsg.writeInt8(q->getHairStyle()); enterMsg.writeInt8(q->getHairColor()); serializeLooks(q, enterMsg); } break; case OBJECT_MONSTER: { Monster *q = static_cast< Monster * >(o); enterMsg.writeInt16(q->getSpecy()->getId()); enterMsg.writeString(q->getName()); } break; case OBJECT_NPC: { NpcComponent *npcComponent = o->getComponent<NpcComponent>(); enterMsg.writeInt16(npcComponent->getNpcId()); enterMsg.writeString(o->getName()); } break; default: assert(false); // TODO break; } gameHandler->sendTo(p, enterMsg); } if (opos != oold) { // Add position check coords every 5 seconds. if (currentTick % 50 == 0) flags |= MOVING_POSITION; flags |= MOVING_DESTINATION; } // Send move messages. moveMsg.writeInt16(oid); moveMsg.writeInt8(flags); if (flags & MOVING_POSITION) { moveMsg.writeInt16(oold.x); moveMsg.writeInt16(oold.y); } if (flags & MOVING_DESTINATION) { moveMsg.writeInt16(opos.x); moveMsg.writeInt16(opos.y); // We multiply the sent speed (in tiles per second) by ten // to get it within a byte with decimal precision. // For instance, a value of 4.5 will be sent as 45. moveMsg.writeInt8((unsigned short) (o->getModifiedAttribute(ATTR_MOVE_SPEED_TPS) * 10)); } } // Do not send a packet if nothing happened in p's range. if (moveMsg.getLength() > 2) gameHandler->sendTo(p, moveMsg); if (damageMsg.getLength() > 2) gameHandler->sendTo(p, damageMsg); // Inform client about status change. p->sendStatus(); // Inform client about health change of party members for (CharacterIterator i(map->getWholeMapIterator()); i; ++i) { Character *c = *i; // Make sure its not the same character if (c == p) continue; // make sure they are in the same party if (c->getParty() == p->getParty()) { int cflags = c->getUpdateFlags(); if (cflags & UPDATEFLAG_HEALTHCHANGE) { MessageOut healthMsg(GPMSG_BEING_HEALTH_CHANGE); healthMsg.writeInt16(c->getPublicID()); healthMsg.writeInt16(c->getModifiedAttribute(ATTR_HP)); healthMsg.writeInt16(c->getModifiedAttribute(ATTR_MAX_HP)); gameHandler->sendTo(p, healthMsg); } } } // Inform client about items on the ground around its character MessageOut itemMsg(GPMSG_ITEMS); for (FixedActorIterator it(map->getAroundBeingIterator(p, visualRange)); it; ++it) { Actor *o = *it; assert(o->getType() == OBJECT_ITEM || o->getType() == OBJECT_EFFECT); Point opos = o->getPosition(); int oflags = o->getUpdateFlags(); bool willBeInRange = ppos.inRangeOf(opos, visualRange); bool wereInRange = pold.inRangeOf(opos, visualRange) && !((pflags | oflags) & UPDATEFLAG_NEW_ON_MAP); if (willBeInRange ^ wereInRange) { switch (o->getType()) { case OBJECT_ITEM: { ItemComponent *item = o->getComponent<ItemComponent>(); ItemClass *itemClass = item->getItemClass(); if (oflags & UPDATEFLAG_NEW_ON_MAP) { /* Send a specific message to the client when an item appears out of nowhere, so that a sound/animation can be performed. */ MessageOut appearMsg(GPMSG_ITEM_APPEAR); appearMsg.writeInt16(itemClass->getDatabaseID()); appearMsg.writeInt16(opos.x); appearMsg.writeInt16(opos.y); gameHandler->sendTo(p, appearMsg); } else { itemMsg.writeInt16(willBeInRange ? itemClass->getDatabaseID() : 0); itemMsg.writeInt16(opos.x); itemMsg.writeInt16(opos.y); } } break; case OBJECT_EFFECT: { EffectComponent *e = o->getComponent<EffectComponent>(); e->setShown(); // Don't show old effects if (!(oflags & UPDATEFLAG_NEW_ON_MAP)) break; if (Being *b = e->getBeing()) { MessageOut effectMsg(GPMSG_CREATE_EFFECT_BEING); effectMsg.writeInt16(e->getEffectId()); effectMsg.writeInt16(b->getPublicID()); gameHandler->sendTo(p, effectMsg); } else { MessageOut effectMsg(GPMSG_CREATE_EFFECT_POS); effectMsg.writeInt16(e->getEffectId()); effectMsg.writeInt16(opos.x); effectMsg.writeInt16(opos.y); gameHandler->sendTo(p, effectMsg); } } break; default: break; } // Switch } } // Do not send a packet if nothing happened in p's range. if (itemMsg.getLength() > 2) gameHandler->sendTo(p, itemMsg); }
bool InputManager::handleKeyboardInput(const SDL_Event &event) { bool used = false; bool metaKeyHeld = false; // Key press events if (event.type == SDL_KEYDOWN) { if (setupWindow->isVisible() && keyboard.getNewKeyIndex() > keyboard.KEY_NO_VALUE) { keyboard.setNewKey((int) event.key.keysym.sym); keyboard.callbackNewKey(); keyboard.setNewKeyIndex(keyboard.KEY_NO_VALUE); return false; } // If the user is configuring the keys then don't respond. if (!keyboard.isEnabled()) return false; const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); // Ignore input if either "ignore" key is pressed // Stops the character moving about if the user's window manager // uses "ignore+arrow key" to switch virtual desktops. if (keyboard.isKeyActive(keyboard.KEY_IGNORE_INPUT_1) || keyboard.isKeyActive(keyboard.KEY_IGNORE_INPUT_2)) { return false; } if (keyboard.isKeyLocked(event.key.keysym.sym)) return false; gcn::Window *requestedWindow = NULL; switch (tKey) { // In-game Help case KeyboardConfig::KEY_WINDOW_HELP: requestedWindow = helpDialog; break; // Quitting confirmation dialog case KeyboardConfig::KEY_QUIT: stateManager->promptForQuit(); used = true; break; case KeyboardConfig::KEY_WINDOW_DEBUG: requestedWindow = debugWindow; break; case KeyboardConfig::KEY_WINDOW_SETUP: requestedWindow = setupWindow; break; // Screenshot (picture, hence the p) case KeyboardConfig::KEY_SCREENSHOT: saveScreenshot(); used = true; break; } if (stateManager->isInGame()) { switch (tKey) { case KeyboardConfig::KEY_SCROLL_CHAT_UP: if (chatWindow && chatWindow->isVisible()) { chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL); used = true; } break; case KeyboardConfig::KEY_SCROLL_CHAT_DOWN: if (chatWindow && chatWindow->isVisible()) { chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL); used = true; } break; case KeyboardConfig::KEY_WINDOW_STATUS: requestedWindow = statusWindow; break; case KeyboardConfig::KEY_WINDOW_INVENTORY: requestedWindow = inventoryWindow; break; case KeyboardConfig::KEY_WINDOW_EQUIPMENT: requestedWindow = equipmentWindow; break; case KeyboardConfig::KEY_WINDOW_SKILL: requestedWindow = skillDialog; break; case KeyboardConfig::KEY_WINDOW_MINIMAP: minimap->toggle(); break; case KeyboardConfig::KEY_WINDOW_CHAT: requestedWindow = chatWindow; break; case KeyboardConfig::KEY_WINDOW_EMOTE: requestedWindow = emoteWindow; break; case KeyboardConfig::KEY_WINDOW_ITEM_SHORTCUT: requestedWindow = itemShortcutWindow; break; case KeyboardConfig::KEY_WINDOW_EMOTE_SHORTCUT: requestedWindow = emoteShortcutWindow; break; // Hide certain windows case KeyboardConfig::KEY_HIDE_WINDOWS: statusWindow->hide(); inventoryWindow->hide(); equipmentWindow->hide(); skillDialog->hide(); chatWindow->hide(); itemShortcutWindow->hide(); setupWindow->hide(); debugWindow->hide(); emoteWindow->hide(); helpDialog->hide(); emoteShortcutWindow->hide(); minimap->hide(); used = true; break; // Find path to mouse (debug purpose) case KeyboardConfig::KEY_PATHFIND: viewport->toggleDebugPath(); used = true; break; default: break; } metaKeyHeld = keyboard.isKeyActive(keyboard.KEY_METAKEY); for (int i = 0; i <= SHORTCUTS; i++) { ShortcutHandler *shortcut = metaKeyHeld ? (ShortcutHandler *) emoteShortcut : (ShortcutHandler *) itemShortcut; const int offset = metaKeyHeld ? KeyboardConfig::KEY_EMOTE_SHORTCUT_1 : KeyboardConfig::KEY_ITEM_SHORTCUT_1; if (keyboard.isKeyActive(i + offset)) { shortcut->useShortcut(i); used = true; break; } } if (keyboard.isKeyActive(keyboard.KEY_TOGGLE_CHAT) && chatWindow) { chatWindow->requestChatFocus(); used = true; } // Player actions if (player_node && player_node->mAction != Being::DEAD) { Being *target = player_node->getTarget(); const Uint16 x = player_node->mX; const Uint16 y = player_node->mY; if (!keyboard.isKeyActive(keyboard.KEY_CLEAR_TARGET)) { Being::Type type = Being::INVALID; // Target the nearest monster if (keyboard.isKeyActive(keyboard.KEY_TARGET_MONSTER)) type = Being::MONSTER; // Target the nearest player else if (keyboard.isKeyActive(keyboard.KEY_TARGET_PLAYER)) type = Being::PLAYER; // Target the nearest npc else if (keyboard.isKeyActive(keyboard.KEY_TARGET_NPC)) type = Being::NPC; target = beingManager->findNearestLivingBeing(x, y, 20, type != Being::INVALID ? type : Being::UNKNOWN); if (type != Being::INVALID && !targetKeyHeld) { player_node->setTarget(target); targetKeyHeld = true; used = true; } else if (player_node->isAttacking()) target = NULL; if (keyboard.isKeyActive(keyboard.KEY_ATTACK) && target) { player_node->attack(player_node->getTarget() ? player_node->getTarget() : target, target->getType() != Being::NPC); used = true; } } // Stop attacking else if (keyboard.isKeyActive(keyboard.KEY_CLEAR_TARGET)) { player_node->stopAttack(); targetKeyHeld = false; } if (keyboard.isKeyActive(keyboard.KEY_BEING_MENU)) { target = player_node->getTarget(); if (!target) target = beingManager->findNearestLivingBeing(x, y, 20); if (target) { Map *map = viewport->getMap(); viewport->showPopup(target->mX * map->getTileWidth() - viewport->getCameraX() + (map->getTileWidth() / 2), target->mY * map->getTileHeight() - viewport->getCameraY(), target); } used = true; } switch (tKey) { case KeyboardConfig::KEY_PICKUP: { Uint16 x = player_node->mX; Uint16 y = player_node->mY; FloorItem *item = floorItemManager-> findNearestItem(x, y); if (item) player_node->pickUp(item); used = true; } break; // Player sit action case KeyboardConfig::KEY_SIT: player_node->toggleSit(); used = true; break; // Toggle accepting of incoming trade requests case KeyboardConfig::KEY_TRADE: { unsigned int deflt = player_relations.getDefault(); if (deflt & PlayerRelation::TRADE) { chatWindow->chatLog(_("Ignoring incoming " "trade requests"), Palette::SYSTEM); deflt &= ~PlayerRelation::TRADE; } else { chatWindow->chatLog(_("Accepting incoming " "trade requests"), Palette::SYSTEM); deflt |= PlayerRelation::TRADE; } player_relations.setDefault(deflt); used = true; } break; } } } if (requestedWindow) { requestedWindow->setVisible(!requestedWindow->isVisible()); used = true; } } else if (event.type == SDL_KEYUP) { const int tKey = keyboard.getKeyIndex(event.key.keysym.sym); // Stop protecting the target keys if (tKey == KeyboardConfig::KEY_TARGET_MONSTER || tKey == KeyboardConfig::KEY_TARGET_PLAYER || tKey == KeyboardConfig::KEY_TARGET_NPC) { targetKeyHeld = false; } } // At the moment, this is the only bit of logic left not assigned to a // specific SDL input poll, because it was causing continuous walking // without stopping. It would be better in the long run if this would get // fixed and then moved to one of them (in case we ever use other input // libraries. If everything is already grouped together, it'd be easier to // adapt to a new library, instead of having to rely on special cases) if (stateManager->isInGame() && player_node->mAction != Being::DEAD && !used) { unsigned char direction = 0; // Get the state of the keyboard keys keyboard.refreshActiveKeys(); // Translate pressed keys to movement and direction if (keyboard.isKeyActive(keyboard.KEY_MOVE_UP)) direction |= Being::UP; else if (keyboard.isKeyActive(keyboard.KEY_MOVE_DOWN)) direction |= Being::DOWN; if (keyboard.isKeyActive(keyboard.KEY_MOVE_LEFT)) direction |= Being::LEFT; else if (keyboard.isKeyActive(keyboard.KEY_MOVE_RIGHT)) direction |= Being::RIGHT; if (metaKeyHeld && direction != 0) player_node->setDirection(direction); else player_node->setWalkingDir(direction); } return used; }
void InputManager::handleJoystickInput(const SDL_Event &event) { if (joystick) joystick->update(); else return; if (!stateManager->isInGame()) return; if (event.type == SDL_JOYBUTTONUP && !joystick->buttonPressed(3)) { targetKeyHeld = false; // Stop protecting the target key } else if (player_node && player_node->mAction != Being::DEAD) { const Uint16 x = player_node->mX; const Uint16 y = player_node->mY; if (!keyboard.isKeyActive(keyboard.KEY_CLEAR_TARGET)) { Being *target = player_node->getTarget(); // Target the nearest monster if (joystick->buttonPressed(3) && !targetKeyHeld) { target = beingManager->findNearestLivingBeing(x, y, 20, Being::MONSTER); player_node->setTarget(target); targetKeyHeld = true; } if (joystick->buttonPressed(0) && target && target->getType() != Being::NPC) { player_node->attack(target, true); } } if (joystick->buttonPressed(1)) { FloorItem *item = floorItemManager->findByCoordinates(x, y); if (item) player_node->pickUp(item); } if (joystick->buttonPressed(2)) player_node->toggleSit(); unsigned char direction = 0; // Translate pressed keys to movement and direction if (joystick->isUp()) direction |= Being::UP; else if (joystick->isDown()) direction |= Being::DOWN; if (joystick->isLeft()) direction |= Being::LEFT; else if (joystick->isRight()) direction |= Being::RIGHT; player_node->setWalkingDir(direction); } }