Skip to content

Commit

Permalink
Implements harvester refinery queue jumping. Vinifera-Developers#202
Browse files Browse the repository at this point in the history
  • Loading branch information
Rampastring committed Dec 17, 2021
1 parent e3dc40e commit 0509979
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 1 deletion.
135 changes: 135 additions & 0 deletions src/extensions/building/buildingext_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@
#include "buildingtypeext.h"
#include "technotype.h"
#include "technotypeext.h"
#include "unit.h"
#include "unitext.h"
#include "house.h"
#include "housetype.h"
#include "cargo.h"
#include "dsurface.h"
#include "convert.h"
#include "drawshape.h"
#include "rules.h"
#include "rulesext.h"
#include "voc.h"
#include "iomap.h"
#include "fatal.h"
Expand Down Expand Up @@ -442,6 +446,135 @@ DECLARE_PATCH(_BuildingClass_Draw_Spied_Cameo_Palette_Patch)
}


/**
* #issue-202
*
* For harvester queue jumping.
* Don't return RADIO_NEGATIVE if a refinery is already in radio contact
* with a unit that is different from the one that sent us the message.
*
* @author: Rampastring
*/
DECLARE_PATCH(_BuildingClass_Receive_Message_Harvester_Queue_Jump_No_Ignoring_If_In_Contact_Patch)
{
GET_REGISTER_STATIC(BuildingClass*, building, esi);

if (building->Class->IsRefinery) {
goto skip_returning_negative;
}

/**
* We're not a refinery, don't skip the check.
*/
goto original_behaviour;


/**
* Skip the (!ScenarioInit && In_Radio_Contact()) and following (Contact_With_Whom() != from)
* condition and related code for the refinery and continue function
* execution from beyond that point.
*/
skip_returning_negative:
JMP(0x0042697B);


/**
* Stolen bytes / code, perform the check.
*/
original_behaviour:
if (ScenarioInit) {
JMP(0x00426962);
}

JMP(0x00426953);
}


/**
* #issue-202
*
* For harvester queue jumping.
* If we're a refinery and the harvester contacting us is closer to us than a
* potentially existing harvester heading towards us, allow the new harvester
* to take priority and tell the old harvester to go do something else.
*
* @author: Rampastring
*/
DECLARE_PATCH(_BuildingClass_Receive_Message_Harvester_Queue_Jump_Allow_Replacing_Old_Harv_If_Closer_Patch)
{
GET_REGISTER_STATIC(BuildingClass*, building, esi);
GET_REGISTER_STATIC(TechnoClass*, message_sender, edi);
static int queue_jump_distance;
static int old_harvester_distance;
static int new_harvester_distance;
static TechnoClass* old_harvester;

if (ScenarioInit) {
/**
* Stolen bytes / code, return RADIO_ROGER if ScenarioInit is set.
*/
return_roger_scenarioinit:
JMP(0x0042707B);
}


if (building->Cargo.Is_Something_Attached()) {

/**
* We're not free (perhaps a harvester is unloading), return RADIO_STATIC.
*/
return_static:
_asm { mov eax, [RADIO_STATIC] }
JMP_REG(ecx, 0x004271CA);
}

/**
* Check if we're already in radio contact with another harvester
* than the one that sent us the message.
* If not, we can simply accept the new harvester.
*/
old_harvester = building->Contact_With_Whom();

if (old_harvester != nullptr && old_harvester != message_sender) {

/**
* Get distance to the old harvester and distance
* to the new harvester and compare the distances.
*/
old_harvester_distance = building->Distance(old_harvester);
new_harvester_distance = building->Distance(message_sender);

queue_jump_distance = 7;
if (RulesExtension) {
queue_jump_distance = RulesExtension->MinHarvesterQueueJumpDistance;
}

if (new_harvester_distance + Cell_To_Lepton(queue_jump_distance) > old_harvester_distance) {

/**
* The new harvester is not significantly closer to us than the old one,
* exit the function and return RADIO_NEGATIVE.
*/
return_negative:
JMP(0x0042696C);
}

/**
* The harvester that sent us the message is significantly closer to us than
* our old assigned harvester. Tell the old harvester to figure out a new
* purpose for their life and accept the new harvester by returning RADIO_ROGER.
*/
building->Transmit_Message(RADIO_OVER_OUT, old_harvester);
}

/**
* Exits the function and returns RADIO_ROGER.
*/
return_roger:
JMP(0x004269BD);
}


/**
* Main function for patching the hooks.
*/
Expand All @@ -459,4 +592,6 @@ 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(0x0042694A, &_BuildingClass_Receive_Message_Harvester_Queue_Jump_No_Ignoring_If_In_Contact_Patch);
Patch_Jump(0x00426A71, &_BuildingClass_Receive_Message_Harvester_Queue_Jump_Allow_Replacing_Old_Harv_If_Closer_Patch);
}
59 changes: 59 additions & 0 deletions src/extensions/foot/footext_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@
*
******************************************************************************/
#include "footext_hooks.h"
#include "footext_functions.h"
#include "foot.h"
#include "technotype.h"
#include "technotypeext.h"
#include "fatal.h"
#include "asserthandler.h"
#include "debughandler.h"
#include "unit.h"
#include "unittype.h"

#include "hooker.h"
#include "hooker_macros.h"
Expand Down Expand Up @@ -172,6 +175,61 @@ DECLARE_PATCH(_FootClass_Death_Announcement_IsInsignifcant_Patch)
}


/**
* #issue-202
*
* For harvester queue jumping.
* Make harvesters seek for a new refinery to unload into when their
* existing refinery has dumped them for a different harvester.
*
* @author: Rampastring
*/
DECLARE_PATCH(_FootClass_Mission_Enter_Seek_New_Refinery_After_Dropped)
{
GET_REGISTER_STATIC(FootClass *, this_ptr, esi);
static UnitTypeClass* unittype;

/**
* Check if we're a harvester.
*/

if (this_ptr->What_Am_I() != RTTI_UNIT) {

/**
* We're not a unit and so we can't be a harvester, don't change original behaviour.
*/
goto original_code;
}

unittype = reinterpret_cast<UnitClass*>(this_ptr)->Class;

if (!unittype->IsToHarvest && !unittype->IsToVeinHarvest) {

/**
* We're not a harvester, don't change original behaviour.
*/
goto original_code;
}

/**
* We're a harvester, try to find a new refinery instead of going idle.
*/
this_ptr->Assign_Mission(MISSION_HARVEST);
goto commence_mission;

/**
* Put the object into idle mode and continue on to commencing the mission.
*/
original_code:
this_ptr->Enter_Idle_Mode(false, true);

/**
* Commences the given mission and exits the function afterwards.
*/
commence_mission:
JMP(0x004A49B1);
}

/**
* Main function for patching the hooks.
*/
Expand All @@ -180,4 +238,5 @@ void FootClassExtension_Hooks()
Patch_Jump(0x004A4D60, &_FootClass_Death_Announcement_IsInsignifcant_Patch);
Patch_Jump(0x004A6866, &_FootClass_Is_Allowed_To_Recloak_Cloak_Stop_BugFix_Patch);
Patch_Jump(0x004A59E1, &_FootClass_AI_IdleRate_Patch);
Patch_Jump(0x004A49A3, &_FootClass_Mission_Enter_Seek_New_Refinery_After_Dropped);
}
5 changes: 4 additions & 1 deletion src/extensions/rules/rulesext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ RulesClassExtension::RulesClassExtension(RulesClass *this_ptr) :
IsMPAutoDeployMCV(false),
IsMPPrePlacedConYards(false),
IsBuildOffAlly(true),
MaxFreeRefineryDistanceBias(16)
MaxFreeRefineryDistanceBias(16),
MinHarvesterQueueJumpDistance(7)
{
ASSERT(ThisPtr != nullptr);
//EXT_DEBUG_TRACE("RulesClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr));
Expand Down Expand Up @@ -164,6 +165,7 @@ void RulesClassExtension::Compute_CRC(WWCRCEngine &crc) const
crc(IsMPPrePlacedConYards);
crc(IsBuildOffAlly);
crc(MaxFreeRefineryDistanceBias);
crc(MinHarvesterQueueJumpDistance);
}


Expand Down Expand Up @@ -209,6 +211,7 @@ bool RulesClassExtension::General(CCINIClass &ini)
}

MaxFreeRefineryDistanceBias = ini.Get_Int(GENERAL, "MaxFreeRefineryDistanceBias", MaxFreeRefineryDistanceBias);
MinHarvesterQueueJumpDistance = ini.Get_Int(GENERAL, "MinHarvesterQueueJumpDistance", MinHarvesterQueueJumpDistance);

return true;
}
Expand Down
8 changes: 8 additions & 0 deletions src/extensions/rules/rulesext.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ class RulesClassExtension final : public Extension<RulesClass>
* difference in cells is less than this.
*/
int MaxFreeRefineryDistanceBias;

/**
* If a refinery is already occupied by a returning harvester and another
* harvester is also looking to dock, allow the new harvester to take over
* the refinery if the difference in distance to the refinery between
* the existing harvester and the new harvester is at least this many cells.
*/
int MinHarvesterQueueJumpDistance;
};


Expand Down

0 comments on commit 0509979

Please sign in to comment.