Open
Description
Units and Buildings can be grouped together by using the SHIFT key feature. SHIFT allows to add units and buildings to existing groups. This can be exploited with game breaking consequences in the game. It is critical issue. GenTool fixes this bug by doing the following:
For game.dat
Inject code at address 0x616031
taking 6 bytes and call naked function.
esi
register contains team number that is about to be used for grouping.
// The Group Selection Logic must be changed
// By default it is possible to combine any groups by using Shift key
// We must remove the possibility to select a building group with Shift:
//////////////////////////////////////////////////////////////////////////////////////
DWORD ccAddTeamInUIRet;
uint32 ccTeamNumber2;
__declspec(naked) void CC_AddTeamInUI_ZH()
{
__asm pop [ccAddTeamInUIRet]
__asm mov ccTeamNumber2,esi
__asm ADD ESI,0x402
__asm pushad
CGameAccess::Instance.PreventInvalidGrouping(ccTeamNumber2);
__asm popad
__asm push [ccAddTeamInUIRet]
__asm ret
}
Here is high level code of logic to prevent invalid grouping.
- Get the local player
- Get the group list of player by the given team number from
esi
- If the first object in the group list is a building, deselect all units
- If the current selected object is a building, deselect all units
Note that point 4 is already done in Zero Hour, but not in Generals. The code responsible must be around address 0x616031
, so when reversing the function, it can also be fixed right there more elegantly than in the example below.
void CGameAccess::PreventInvalidGrouping(uint32 teamNumber)
{
DWORD building = 0;
TPlayer player = 0;
if (teamNumber < 10 && Hack_GetLocalPlayer(player) && player != 0)
{
TGroupList groupList;
if (Hack_GetGroupList(player, teamNumber, groupList))
{
CGameArray<TGroupObject> groupObjectArray(0, 0);
Hack_GetGroupObjectArray(groupList, groupObjectArray);
if (TGroupObject* pFirstGroupObject = groupObjectArray.get(0))
{
TObject object = 0;
Hack_GetObjectFromGroupObject(*pFirstGroupObject, object);
Hack_GetBuildingHandle(object, building);
}
}
}
const bool selectsToBuilding = building != 0;
const bool selectsFromBuilding = IsGenerals() && Hack_IsBuildingSelected(); // Is already fixed in Zero Hour
if (selectsToBuilding || selectsFromBuilding)
{
Hack_SelectUnit(0);
}
}