Skip to content

Commit

Permalink
Improved approach to reasoning about the attacked and followed Creatu…
Browse files Browse the repository at this point in the history
…re (otland#4824)
  • Loading branch information
ramon-bernardo authored Nov 17, 2024
1 parent a03f893 commit 173ab18
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 90 deletions.
107 changes: 68 additions & 39 deletions src/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Creature::Creature() { onIdleStatus(); }
Creature::~Creature()
{
for (Creature* summon : summons) {
summon->setAttackedCreature(nullptr);
summon->removeAttackedCreature();
summon->removeMaster();
}

Expand Down Expand Up @@ -338,12 +338,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 @@ -721,26 +721,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 @@ -752,37 +768,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 @@ -3231,14 +3231,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 @@ -3247,11 +3247,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 @@ -3262,9 +3263,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 @@ -8115,11 +8115,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 @@ -8146,11 +8155,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 @@ -679,11 +679,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 @@ -787,7 +798,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 @@ -1852,7 +1863,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

0 comments on commit 173ab18

Please sign in to comment.