Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved approach to reasoning about the attacked and followed Creature #4824

Merged
21 commits merged into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 68 additions & 39 deletions src/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Creature::Creature() { onIdleStatus(); }
Creature::~Creature()
{
for (Creature* summon : summons) {
summon->setAttackedCreature(nullptr);
summon->removeAttackedCreature();
summon->removeMaster();
}

Expand Down Expand Up @@ -339,12 +339,12 @@ void Creature::onRemoveCreature(Creature* creature, bool) { onCreatureDisappear(
void Creature::onCreatureDisappear(const Creature* creature, bool isLogout)
{
if (attackedCreature == creature) {
setAttackedCreature(nullptr);
removeAttackedCreature();
onAttackedCreatureDisappear(isLogout);
}

if (followCreature == creature) {
setFollowCreature(nullptr);
removeFollowCreature();
onFollowCreatureDisappear(isLogout);
}
}
Expand Down Expand Up @@ -722,26 +722,42 @@ BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int3
return blockType;
}

bool Creature::setAttackedCreature(Creature* creature)
void Creature::setAttackedCreature(Creature* creature)
{
if (creature) {
const Position& creaturePos = creature->getPosition();
if (creaturePos.z != getPosition().z || !canSee(creaturePos)) {
attackedCreature = nullptr;
return false;
}
if (isAttackingCreature(creature)) {
return;
}

attackedCreature = creature;
onAttackedCreature(attackedCreature);
attackedCreature->onAttacked();
} else {
attackedCreature = nullptr;
if (!canAttackCreature(creature)) {
removeAttackedCreature();
return;
}

attackedCreature = creature;
onAttackedCreature(attackedCreature);
attackedCreature->onAttacked();

for (Creature* summon : summons) {
summon->setAttackedCreature(creature);
}
return true;
}

void Creature::removeAttackedCreature()
{
attackedCreature = nullptr;

for (Creature* summon : summons) {
summon->removeAttackedCreature();
}
}

bool Creature::canAttackCreature(Creature* creature)
{
const auto& creaturePos = creature->getPosition();
if (creaturePos.z != getPosition().z) {
return false;
}
return canSee(creaturePos);
}

void Creature::getPathSearchParams(const Creature*, FindPathParams& fpp) const
Expand All @@ -753,37 +769,50 @@ void Creature::getPathSearchParams(const Creature*, FindPathParams& fpp) const
fpp.maxTargetDist = 1;
}

bool Creature::setFollowCreature(Creature* creature)
void Creature::setFollowCreature(Creature* creature)
{
if (creature) {
if (followCreature == creature) {
return true;
}
if (isFollowingCreature(creature)) {
return;
}

const Position& creaturePos = creature->getPosition();
if (creaturePos.z != getPosition().z || !canSee(creaturePos)) {
followCreature = nullptr;
return false;
}
if (!canFollowCreature(creature)) {
removeFollowCreature();
return;
}

if (!listWalkDir.empty()) {
listWalkDir.clear();
onWalkAborted();
}
followCreature = creature;
onFollowCreature(creature);
}

hasFollowPath = false;
forceUpdateFollowPath = false;
followCreature = creature;
isUpdatingPath = true;
} else {
isUpdatingPath = false;
followCreature = nullptr;
void Creature::removeFollowCreature()
{
followCreature = nullptr;
onUnfollowCreature();
}

bool Creature::canFollowCreature(Creature* creature)
{
const auto& creaturePos = creature->getPosition();
if (creaturePos.z != getPosition().z) {
return false;
}
return canSee(creaturePos);
}

onFollowCreature(creature);
return true;
void Creature::onFollowCreature(const Creature*)
{
if (!listWalkDir.empty()) {
listWalkDir.clear();
onWalkAborted();
}

hasFollowPath = false;
forceUpdateFollowPath = false;
isUpdatingPath = true;
}

void Creature::onUnfollowCreature() { isUpdatingPath = false; }

double Creature::getDamageRatio(Creature* attacker) const
{
uint32_t totalDamage = 0;
Expand Down
14 changes: 11 additions & 3 deletions src/creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,22 @@ class Creature : virtual public Thing

// follow functions
Creature* getFollowCreature() const { return followCreature; }
virtual bool setFollowCreature(Creature* creature);
virtual void setFollowCreature(Creature* creature);
virtual void removeFollowCreature();
virtual bool canFollowCreature(Creature* creature);
virtual bool isFollowingCreature(Creature* creature) { return followCreature == creature; }

// follow events
virtual void onFollowCreature(const Creature*) {}
virtual void onFollowCreature(const Creature*);
virtual void onUnfollowCreature();

// combat functions
Creature* getAttackedCreature() { return attackedCreature; }
virtual bool setAttackedCreature(Creature* creature);
virtual void setAttackedCreature(Creature* creature);
virtual void removeAttackedCreature();
virtual bool canAttackCreature(Creature* creature);
virtual bool isAttackingCreature(Creature* creature) { return attackedCreature == creature; }

virtual BlockType_t blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
bool checkDefense = false, bool checkArmor = false, bool field = false,
bool ignoreResistances = false);
Expand Down
17 changes: 12 additions & 5 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3232,14 +3232,14 @@ void Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId)
}

if (player->getAttackedCreature() && creatureId == 0) {
player->setAttackedCreature(nullptr);
player->removeAttackedCreature();
player->sendCancelTarget();
return;
}

Creature* attackCreature = getCreatureByID(creatureId);
if (!attackCreature) {
player->setAttackedCreature(nullptr);
player->removeAttackedCreature();
player->sendCancelTarget();
return;
}
Expand All @@ -3248,11 +3248,12 @@ void Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId)
if (ret != RETURNVALUE_NOERROR) {
player->sendCancelMessage(ret);
player->sendCancelTarget();
player->setAttackedCreature(nullptr);
player->removeAttackedCreature();
return;
}

player->setAttackedCreature(attackCreature);

g_dispatcher.addTask([this, id = player->getID()]() { updateCreatureWalk(id); });
}

Expand All @@ -3263,9 +3264,15 @@ void Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId)
return;
}

player->setAttackedCreature(nullptr);
player->removeAttackedCreature();

if (Creature* followCreature = getCreatureByID(creatureId)) {
player->setFollowCreature(followCreature);
} else {
player->removeFollowCreature();
}

g_dispatcher.addTask([this, id = player->getID()]() { updateCreatureWalk(id); });
player->setFollowCreature(getCreatureByID(creatureId));
}

void Game::playerSetFightModes(uint32_t playerId, fightMode_t fightMode, bool chaseMode, bool secureMode)
Expand Down
33 changes: 25 additions & 8 deletions src/luascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8116,11 +8116,20 @@ int LuaScriptInterface::luaCreatureGetTarget(lua_State* L)
int LuaScriptInterface::luaCreatureSetTarget(lua_State* L)
{
// creature:setTarget(target)
Creature* creature = tfs::lua::getUserdata<Creature>(L, 1);
if (creature) {
tfs::lua::pushBoolean(L, creature->setAttackedCreature(tfs::lua::getCreature(L, 2)));
} else {
auto creature = tfs::lua::getUserdata<Creature>(L, 1);
if (!creature) {
lua_pushnil(L);

return 1;
}

auto target = tfs::lua::getCreature(L, 2);
if (target) {
creature->setAttackedCreature(target);
tfs::lua::pushBoolean(L, creature->canAttackCreature(target));
} else {
creature->removeAttackedCreature();
tfs::lua::pushBoolean(L, true);
}
return 1;
}
Expand All @@ -8147,11 +8156,19 @@ int LuaScriptInterface::luaCreatureGetFollowCreature(lua_State* L)
int LuaScriptInterface::luaCreatureSetFollowCreature(lua_State* L)
{
// creature:setFollowCreature(followedCreature)
Creature* creature = tfs::lua::getUserdata<Creature>(L, 1);
if (creature) {
tfs::lua::pushBoolean(L, creature->setFollowCreature(tfs::lua::getCreature(L, 2)));
} else {
auto creature = tfs::lua::getUserdata<Creature>(L, 1);
if (!creature) {
lua_pushnil(L);
return 1;
}

auto followedCreature = tfs::lua::getCreature(L, 2);
if (followedCreature) {
creature->setFollowCreature(followedCreature);
tfs::lua::pushBoolean(L, creature->canFollowCreature(followedCreature));
} else {
creature->removeFollowCreature();
tfs::lua::pushBoolean(L, true);
}
return 1;
}
Expand Down
21 changes: 16 additions & 5 deletions src/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,11 +680,22 @@ bool Monster::selectTarget(Creature* creature)
}

if (isHostile() || isSummon()) {
if (setAttackedCreature(creature) && !isSummon()) {
g_dispatcher.addTask([id = getID()]() { g_game.checkCreatureAttack(id); });
if (canAttackCreature(creature)) {
setAttackedCreature(creature);

if (isHostile()) {
g_dispatcher.addTask([id = getID()]() { g_game.checkCreatureAttack(id); });
}
} else {
removeAttackedCreature();
}
}
return setFollowCreature(creature);

if (isFollowingCreature(creature) || canFollowCreature(creature)) {
setFollowCreature(creature);
return true;
}
return false;
}

void Monster::setIdle(bool idle)
Expand Down Expand Up @@ -788,7 +799,7 @@ void Monster::onThink(uint32_t interval)
setFollowCreature(getMaster());
}
} else if (attackedCreature == this) {
setFollowCreature(nullptr);
removeFollowCreature();
} else if (followCreature != attackedCreature) {
// This happens just after a master orders an attack, so lets follow it as well.
setFollowCreature(attackedCreature);
Expand Down Expand Up @@ -1853,7 +1864,7 @@ bool Monster::canWalkTo(Position pos, Direction direction) const

void Monster::death(Creature*)
{
setAttackedCreature(nullptr);
removeAttackedCreature();

for (Creature* summon : summons) {
summon->changeHealth(-summon->getHealth());
Expand Down
9 changes: 8 additions & 1 deletion src/npc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,14 @@ int NpcScriptInterface::luaActionFollow(lua_State* L)
return 1;
}

tfs::lua::pushBoolean(L, npc->setFollowCreature(tfs::lua::getPlayer(L, 1)));
auto followedPlayer = tfs::lua::getPlayer(L, 1);
if (followedPlayer) {
npc->setFollowCreature(followedPlayer);
tfs::lua::pushBoolean(L, npc->canFollowCreature(followedPlayer));
} else {
npc->removeFollowCreature();
tfs::lua::pushBoolean(L, true);
}
return 1;
}

Expand Down
Loading
Loading