Skip to content

Commit

Permalink
Implement TargetZoneScanType to allow AI units to properly target obj…
Browse files Browse the repository at this point in the history
…ects outside of their movement zone
  • Loading branch information
Rampastring committed Dec 20, 2024
1 parent 1ed3234 commit 8bf233d
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 1 deletion.
95 changes: 95 additions & 0 deletions src/extensions/techno/technoext_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2550,6 +2550,99 @@ DECLARE_PATCH(_TechnoClass_Fire_At_TargetLaserTimer_Patch)
}


/**
* #issue-1161
*
* Helper function. Checks whether a target is valid considering zone evaluation.
*
* @author: Rampastring
*/
bool _TechnoClass_Evaluate_Object_Zone_Evaluation_Is_Valid_Target(TechnoClass* techno, TARGET target, int ourzone, int targetzone)
{
auto technotype = techno->Techno_Type_Class();
auto technotypeext = Extension::Fetch<TechnoTypeClassExtension>(technotype);

if (technotypeext->TargetZoneScan == TZST_SAME) {
// Only allow targeting objects in the same zone.
return ourzone == targetzone;
}

if (technotypeext->TargetZoneScan == TZST_ANY) {
// Any zone is allowed.
return true;
}

if (technotypeext->TargetZoneScan == TZST_INRANGE) {
// If the zone is different, only allow targeting if we can reach the target from our zone.

if (ourzone == targetzone) {
return true;
}

Cell nearbycellcoords = Map.Nearby_Location(Coord_Cell(target->Center_Coord()),
technotype->Speed,
/*Phobos has -1 here*/ ourzone,
technotype->MZone,
false, 1, 1, true, false, false, technotype->Speed != SPEED_FLOAT, Cell());

const CellClass& cell = Map[nearbycellcoords];

if (&cell == nullptr) {
// We couldn't find a valid cell to reach the target from
return false;
}

int distance = ::Distance(nearbycellcoords, Coord_Cell(target->Center_Coord()));

WeaponSlotType weaponslot = techno->What_Weapon_Should_I_Use(target);
auto weaponinfo = techno->Get_Weapon(weaponslot);
if (weaponinfo->Weapon == nullptr) {
return false;
}

return (distance * CELL_LEPTON_W) < weaponinfo->Weapon->Range;
}

// For some reason the target zone scan type was invalid. Something is wrong.
Fatal("Invalid TargetZoneScanType for techno type %s", technotype->IniName);
return false;
}


/**
* #issue-1161
*
* Makes Technos consider their TargetZoneScan when potential targets are in a
* different movement zone. Makes the AI smarter when targeting objects on different
* movement zones (for example, ships targeting ground targets).
* Implementation inspired by respective feature for the "Phobos" Yuri's Revenge engine extension.
*
* @author: Rampastring
*/
DECLARE_PATCH(_TechnoClass_Evaluate_Object_Zone_Evaluation_TargetZoneScanType_Patch)
{
GET_REGISTER_STATIC(int, targetzone, eax);
GET_REGISTER_STATIC(int, ourzone, ebp);
GET_REGISTER_STATIC(TARGET, target, esi);
GET_REGISTER_STATIC(TechnoClass*, this_ptr, edi);

enum {
Continue = 0x0062D220,
InvalidTarget = 0x0062D8C0
};

if (targetzone == ourzone) {
JMP(Continue);
}

if (!_TechnoClass_Evaluate_Object_Zone_Evaluation_Is_Valid_Target(this_ptr, target, ourzone, targetzone)) {
JMP(InvalidTarget);
}

JMP(Continue);
}


/**
* Main function for patching the hooks.
*/
Expand Down Expand Up @@ -2599,4 +2692,6 @@ void TechnoClassExtension_Hooks()
Patch_Jump(0x00631FF0, &TechnoClassExt::_Can_Player_Move);
Patch_Jump(0x006336F0, &TechnoClassExt::_Record_The_Kill);
//Patch_Jump(0x0062A3D0, &TechnoClassExt::_Fire_Coord); // Disabled because it's functionally identical to the vanilla function when there's no secondary coordinate
Patch_Jump(0x00633745, (uintptr_t)0x00633762); // Do not trigger "Discovered by Player" when an object is destroyed
Patch_Jump(0x0062D218, &_TechnoClass_Evaluate_Object_Zone_Evaluation_TargetZoneScanType_Patch);
}
35 changes: 34 additions & 1 deletion src/extensions/technotype/technotypeext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ TechnoTypeClassExtension::TechnoTypeClassExtension(const TechnoTypeClass *this_p
IsSpawned(false),
BuildTimeCost(0),
RequiredHouses(-1),
ForbiddenHouses(-1)
ForbiddenHouses(-1),
TargetZoneScan(TZST_SAME)
{
//if (this_ptr) EXT_DEBUG_TRACE("TechnoTypeClassExtension::TechnoTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This()));
}
Expand Down Expand Up @@ -237,6 +238,36 @@ void TechnoTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const
crc(SpawnRegenRate);
crc(SpawnReloadRate);
crc(SpawnsNumber);
crc(TargetZoneScan);
}


/**
* #issue-1161
*
* Fetches the target zone scan type from the INI database.
*
* @author: Rampastring
*/
TargetZoneScanType _Get_TargetZoneScanType(CCINIClass& ini, const char* section, const char* entry, const TargetZoneScanType defvalue)
{
char buffer[1024];

if (ini.Get_String(section, entry, nullptr, buffer, sizeof(buffer)) > 0) {
if (std::strncmp("Same", buffer, sizeof("Same")) == 0) {
return TZST_SAME;
}

if (std::strncmp("Any", buffer, sizeof("Any")) == 0) {
return TZST_ANY;
}

if (std::strncmp("InRange", buffer, sizeof("InRange")) == 0) {
return TZST_INRANGE;
}
}

return defvalue;
}


Expand Down Expand Up @@ -327,5 +358,7 @@ bool TechnoTypeClassExtension::Read_INI(CCINIClass &ini)
RequiredHouses = ini.Get_Owners(ini_name, "RequiredHouses", RequiredHouses);
ForbiddenHouses = ini.Get_Owners(ini_name, "ForbiddenHouses", ForbiddenHouses);

TargetZoneScan = _Get_TargetZoneScanType(ini, ini_name, "TargetZoneScan", TargetZoneScan);

return true;
}
5 changes: 5 additions & 0 deletions src/extensions/technotype/technotypeext.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,9 @@ class TechnoTypeClassExtension : public ObjectTypeClassExtension
* Optional override for the cost that is used for determining the techno's build time.
*/
int BuildTimeCost;

/**
* Defines how the techno treats targets outside of its zone when scanning for targets.
*/
TargetZoneScanType TargetZoneScan;
};
8 changes: 8 additions & 0 deletions src/vinifera/vinifera_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,11 @@ typedef enum ViniferaRTTIType
VINIFERA_RTTI_COUNT
};
DEFINE_ENUMERATION_OPERATORS(ViniferaRTTIType);


typedef enum TargetZoneScanType
{
TZST_SAME,
TZST_ANY,
TZST_INRANGE
} TargetZoneScanType;

0 comments on commit 8bf233d

Please sign in to comment.