Skip to content

Commit

Permalink
Improves the harvester AI. #201, #203
Browse files Browse the repository at this point in the history
  • Loading branch information
Rampastring committed Feb 10, 2023
1 parent 850f118 commit e478322
Show file tree
Hide file tree
Showing 11 changed files with 518 additions and 2 deletions.
31 changes: 31 additions & 0 deletions src/extensions/building/buildingext_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "building.h"
#include "buildingtype.h"
#include "buildingtypeext.h"
#include "unit.h";
#include "unitext.h"
#include "technotype.h"
#include "technotypeext.h"
#include "house.h"
Expand Down Expand Up @@ -464,6 +466,34 @@ DECLARE_PATCH(_BuildingClass_Draw_Spied_Cameo_Palette_Patch)
}


/**
* #issue-203
*
* Assigns the last docked building of a spawned free unit on
* building placement complete (the "grand opening").
* This allows harvesters to know which refinery they spawned from.
*
* @author: Rampastring
*/
DECLARE_PATCH(_BuildingClass_Grand_Opening_Assign_FreeUnit_LastDockedBuilding_Patch)
{
GET_REGISTER_STATIC(BuildingClass*, this_ptr, esi);
GET_REGISTER_STATIC(UnitClass*, unit, edi);
static UnitClassExtension* unitext;

unitext = Extension::Fetch<UnitClassExtension>(unit);
unitext->LastDockedBuilding = this_ptr;

/**
* Continue the FreeUnit down-placing process.
*/
original_code:
_asm { movsx eax, bp }
_asm { movsx ecx, bx }
JMP_REG(edx, 0x0042E5FB);
}


/**
* Main function for patching the hooks.
*/
Expand All @@ -481,4 +511,5 @@ void BuildingClassExtension_Hooks()
Patch_Jump(0x00429A96, &_BuildingClass_AI_ProduceCash_Patch);
Patch_Jump(0x0042F67D, &_BuildingClass_Captured_ProduceCash_Patch);
Patch_Jump(0x0042E179, &_BuildingClass_Grand_Opening_ProduceCash_Patch);
Patch_Jump(0x0042E5F5, &_BuildingClass_Grand_Opening_Assign_FreeUnit_LastDockedBuilding_Patch);
}
149 changes: 149 additions & 0 deletions src/extensions/foot/footext_functions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*******************************************************************************
/* O P E N S O U R C E -- V I N I F E R A **
/*******************************************************************************
*
* @project Vinifera
*
* @file FOOTEXT_FUNCTIONS.CPP
*
* @author Rampastring
*
* @brief Contains the supporting functions for the extended FootClass.
*
* @license Vinifera is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version
* 3 of the License, or (at your option) any later version.
*
* Vinifera is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#include "footext_functions.h"
#include "unitext_functions.h"
#include "unit.h"
#include "unittype.h"
#include "unitext.h"
#include "building.h"
#include "buildingtype.h"
#include "cell.h"
#include "map.h"
#include "mouse.h"
#include "house.h"
#include "technotype.h"
#include "rulesext.h"
#include "session.h"
#include "tibsun_inline.h"
#include "vinifera_globals.h"
#include "tibsun_globals.h"
#include "tibsun_functions.h"
#include "tibsun_defines.h"
#include "debughandler.h"
#include "asserthandler.h"



void _Vinifera_FootClass_Search_For_Tiberium_Check_Tiberium_Value_Of_Cell(FootClass* this_ptr, Cell& cell_coords, Cell* besttiberiumcell, int* besttiberiumvalue, UnitClassExtension* unitext)
{
if (this_ptr->Tiberium_Check(cell_coords)) {

CellClass* cell = &Map[cell_coords];
int tiberiumvalue = cell->Get_Tiberium_Value();

/**
* #issue-203
*
* Consider distance to refinery when selecting the next tiberium patch to harvest.
* Prefer the most resourceful tiberium patch, but if there's a tie, prefer one that's
* closer to our refinery.
*
* @author: Rampastring
*/
if (unitext && unitext->LastDockedBuilding && unitext->LastDockedBuilding->IsActive && !unitext->LastDockedBuilding->IsInLimbo) {
tiberiumvalue *= 100;
tiberiumvalue -= ::Distance(cell_coords, unitext->LastDockedBuilding->Get_Cell());
}

if (tiberiumvalue > * besttiberiumvalue)
{
*besttiberiumvalue = tiberiumvalue;
*besttiberiumcell = cell_coords;
}
}
}


/**
* Smarter replacement for the Search_For_Tiberium method.
* Makes harvesters consider the distance to their refinery when
* looking for the cell of tiberium to harvest.
*
* @author: Rampastring
*/
Cell Vinifera_FootClass_Search_For_Tiberium(FootClass* this_ptr, int rad, bool a2)
{
if (!this_ptr->Owning_House()->Is_Human_Control() &&
this_ptr->What_Am_I() == RTTI_UNIT &&
((UnitClass*)this_ptr)->Class->IsToHarvest &&
a2 &&
Session.Type != GAME_NORMAL)
{
/**
* Use weighted tiberium-seeking algorithm for AI in multiplayer.
*/

return this_ptr->Search_For_Tiberium_Weighted(rad);
}

Coordinate center_coord = this_ptr->Center_Coord();
Cell cell_coords = Coord_Cell(center_coord);
Cell unit_cell_coords = cell_coords;

if (Map[unit_cell_coords].Land_Type() == LAND_TIBERIUM) {

/**
* If we're already standing on tiberium, then we don't need to move anywhere.
*/

return unit_cell_coords;
}

int besttiberiumvalue = -1;
Cell besttiberiumcell = Cell(0, 0);

UnitClassExtension* unitext = nullptr;
if (this_ptr->What_Am_I() == RTTI_UNIT) {
unitext = Extension::Fetch<UnitClassExtension>((UnitClass*)this_ptr);
}

/**
* Perform a ring search outward from the center.
*/
for (int radius = 1; radius < rad; radius++) {
for (int x = -radius; x <= radius; x++) {

cell_coords = Cell(unit_cell_coords.X + x, unit_cell_coords.Y - radius);
_Vinifera_FootClass_Search_For_Tiberium_Check_Tiberium_Value_Of_Cell(this_ptr, cell_coords, &besttiberiumcell, &besttiberiumvalue, unitext);

cell_coords = Cell(unit_cell_coords.X + x, unit_cell_coords.Y + radius);
_Vinifera_FootClass_Search_For_Tiberium_Check_Tiberium_Value_Of_Cell(this_ptr, cell_coords, &besttiberiumcell, &besttiberiumvalue, unitext);

cell_coords = Cell(unit_cell_coords.X - radius, unit_cell_coords.Y + x);
_Vinifera_FootClass_Search_For_Tiberium_Check_Tiberium_Value_Of_Cell(this_ptr, cell_coords, &besttiberiumcell, &besttiberiumvalue, unitext);

cell_coords = Cell(unit_cell_coords.X + radius, unit_cell_coords.Y + x);
_Vinifera_FootClass_Search_For_Tiberium_Check_Tiberium_Value_Of_Cell(this_ptr, cell_coords, &besttiberiumcell, &besttiberiumvalue, unitext);
}

if (besttiberiumvalue != -1)
break;
}

return besttiberiumcell;
}
34 changes: 34 additions & 0 deletions src/extensions/foot/footext_functions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*******************************************************************************
/* O P E N S O U R C E -- V I N I F E R A **
/*******************************************************************************
*
* @project Vinifera
*
* @file FOOTEXT_FUNCTIONS.H
*
* @author Rampastring
*
* @brief Contains the supporting functions for the extended UnitClass.
*
* @license Vinifera is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version
* 3 of the License, or (at your option) any later version.
*
* Vinifera is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#pragma once

#include "always.h"
#include "foot.h"
#include "tibsun_defines.h"

Cell Vinifera_FootClass_Search_For_Tiberium(FootClass* this_ptr, int rad, bool a2);
31 changes: 31 additions & 0 deletions src/extensions/foot/footext_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@
*
******************************************************************************/
#include "footext_hooks.h"
#include "footext_functions.h"
#include "foot.h"
#include "technoext.h"
#include "technotype.h"
#include "technotypeext.h"
#include "unit.h"
#include "unittype.h"
#include "extension.h"
#include "fatal.h"
#include "asserthandler.h"
Expand All @@ -39,6 +42,33 @@
#include "hooker_macros.h"


/**
* A fake class for implementing new member functions which allow
* access to the "this" pointer of the intended class.
*
* @note: This must not contain a constructor or deconstructor!
* @note: All functions must be prefixed with "_" to prevent accidental virtualization.
*/
static class FootClassFake final : public FootClass
{
public:
Cell _Search_For_Tiberium(int rad, bool a2);
};


/**
* #issue-203
*
* Enables smarter harvester tiberium-seeking algorithm.
*
* Author: Rampastring
*/
Cell FootClassFake::_Search_For_Tiberium(int rad, bool a2)
{
return Vinifera_FootClass_Search_For_Tiberium(this, rad, a2);
}


/**
* #issue-593
*
Expand Down Expand Up @@ -283,4 +313,5 @@ void FootClassExtension_Hooks()
Patch_Jump(0x004A2BE7, &_FootClass_Mission_Guard_Area_Can_Passive_Acquire_Patch);
Patch_Jump(0x004A1AAE, &_FootClass_Mission_Guard_Can_Passive_Acquire_Patch);
Patch_Jump(0x004A102F, &_FootClass_Mission_Move_Can_Passive_Acquire_Patch);
Patch_Jump(0x004A76F0, &FootClassFake::_Search_For_Tiberium);
}
5 changes: 4 additions & 1 deletion src/extensions/rules/rulesext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ RulesClassExtension::RulesClassExtension(const RulesClass *this_ptr) :
IsMPAutoDeployMCV(false),
IsMPPrePlacedConYards(false),
IsBuildOffAlly(true),
IsShowSuperWeaponTimers(true)
IsShowSuperWeaponTimers(true),
MaxFreeRefineryDistanceBias(16)
{
//if (this_ptr) EXT_DEBUG_TRACE("RulesClassExtension::RulesClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr));

Expand Down Expand Up @@ -192,6 +193,7 @@ void RulesClassExtension::Compute_CRC(WWCRCEngine &crc) const
crc(IsMPPrePlacedConYards);
crc(IsBuildOffAlly);
crc(IsShowSuperWeaponTimers);
crc(MaxFreeRefineryDistanceBias);
}


Expand Down Expand Up @@ -426,6 +428,7 @@ bool RulesClassExtension::General(CCINIClass &ini)
* @author: CCHyper
*/
This()->EngineerDamage = ini.Get_Float(GENERAL, "EngineerDamage", This()->EngineerDamage);
MaxFreeRefineryDistanceBias = ini.Get_Int(GENERAL, "MaxFreeRefineryDistanceBias", MaxFreeRefineryDistanceBias);

return true;
}
Expand Down
7 changes: 7 additions & 0 deletions src/extensions/rules/rulesext.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,11 @@ class RulesClassExtension final : public GlobalExtensionClass<RulesClass>
* on the tactical view?
*/
bool IsShowSuperWeaponTimers;

/**
* When looking for refineries, harvesters will prefer a distant free
* refinery over a closer occupied refinery if the refineries' distance
* difference in cells is less than this.
*/
int MaxFreeRefineryDistanceBias;
};
9 changes: 8 additions & 1 deletion src/extensions/unit/unitext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
******************************************************************************/
#include "unitext.h"
#include "unit.h"
#include "building.h"
#include "vinifera_saveload.h"
#include "wwcrc.h"
#include "extension.h"
#include "asserthandler.h"
Expand All @@ -39,7 +41,8 @@
* @author: CCHyper
*/
UnitClassExtension::UnitClassExtension(const UnitClass *this_ptr) :
FootClassExtension(this_ptr)
FootClassExtension(this_ptr),
LastDockedBuilding(nullptr)
{
//if (this_ptr) EXT_DEBUG_TRACE("UnitClassExtension::UnitClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This()));

Expand Down Expand Up @@ -107,6 +110,8 @@ HRESULT UnitClassExtension::Load(IStream *pStm)

new (this) UnitClassExtension(NoInitClass());

VINIFERA_SWIZZLE_REQUEST_POINTER_REMAP(LastDockedBuilding, "LastDockedBuilding");

return hr;
}

Expand Down Expand Up @@ -161,4 +166,6 @@ void UnitClassExtension::Detach(TARGET target, bool all)
void UnitClassExtension::Compute_CRC(WWCRCEngine &crc) const
{
//EXT_DEBUG_TRACE("UnitClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This()));

crc(LastDockedBuilding != nullptr ? LastDockedBuilding->Fetch_ID() : 0);
}
9 changes: 9 additions & 0 deletions src/extensions/unit/unitext.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include "footext.h"
#include "unit.h"
#include "building.h"


class DECLSPEC_UUID(UUID_UNIT_EXTENSION)
Expand Down Expand Up @@ -60,4 +61,12 @@ UnitClassExtension final : public FootClassExtension
virtual RTTIType What_Am_I() const override { return RTTI_UNIT; }

public:
/**
* #issue-203
*
* The building that this unit last docked with.
* Used by harvesters for considering the distance to their last refinery
* when picking a tiberium cell to harvest from.
*/
BuildingClass *LastDockedBuilding;
};

0 comments on commit e478322

Please sign in to comment.