Skip to content
Draft
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
4 changes: 4 additions & 0 deletions libzhl/functions/ASM.zhl
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,7 @@ asm AutoReassignControllers_Reassign "e8????????836d??018b4d";
asm ControllerDisconnected_Unassign "e8????????c645??018d8d";
asm ControllerDisconnected_Reassign "e8????????85ff75??8935";
asm ControllerDisconnected_LoopEnd "8945??3b45??0f82????????85d2";

// Pathfinding

asm NPCAI_Pathfinder_LineOfSightThresholdOverride "516a008d45??8bce";
39 changes: 39 additions & 0 deletions repentogon/LuaInterfaces/Entities/LuaEntity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,42 @@ LUA_FUNCTION(Lua_EntitySetVariant) {
return 0;
}

LUA_FUNCTION(Lua_EntityGetLineOfSightCostThreshold) {
Entity* ent = lua::GetLuabridgeUserdata<Entity*>(L, 1, lua::Metatables::ENTITY, "Entity");
EntityPlus* plus = GetEntityPlus(ent);

if (plus && plus->lineOfSightCostThreshold.has_value()) {
lua_pushinteger(L, plus->lineOfSightCostThreshold.value());
}
else {
// TODO: Have fallback match what decomp does internally
lua_pushinteger(L, 900);
}
return 1;
}

LUA_FUNCTION(Lua_EntitySetLineOfSightCostThreshold) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a thought, pretty sure that the Pathfinder class has a reference to its parent Entity:

Entity * _entity : 0x0;

So in theory, you could still have these as Pathfinder functions, while under the hood they still read/write from EntityPlus

This is hypothetical though, lemme know if it doesn't seem like that would work. Just seems like something that should be in Pathfinder API-wise

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

Entity* ent = lua::GetLuabridgeUserdata<Entity*>(L, 1, lua::Metatables::ENTITY, "Entity");
int threshold = (int)luaL_checkinteger(L, 2);
EntityPlus* plus = GetEntityPlus(ent);

if (plus) {
plus->lineOfSightCostThreshold = threshold;
}

return 0;
}

LUA_FUNCTION(Lua_EntityResetLineOfSightCostThreshold) {
Entity* ent = lua::GetLuabridgeUserdata<Entity*>(L, 1, lua::Metatables::ENTITY, "Entity");
EntityPlus* plus = GetEntityPlus(ent);

if (plus) {
plus->lineOfSightCostThreshold = std::nullopt;
}

return 0;
}

HOOK_METHOD(LuaEngine, RegisterClasses, () -> void) {
super();
Expand Down Expand Up @@ -955,6 +991,9 @@ HOOK_METHOD(LuaEngine, RegisterClasses, () -> void) {
{ "SetWaterClipFlags", Lua_EntitySetWaterClipFlags },
{ "ResetWaterClipFlags", Lua_EntityResetWaterClipFlags },
{ "CanDevolve", Lua_EntityCanDevolve },
{ "GetLineOfSightCostThreshold", Lua_EntityGetLineOfSightCostThreshold },
{ "SetLineOfSightCostThreshold", Lua_EntitySetLineOfSightCostThreshold },
{ "ResetLineOfSightCostThreshold", Lua_EntityResetLineOfSightCostThreshold },
{ NULL, NULL }
};
lua::RegisterFunctions(_state, lua::Metatables::ENTITY, functions);
Expand Down
1 change: 1 addition & 0 deletions repentogon/Patches/ASMPatches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ void PerformASMPatches() {
ASMPatchHushBug();
ASMPatchFireProjectiles();
ASMPatchFireBossProjectiles();
ASMPatchLineOfSightThreshold();
//ASMPatchApplyFrozenEnemyDeathEffects(); // This was disabled prior to rep+, ignore it!

// EntityKnife
Expand Down
35 changes: 35 additions & 0 deletions repentogon/Patches/ASMPatches/ASMEntityNPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
#include "../ASMPatches.h"

#include "ASMEntityNPC.h"
#include "../EntityPlus.h"

#include "HookSystem.h"
#include "../XMLData.h"
#include "ASMDefinition.h"

thread_local FireProjectilesStorage projectilesStorage;

Expand Down Expand Up @@ -134,6 +136,39 @@ void ASMPatchApplyFrozenEnemyDeathEffects() {
sASMPatcher.PatchAt(addr, &patch);
}


int __stdcall GetLineOfSightThresholdOverride(Entity* entity, int originalThreshold) {
EntityPlus* plus = GetEntityPlus(entity);

if (plus && plus->lineOfSightCostThreshold.has_value()) {
return plus->lineOfSightCostThreshold.value();
}

return originalThreshold;
}

void ASMPatchLineOfSightThreshold() {
void* addr = sASMDefinitionHolder->GetDefinition(&AsmDefinitions::NPCAI_Pathfinder_LineOfSightThresholdOverride);
printf("[REPENTOGON] Patching NPCAI_Pathfinder::FindGridPath line of sight threshold at %p\n", addr);

ASMPatch::SavedRegisters reg(ASMPatch::SavedRegisters::GP_REGISTERS_STACKLESS & ~ASMPatch::SavedRegisters::Registers::EAX, true);

ASMPatch patch;
patch.PreserveRegisters(reg)
.Push(ASMPatch::Registers::ECX) // Original threshold
.AddBytes("\x8B\x07") // mov eax, [edi] (Get Entity* from Pathfinder)
.Push(ASMPatch::Registers::EAX)
.AddInternalCall(GetLineOfSightThresholdOverride)
// Restore our registers and call our functions as is.
.RestoreRegisters(reg)
.Push(ASMPatch::Registers::EAX)
.Push((int8_t)0)
.LoadEffectiveAddress(ASMPatch::Registers::EBP, -0x48, ASMPatch::Registers::EAX)
.AddRelativeJump((char*)addr + 0x6);

sASMPatcher.PatchAt(addr, &patch);
}

HOOK_METHOD(Entity, IsActiveEnemy, (bool includeDead) -> bool) {
if (this->_type >= ENTITY_GAPER && this->_type < ENTITY_EFFECT) {
const std::string attr = XMLStuff.EntityData->GetAttributeByTypeVarSub(this->_type, this->_variant, this->_subtype, false, "isactiveenemy");
Expand Down
3 changes: 2 additions & 1 deletion repentogon/Patches/ASMPatches/ASMEntityNPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ static std::vector<Entity_Projectile*>& InitProjectileStorage() {
void ASMPatchHushBug();
void ASMPatchFireProjectiles();
void ASMPatchFireBossProjectiles();
void ASMPatchApplyFrozenEnemyDeathEffects();
void ASMPatchApplyFrozenEnemyDeathEffects();
void ASMPatchLineOfSightThreshold();
4 changes: 4 additions & 0 deletions repentogon/Patches/EntityPlus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ EntityKnifePlus* GetEntityKnifePlus(Entity_Knife* knife) {
return dynamic_cast<EntityKnifePlus*>(GetEntityPlusHolder(knife, true)->data.get());
}

EntityNPCPlus* GetEntityNPCPlus(Entity_NPC* npc) {
return dynamic_cast<EntityNPCPlus*>(GetEntityPlusHolder(npc, true)->data.get());
}


// ----------------------------------------------------------------------------------------------------
// -- Make entities obey EntityPlus.isFlyingOverride
Expand Down
7 changes: 7 additions & 0 deletions repentogon/Patches/EntityPlus.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class EntityPlus {
public:
virtual ~EntityPlus() {}

std::optional<int> lineOfSightCostThreshold = std::nullopt;
std::optional<bool> isFlyingOverride = std::nullopt;
std::optional<uint32_t> waterClipInfoFlagsOverride = std::nullopt;
};
Expand Down Expand Up @@ -56,6 +57,11 @@ class EntityKnifePlus : public EntityPlus {
EntityPtr hitboxSource;
};

// Attributes for EntityNPC.
class EntityNPCPlus : public EntityPlus {
public:
};

// Returns a ptr to the base EntityPlus class held by the entity.
// In theory should typically not be nullptr as it, or a child class, is initialized on entity Init.
EntityPlus* GetEntityPlus(Entity* entity);
Expand All @@ -67,5 +73,6 @@ EntityFamiliarPlus* GetEntityFamiliarPlus(Entity_Familiar* familiar);
EntityTearPlus* GetEntityTearPlus(Entity_Tear* tear);
EntityLaserPlus* GetEntityLaserPlus(Entity_Laser* laser);
EntityKnifePlus* GetEntityKnifePlus(Entity_Knife* knife);
EntityNPCPlus* GetEntityNPCPlus(Entity_NPC* npc);

void ASMPatchesForEntityPlus();
7 changes: 7 additions & 0 deletions repentogon/resources/scripts/enums_ex.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3174,6 +3174,13 @@ TrinketSlot = {
BELLY_BUTTON = 1,
}

GridPathThreshold = {
DEFAULT = 900,
IGNORE_DECAY = 950,
IGNORE_FIREPLACES_AND_DECAY = 1000,
IGNORE_EVERYTHING = 1001
}

--deprecated enums

Achievement.REVERSED_THE_HEIROPHANT = 529
Expand Down
Loading