Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/game/iw4/mp_tu6/components/patches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ void DisableDvarProtection()
// Cheat-protected
// .text:8230D6EC b __restgprlr_27
*(volatile uint32_t *)0x8230D6EC = 0x60000000;

// default migration_dvarErrors off to prevent console spam
*(volatile uint8_t *)0x822828E7 = 0x0;

// default loc_warnings off to prevent console spam
*(volatile uint8_t *)0x822CBDEB = 0x0;
}

patches::patches()
Expand Down
35 changes: 33 additions & 2 deletions src/game/iw4/mp_tu6/components/sv_bots.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct BotMovementInfo_t
bool active;
int buttons;
unsigned short weapon;
unsigned short primaryWeaponForAlt;
bool has_move;
char forwardmove;
char rightmove;
Expand Down Expand Up @@ -56,7 +57,32 @@ static Detour G_SelectWeaponIndex_Detour;
static int *G_SelectWeaponIndex_Hook(int clientNum, int iWeaponIndex)
{
if (clientNum >= 0 && clientNum < IW4_MAX_CLIENTS)
{
g_botai[clientNum].weapon = static_cast<unsigned short>(iWeaponIndex);
g_botai[clientNum].primaryWeaponForAlt = 0;

const WeaponCompleteDef *def = BG_GetWeaponCompleteDef(iWeaponIndex);

if (def && def->weapDef->inventoryType == WEAPINVENTORY_ALTMODE)
{
const playerState_s *ps = &g_entities[clientNum].client->ps;
const int numWeaps = BG_GetNumWeapons();

for (auto i = 1; i < numWeaps; i++)
{
if (!BG_PlayerHasWeapon(ps, i))
continue;

const WeaponCompleteDef *thisDef = BG_GetWeaponCompleteDef(i);

if (!thisDef || thisDef->altWeaponIndex != iWeaponIndex)
continue;

g_botai[clientNum].primaryWeaponForAlt = static_cast<unsigned short>(i);
break;
}
}
}

return G_SelectWeaponIndex_Detour.GetOriginal<G_SelectWeaponIndex_t>()(clientNum, iWeaponIndex);
}
Expand Down Expand Up @@ -90,7 +116,9 @@ static void SV_BotUserMove_Stub(client_t *cl)
? g_botai[clientNum].weapon
: static_cast<unsigned short>(level->clients[clientNum].ps.weapCommon.weapon);
cmd.primaryWeaponForAltMode =
static_cast<unsigned short>(level->clients[clientNum].ps.weapCommon.primaryWeaponForAltMode);
g_botai[clientNum].primaryWeaponForAlt
? g_botai[clientNum].primaryWeaponForAlt
: static_cast<unsigned short>(level->clients[clientNum].ps.weapCommon.primaryWeaponForAltMode);
cmd.offHandIndex = static_cast<unsigned short>(level->clients[clientNum].ps.weapCommon.offHandIndex);
cmd.forwardmove = g_botai[clientNum].has_move ? g_botai[clientNum].forwardmove : 0;
cmd.rightmove = g_botai[clientNum].has_move ? g_botai[clientNum].rightmove : 0;
Expand Down Expand Up @@ -278,7 +306,7 @@ static void PlayerCmd_BotMeleeParams(scr_entref_t entref)
Scr_Error("Usage: <bot> botMeleeParams(<yaw>, <dist>);");

const float yaw = static_cast<float>(Scr_GetFloat(0));
const int dist = Scr_GetInt(1);
const int dist = static_cast<int>(static_cast<float>(Scr_GetFloat(1)));

g_botai[entref.entnum].melee_charge_yaw = yaw;
g_botai[entref.entnum].melee_charge_dist = ClampByte(dist);
Expand Down Expand Up @@ -332,6 +360,9 @@ SVBots::SVBots()
SV_CalcPings_Detour = Detour(SV_CalcPings, SV_CalcPings_Hook);
SV_CalcPings_Detour.Install();

// remove bot check inside of Player_ActivateHoldCmd
*(volatile uint32_t *)0x82263658 = 0x60000000;

Scr_AddFunction("addtestclient", GScr_AddTestClient, BUILTIN_ANY);

Scr_AddMethod("botaction", PlayerCmd_BotAction, BUILTIN_ANY);
Expand Down
28 changes: 28 additions & 0 deletions src/game/iw4/mp_tu6/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,34 @@ static_assert(offsetof(level_locals_t, gentities) == 0x4, "");
static_assert(offsetof(level_locals_t, num_entities) == 0x8, "");
static_assert(offsetof(level_locals_t, maxclients) == 0x3A4, "");

enum weapInventoryType_t
{
WEAPINVENTORY_PRIMARY = 0x0,
WEAPINVENTORY_OFFHAND = 0x1,
WEAPINVENTORY_ITEM = 0x2,
WEAPINVENTORY_ALTMODE = 0x3,
WEAPINVENTORY_EXCLUSIVE = 0x4,
WEAPINVENTORY_SCAVENGER = 0x5,
WEAPINVENTORYCOUNT = 0x6,
};

struct WeaponDef
{
char pad[0x38];
weapInventoryType_t inventoryType;
};
static_assert(offsetof(WeaponDef, inventoryType) == 0x38, "");

struct WeaponCompleteDef
{
const char *szInternalName;
WeaponDef *weapDef;
char pad[0x38];
int altWeaponIndex;
};
static_assert(offsetof(WeaponCompleteDef, weapDef) == 0x4, "");
static_assert(offsetof(WeaponCompleteDef, altWeaponIndex) == 0x40, "");

struct weaponParms
{
float forward[3];
Expand Down
9 changes: 9 additions & 0 deletions src/game/iw4/mp_tu6/symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,15 @@ typedef void (*BG_CalculateViewMovement_Angles_Idle_t)(viewState_t *vs, float *a
static BG_CalculateViewMovement_Angles_Idle_t BG_CalculateViewMovement_Angles_Idle =
reinterpret_cast<BG_CalculateViewMovement_Angles_Idle_t>(0x82118198);

typedef WeaponCompleteDef *(*BG_GetWeaponCompleteDef_t)(unsigned int weaponIndex);
static BG_GetWeaponCompleteDef_t BG_GetWeaponCompleteDef = reinterpret_cast<BG_GetWeaponCompleteDef_t>(0x821142C0);

typedef int (*BG_GetNumWeapons_t)();
static BG_GetNumWeapons_t BG_GetNumWeapons = reinterpret_cast<BG_GetNumWeapons_t>(0x821143F0);

typedef bool (*BG_PlayerHasWeapon_t)(const playerState_s *ps, unsigned int weaponIndex);
static BG_PlayerHasWeapon_t BG_PlayerHasWeapon = reinterpret_cast<BG_PlayerHasWeapon_t>(0x820FE5F0);

static auto Weapon_RocketLauncher_Fire =
reinterpret_cast<gentity_s *(*)(gentity_s * ent, unsigned int weaponIndex, double spread, weaponParms *wp,
weaponParms *gunVel, struct lockonFireParms *lockParms,
Expand Down