From 9ad973ec5232e4e77674c4d6d602b8e830d44312 Mon Sep 17 00:00:00 2001 From: Marcin Michalski Date: Sat, 18 Sep 2021 00:25:50 +0200 Subject: [PATCH] Make monsters walk to spawn by chunked path (#3612) Issues addressed: #3600 Supersedes PR: #3610 --- src/creature.cpp | 4 ++-- src/luascript.cpp | 27 ++++++++++++++++++++++++ src/luascript.h | 3 +++ src/monster.cpp | 52 +++++++++++++++++++++++++++++++++-------------- src/monster.h | 9 +++++++- 5 files changed, 77 insertions(+), 18 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 2058b40be1..49f63d888c 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -211,11 +211,11 @@ void Creature::onWalk() forceUpdateFollowPath = true; } } else { + stopEventWalk(); + if (listWalkDir.empty()) { onWalkComplete(); } - - stopEventWalk(); } } diff --git a/src/luascript.cpp b/src/luascript.cpp index 9c2404a9dc..bcdd44e9c9 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -2558,6 +2558,9 @@ void LuaScriptInterface::registerFunctions() registerMethod("Monster", "selectTarget", LuaScriptInterface::luaMonsterSelectTarget); registerMethod("Monster", "searchTarget", LuaScriptInterface::luaMonsterSearchTarget); + registerMethod("Monster", "isWalkingToSpawn", LuaScriptInterface::luaMonsterIsWalkingToSpawn); + registerMethod("Monster", "walkToSpawn", LuaScriptInterface::luaMonsterWalkToSpawn); + // Npc registerClass("Npc", "Creature", LuaScriptInterface::luaNpcCreate); registerMetaMethod("Npc", "__eq", LuaScriptInterface::luaUserdataCompare); @@ -10635,6 +10638,30 @@ int LuaScriptInterface::luaMonsterSearchTarget(lua_State* L) return 1; } +int LuaScriptInterface::luaMonsterIsWalkingToSpawn(lua_State* L) +{ + // monster:isWalkingToSpawn() + Monster* monster = getUserdata(L, 1); + if (monster) { + pushBoolean(L, monster->isWalkingToSpawn()); + } else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaMonsterWalkToSpawn(lua_State* L) +{ + // monster:walkToSpawn() + Monster* monster = getUserdata(L, 1); + if (monster) { + pushBoolean(L, monster->walkToSpawn()); + } else { + lua_pushnil(L); + } + return 1; +} + // Npc int LuaScriptInterface::luaNpcCreate(lua_State* L) { diff --git a/src/luascript.h b/src/luascript.h index 80eee05163..a66bf4f1c7 100644 --- a/src/luascript.h +++ b/src/luascript.h @@ -1064,6 +1064,9 @@ class LuaScriptInterface static int luaMonsterSelectTarget(lua_State* L); static int luaMonsterSearchTarget(lua_State* L); + static int luaMonsterIsWalkingToSpawn(lua_State* L); + static int luaMonsterWalkToSpawn(lua_State* L); + // Npc static int luaNpcCreate(lua_State* L); diff --git a/src/monster.cpp b/src/monster.cpp index 9b50848f18..f57ace9ebf 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -517,17 +517,13 @@ void Monster::onCreatureLeave(Creature* creature) //update targetList if (isOpponent(creature)) { removeTarget(creature); - if (targetList.empty()) { + updateIdleStatus(); + + if (!isSummon() && targetList.empty()) { int32_t walkToSpawnRadius = g_config.getNumber(ConfigManager::DEFAULT_WALKTOSPAWNRADIUS); if (walkToSpawnRadius > 0 && !Position::areInRange(position, masterPos, walkToSpawnRadius, walkToSpawnRadius)) { - std::vector dirList; - if (getPathTo(masterPos, dirList, 0, 0, true, true)) { - startAutoWalk(dirList); - return; - } + walkToSpawn(); } - - updateIdleStatus(); } } } @@ -718,10 +714,6 @@ void Monster::updateIdleStatus() }) == conditions.end(); } - if (idle) { - idle = listWalkDir.empty(); - } - setIdle(idle); } @@ -1059,11 +1051,41 @@ void Monster::onThinkYell(uint32_t interval) } } +bool Monster::walkToSpawn() +{ + if (walkingToSpawn || !spawn || !targetList.empty()) { + return false; + } + + int32_t distance = std::max(Position::getDistanceX(position, masterPos), Position::getDistanceY(position, masterPos)); + if (distance == 0) { + return false; + } + + listWalkDir.clear(); + if (!getPathTo(masterPos, listWalkDir, 0, std::max(0, distance - 5), true, true, distance)) { + return false; + } + + walkingToSpawn = true; + startAutoWalk(); + return true; +} + void Monster::onWalk() { Creature::onWalk(); } +void Monster::onWalkComplete() +{ + // Continue walking to spawn + if (walkingToSpawn) { + walkingToSpawn = false; + walkToSpawn(); + } +} + bool Monster::pushItem(Item* item) { const Position& centerPos = item->getPosition(); @@ -1168,20 +1190,20 @@ void Monster::pushCreatures(Tile* tile) bool Monster::getNextStep(Direction& direction, uint32_t& flags) { - if (listWalkDir.empty() && (isIdle || getHealth() <= 0)) { + if (!walkingToSpawn && (isIdle || getHealth() <= 0)) { //we don't have anyone watching, might as well stop walking eventWalk = 0; return false; } bool result = false; - if (listWalkDir.empty() && (!followCreature || !hasFollowPath) && (!isSummon() || !isMasterInRange)) { + if (!walkingToSpawn && (!followCreature || !hasFollowPath) && (!isSummon() || !isMasterInRange)) { if (getTimeSinceLastMove() >= 1000) { randomStepping = true; //choose a random direction result = getRandomStep(getPosition(), direction); } - } else if ((isSummon() && isMasterInRange) || followCreature || !listWalkDir.empty()) { + } else if ((isSummon() && isMasterInRange) || followCreature || walkingToSpawn) { randomStepping = false; result = Creature::getNextStep(direction, flags); if (result) { diff --git a/src/monster.h b/src/monster.h index 8ce39991f0..9375713ffb 100644 --- a/src/monster.h +++ b/src/monster.h @@ -134,7 +134,13 @@ class Monster final : public Creature void drainHealth(Creature* attacker, int32_t damage) override; void changeHealth(int32_t healthChange, bool sendHealthChange = true) override; + + bool isWalkingToSpawn() const { + return walkingToSpawn; + } + bool walkToSpawn(); void onWalk() override; + void onWalkComplete() override; bool getNextStep(Direction& direction, uint32_t& flags) override; void onFollowCreatureComplete(const Creature* creature) override; @@ -203,10 +209,11 @@ class Monster final : public Creature Position masterPos; + bool ignoreFieldDamage = false; bool isIdle = true; bool isMasterInRange = false; bool randomStepping = false; - bool ignoreFieldDamage = false; + bool walkingToSpawn = false; void onCreatureEnter(Creature* creature); void onCreatureLeave(Creature* creature);