diff --git a/data/scripts/talkactions/god/create_monster.lua b/data/scripts/talkactions/god/manage_monster.lua similarity index 83% rename from data/scripts/talkactions/god/create_monster.lua rename to data/scripts/talkactions/god/manage_monster.lua index ce5869a2eee..da110d59265 100644 --- a/data/scripts/talkactions/god/create_monster.lua +++ b/data/scripts/talkactions/god/manage_monster.lua @@ -56,7 +56,7 @@ local createMonster = TalkAction("/m") -- @param param: String containing the command parameters. -- Format: "/m monstername, monstercount, [fiendish/influenced level], spawnRadius, [forceCreate]" -- Example: "/m rat, 10, fiendish, 5, true" --- @param: the last param is by default "false", if add "," or any value i'ts set to true +-- @param: the last param is by default "false", if add "," or any value it's set to true -- @return true if the command is executed successfully, false otherwise. function createMonster.onSay(player, words, param) -- create log @@ -127,3 +127,33 @@ end createMonster:separator(" ") createMonster:groupType("god") createMonster:register() + +----------------- Rename monster name ----------------- +local setMonsterName = TalkAction("/setmonstername") + +-- @function setMonsterName.onSay +-- @desc TalkAction to rename nearby monsters within a radius of 4 sqm. +-- Format: "/setmonstername newName" +function setMonsterName.onSay(player, words, param) + if param == "" then + player:sendCancelMessage("Command param required.") + return true + end + + local split = param:split(",") + local monsterNewName = split[1] + + local spectators, spectator = Game.getSpectators(player:getPosition(), false, false, 4, 4, 4, 4) + for i = 1, #spectators do + spectator = spectators[i] + if spectator:isMonster() then + spectator:setName(monsterNewName) + end + end + + return true +end + +setMonsterName:separator(" ") +setMonsterName:groupType("god") +setMonsterName:register() diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp index fccc19b05e5..5e0a7d16bb4 100644 --- a/src/creatures/monsters/monster.cpp +++ b/src/creatures/monsters/monster.cpp @@ -33,7 +33,7 @@ std::shared_ptr Monster::createMonster(const std::string &name) { Monster::Monster(const std::shared_ptr mType) : Creature(), - strDescription(asLowerCaseString(mType->nameDescription)), + nameDescription(asLowerCaseString(mType->nameDescription)), mType(mType) { defaultOutfit = mType->info.outfit; currentOutfit = mType->info.outfit; @@ -64,6 +64,37 @@ void Monster::removeList() { g_game().removeMonster(static_self_cast()); } +const std::string &Monster::getName() const { + if (name.empty()) { + return mType->name; + } + return name; +} + +void Monster::setName(const std::string &name) { + if (getName() == name) { + return; + } + + this->name = name; + + // NOTE: Due to how client caches known creatures, + // it is not feasible to send creature update to everyone that has ever met it + auto spectators = Spectators().find(position, true); + for (const auto &spectator : spectators) { + if (const auto &tmpPlayer = spectator->getPlayer()) { + tmpPlayer->sendUpdateTileCreature(static_self_cast()); + } + } +} + +const std::string &Monster::getNameDescription() const { + if (nameDescription.empty()) { + return mType->nameDescription; + } + return nameDescription; +} + bool Monster::canWalkOnFieldType(CombatType_t combatType) const { switch (combatType) { case COMBAT_ENERGYDAMAGE: diff --git a/src/creatures/monsters/monster.hpp b/src/creatures/monsters/monster.hpp index bf9a39e4133..6c45fa3eaca 100644 --- a/src/creatures/monsters/monster.hpp +++ b/src/creatures/monsters/monster.hpp @@ -41,21 +41,22 @@ class Monster final : public Creature { } } - void removeList() override; void addList() override; + void removeList() override; + + const std::string &getName() const override; + void setName(const std::string &name); - const std::string &getName() const override { - return mType->name; - } // Real monster name, set on monster creation "createMonsterType(typeName)" const std::string &getTypeName() const override { return mType->typeName; } - const std::string &getNameDescription() const override { - return mType->nameDescription; - } + const std::string &getNameDescription() const override; + void setNameDescription(const std::string &nameDescription) { + this->nameDescription = nameDescription; + }; std::string getDescription(int32_t) override { - return strDescription + '.'; + return nameDescription + '.'; } CreatureType_t getType() const override { @@ -363,7 +364,8 @@ class Monster final : public Creature { uint16_t forgeStack = 0; ForgeClassifications_t monsterForgeClassification = ForgeClassifications_t::FORGE_NORMAL_MONSTER; - std::string strDescription; + std::string name; + std::string nameDescription; std::shared_ptr mType; SpawnMonster* spawnMonster = nullptr; diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 19e3af5ca9c..947acedca54 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -153,8 +153,8 @@ class Player final : public Creature, public Cylinder, public Bankable { const std::string &getName() const override { return name; } - void setName(std::string newName) { - this->name = std::move(newName); + void setName(const std::string &name) { + this->name = name; } const std::string &getTypeName() const override { return name; @@ -1075,6 +1075,11 @@ class Player final : public Creature, public Cylinder, public Bankable { client->sendRemoveTileThing(pos, stackpos); } } + void sendUpdateTileCreature(const std::shared_ptr creature) { + if (client) { + client->sendUpdateTileCreature(creature->getPosition(), creature->getTile()->getClientIndexOfCreature(static_self_cast(), creature), creature); + } + } void sendUpdateTile(std::shared_ptr updateTile, const Position &pos) { if (client) { client->sendUpdateTile(updateTile, pos); diff --git a/src/lua/functions/creatures/monster/monster_functions.cpp b/src/lua/functions/creatures/monster/monster_functions.cpp index 1591053c391..273f6af5c99 100644 --- a/src/lua/functions/creatures/monster/monster_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_functions.cpp @@ -77,7 +77,7 @@ int MonsterFunctions::luaMonsterSetType(lua_State* L) { } // Assign new MonsterType monster->mType = mType; - monster->strDescription = asLowerCaseString(mType->nameDescription); + monster->nameDescription = asLowerCaseString(mType->nameDescription); monster->defaultOutfit = mType->info.outfit; monster->currentOutfit = mType->info.outfit; monster->skull = mType->info.skull; @@ -529,6 +529,24 @@ int MonsterFunctions::luaMonsterGetName(lua_State* L) { return 1; } +int MonsterFunctions::luaMonsterSetName(lua_State* L) { + // monster:setName(name[, nameDescription]) + auto monster = getUserdataShared(L, 1); + if (!monster) { + reportErrorFunc(getErrorDesc(LUA_ERROR_MONSTER_NOT_FOUND)); + pushBoolean(L, false); + return 0; + } + + monster->setName(getString(L, 2)); + if (lua_gettop(L) >= 3) { + monster->setNameDescription(getString(L, 3)); + } + + pushBoolean(L, true); + return 1; +} + int MonsterFunctions::luaMonsterHazard(lua_State* L) { // get: monster:hazard() ; set: monster:hazard(hazard) std::shared_ptr monster = getUserdataShared(L, 1); diff --git a/src/lua/functions/creatures/monster/monster_functions.hpp b/src/lua/functions/creatures/monster/monster_functions.hpp index bf2785ae430..dd1c3827344 100644 --- a/src/lua/functions/creatures/monster/monster_functions.hpp +++ b/src/lua/functions/creatures/monster/monster_functions.hpp @@ -56,6 +56,7 @@ class MonsterFunctions final : LuaScriptInterface { registerMethod(L, "Monster", "isForgeable", MonsterFunctions::luaMonsterIsForgeable); registerMethod(L, "Monster", "getName", MonsterFunctions::luaMonsterGetName); + registerMethod(L, "Monster", "setName", MonsterFunctions::luaMonsterSetName); registerMethod(L, "Monster", "hazard", MonsterFunctions::luaMonsterHazard); registerMethod(L, "Monster", "hazardCrit", MonsterFunctions::luaMonsterHazardCrit); @@ -116,6 +117,7 @@ class MonsterFunctions final : LuaScriptInterface { static int luaMonsterIsForgeable(lua_State* L); static int luaMonsterGetName(lua_State* L); + static int luaMonsterSetName(lua_State* L); static int luaMonsterHazard(lua_State* L); static int luaMonsterHazardCrit(lua_State* L); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 98bacfc5e12..8cf0660a262 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -5947,7 +5947,7 @@ void ProtocolGame::sendCreatureTurn(std::shared_ptr creature, uint32_t NetworkMessage msg; msg.addByte(0x6B); msg.addPosition(creature->getPosition()); - msg.addByte(stackPos); + msg.addByte(static_cast(stackPos)); msg.add(0x63); msg.add(creature->getID()); msg.addByte(creature->getDirection()); @@ -6385,7 +6385,7 @@ void ProtocolGame::sendAddTileItem(const Position &pos, uint32_t stackpos, std:: NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); AddItem(msg, item); writeToOutputBuffer(msg); } @@ -6398,7 +6398,7 @@ void ProtocolGame::sendUpdateTileItem(const Position &pos, uint32_t stackpos, st NetworkMessage msg; msg.addByte(0x6B); msg.addPosition(pos); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); AddItem(msg, item); writeToOutputBuffer(msg); } @@ -6413,6 +6413,23 @@ void ProtocolGame::sendRemoveTileThing(const Position &pos, uint32_t stackpos) { writeToOutputBuffer(msg); } +void ProtocolGame::sendUpdateTileCreature(const Position &pos, uint32_t stackpos, const std::shared_ptr creature) { + if (!canSee(pos)) { + return; + } + + NetworkMessage msg; + msg.addByte(0x6B); + msg.addPosition(pos); + msg.addByte(static_cast(stackpos)); + + bool known; + uint32_t removedKnown; + checkCreatureAsKnown(creature->getID(), known, removedKnown); + AddCreature(msg, creature, false, removedKnown); + writeToOutputBuffer(msg); +} + void ProtocolGame::sendUpdateTile(std::shared_ptr tile, const Position &pos) { if (!canSee(pos)) { return; @@ -6484,7 +6501,7 @@ void ProtocolGame::sendAddCreature(std::shared_ptr creature, const Pos NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); bool known; uint32_t removedKnown; @@ -6641,7 +6658,7 @@ void ProtocolGame::sendMoveCreature(std::shared_ptr creature, const Po } else { msg.addByte(0x6D); msg.addPosition(oldPos); - msg.addByte(oldStackPos); + msg.addByte(static_cast(oldStackPos)); msg.addPosition(newPos); } @@ -6676,7 +6693,7 @@ void ProtocolGame::sendMoveCreature(std::shared_ptr creature, const Po NetworkMessage msg; msg.addByte(0x6D); msg.addPosition(oldPos); - msg.addByte(oldStackPos); + msg.addByte(static_cast(oldStackPos)); msg.addPosition(newPos); writeToOutputBuffer(msg); } @@ -7836,7 +7853,7 @@ void ProtocolGame::RemoveTileThing(NetworkMessage &msg, const Position &pos, uin msg.addByte(0x6C); msg.addPosition(pos); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); } void ProtocolGame::sendKillTrackerUpdate(std::shared_ptr corpse, const std::string &name, const Outfit_t creatureOutfit) { @@ -8279,7 +8296,7 @@ void ProtocolGame::reloadCreature(std::shared_ptr creature) { if (knownCreatureSet.contains(creature->getID())) { msg.addByte(0x6B); msg.addPosition(creature->getPosition()); - msg.addByte(stackpos); + msg.addByte(static_cast(stackpos)); AddCreature(msg, creature, false, 0); } else { sendAddCreature(creature, creature->getPosition(), stackpos, false); diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index 0386093cfc4..100ca199b77 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -393,6 +393,7 @@ class ProtocolGame final : public Protocol { void sendAddTileItem(const Position &pos, uint32_t stackpos, std::shared_ptr item); void sendUpdateTileItem(const Position &pos, uint32_t stackpos, std::shared_ptr item); void sendRemoveTileThing(const Position &pos, uint32_t stackpos); + void sendUpdateTileCreature(const Position &pos, uint32_t stackpos, const std::shared_ptr creature); void sendUpdateTile(std::shared_ptr tile, const Position &pos); void sendAddCreature(std::shared_ptr creature, const Position &pos, int32_t stackpos, bool isLogin);