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

Improves the harvester AI. #934

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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;
};
13 changes: 12 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 @@ -150,6 +155,10 @@ int UnitClassExtension::Size_Of() const
void UnitClassExtension::Detach(TARGET target, bool all)
{
//EXT_DEBUG_TRACE("UnitClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This()));

if (LastDockedBuilding == target) {
LastDockedBuilding = nullptr;
}
}


Expand All @@ -161,4 +170,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;
};