-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathCheats.cpp
More file actions
672 lines (567 loc) · 25.3 KB
/
Copy pathCheats.cpp
File metadata and controls
672 lines (567 loc) · 25.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
#include "Cheats.hpp"
#include "Event.hpp"
#include "Features/AutoSubmit.hpp"
#include "Features/Cvars.hpp"
#include "Features/Hud/Hud.hpp"
#include "Features/Hud/InspectionHud.hpp"
#include "Features/Hud/SpeedrunHud.hpp"
#include "Features/Listener.hpp"
#include "Features/OverlayRender.hpp"
#include "Features/ReloadedFix.hpp"
#include "Features/Routing/EntityInspector.hpp"
#include "Features/Speedrun/SpeedrunTimer.hpp"
#include "Features/Tas/TasParser.hpp"
#include "Features/Tas/TasTools/JumpTool.hpp"
#include "Features/Tas/TasTools/StrafeTool.hpp"
#include "Features/Timer/Timer.hpp"
#include "Features/WorkshopList.hpp"
#include "Game.hpp"
#include "Modules/Client.hpp"
#include "Modules/Console.hpp"
#include "Modules/Engine.hpp"
#include "Modules/Server.hpp"
#include "Offsets.hpp"
#include <cstring>
Variable sar_autorecord("sar_autorecord", "0", -1, 1, "Enables or disables automatic demo recording.\n");
Variable sar_autojump("sar_autojump", "0", "Enables automatic jumping on the server.\n");
Variable sar_autostrafe("sar_autostrafe", "0", "Automatically strafes in your current wishdir.\n");
Variable sar_ensure_slope_boost("sar_ensure_slope_boost", "0", "Ensures a successful slope boost.\n");
Variable sar_jumpboost("sar_jumpboost", "0", 0,
"Enables special game movement on the server.\n"
"0 = Default,\n"
"1 = Orange Box Engine,\n"
"2 = Pre-OBE.\n");
Variable sar_aircontrol("sar_aircontrol", "0", 0, 2, "Enables more air-control on the server.\n");
Variable sar_duckjump("sar_duckjump", "0", "Allows duck-jumping even when fully crouched, similar to prevent_crouch_jump.\n");
Variable sar_disable_challenge_stats_hud("sar_disable_challenge_stats_hud", "0", -1, "Disables opening the challenge mode stats HUD. Greater than 1 specifies a custom amount of ticks to leave leaderboard open. -1 closes instantly.\n");
Variable sar_disable_challenge_stats_hud_partner("sar_disable_challenge_stats_hud_partner", "1", "Closes the challenge mode stats HUD after your coop partner does.\n");
Variable sar_disable_steam_pause("sar_disable_steam_pause", "0", "Prevents pauses from steam overlay.\n");
Variable sar_disable_no_focus_sleep("sar_disable_no_focus_sleep", "0", "Does not yield the CPU when game is not focused.\n");
Variable sar_disable_progress_bar_update("sar_disable_progress_bar_update", "0", 0, 2, "Disables excessive usage of progress bar.\n");
Variable sar_prevent_mat_snapshot_recompute("sar_prevent_mat_snapshot_recompute", "0", "Shortens loading times by preventing state snapshot recomputation.\n");
Variable sar_challenge_autostop("sar_challenge_autostop", "0", 0, 3, "Automatically stops recording demos when the leaderboard opens after a CM run. If 2, automatically appends the run time to the demo name.\n");
Variable sar_show_entinp("sar_show_entinp", "0", "Print all entity inputs to console.\n");
Variable sar_force_qc("sar_force_qc", "0", 0, 1, "When ducking, forces view offset to always be at standing height. Requires sv_cheats to work.\n");
Variable sar_patch_bhop("sar_patch_bhop", "0", 0, 1, "Patches bhop by limiting wish direction if your velocity is too high.\n");
Variable sar_patch_cfg("sar_patch_cfg", "0", 0, 1, "Patches Crouch Flying Glitch.\n");
Variable sar_prevent_ehm("sar_prevent_ehm", "0", 0, 1, "Prevents Entity Handle Misinterpretation (EHM) from happening.\n");
Variable sar_disable_weapon_sway("sar_disable_weapon_sway", "0", 0, 1, "Disables the viewmodel lagging behind.\n");
Variable sar_disable_viewmodel_shadows("sar_disable_viewmodel_shadows", "0", 0, 1, "Disables the shadows on the viewmodel.\n");
Variable sar_floor_reportals("sar_floor_reportals", "0", "Toggles floor reportals. Requires cheats.\n", FCVAR_CHEAT);
Variable sar_loads_coop_dots("sar_loads_coop_dots", "0", "Toggles the loading screen dots during map transitions in coop.\n");
Variable sar_disable_autograb("sar_disable_autograb", "0", 0, 1, "Disables the auto-grab in coop. Requires host to enable it for everyone that also enables it.\n");
Variable sar_force_enable_paint_in_map("sar_force_enable_paint_in_map", "0", 0, 1, "Forces paint to be enabled on next map load.\n");
Variable sv_laser_cube_autoaim;
Variable ui_loadingscreen_transition_time;
Variable ui_loadingscreen_fadein_time;
Variable ui_loadingscreen_mintransition_time;
Variable ui_transition_effect;
Variable ui_transition_time;
Variable ui_pvplobby_show_offline;
Variable mm_session_sys_delay_create_host;
Variable hide_gun_when_holding;
Variable r_flashlightbrightness;
// TSP only
void IN_BhopDown(const CCommand& args) {
if (!client->KeyDown || !client->in_jump) return;
client->KeyDown(client->in_jump, (args.ArgC() > 1) ? args[1] : nullptr);
}
void IN_BhopUp(const CCommand& args) {
if (!client->KeyUp || !client->in_jump) return;
client->KeyUp(client->in_jump, (args.ArgC() > 1) ? args[1] : nullptr);
}
Command startbhop("+bhop", IN_BhopDown, "Client sends a key-down event for the in_jump state.\n");
Command endbhop("-bhop", IN_BhopUp, "Client sends a key-up event for the in_jump state.\n");
CON_COMMAND(sar_anti_anti_cheat, "sar_anti_anti_cheat - turns on cheats without the Narrator noticing\n") {
sv_cheats.ThisPtr()->m_nValue = 1;
}
// P2 only
CON_COMMAND(sar_togglewait, "sar_togglewait - enables or disables \"wait\" for the command buffer\n") {
auto state = !*engine->m_bWaitEnabled;
*engine->m_bWaitEnabled = *engine->m_bWaitEnabled2 = state;
console->Print("%s wait!\n", (state) ? "Enabled" : "Disabled");
}
CON_COMMAND(sar_autoaim_point, "sar_autoaim_point <x> <y> <z> - automatically aims at a point in space. Requires cheats\n") {
if (args.ArgC() != 4) {
return console->Print(sar_autoaim_point.ThisPtr()->m_pszHelpString);
}
if (!sv_cheats.GetBool()) {
return console->Print("sar_autoaim_point requires sv_cheats 1.\n");
}
auto player = client->GetPlayer(GET_SLOT() + 1);
if (!player) return;
Vector cam = client->GetAbsOrigin(player) + client->GetViewOffset(player) + client->GetPortalLocal(player).m_vEyeOffset;
Vector target = Vector(atof(args[1]), atof(args[2]), atof(args[3]));
Vector forward = target - cam;
float pitch = -atan2f(forward.z, forward.Length2D());
float yaw = atan2f(forward.y, forward.x);
pitch *= 180.0f / M_PI;
yaw *= 180.0f / M_PI;
engine->ExecuteCommand(Utils::ssprintf("setang %f %f\n", pitch, yaw).c_str());
}
CON_COMMAND(sar_delete_alias_cmds, "sar_delete_alias_cmds - deletes all alias commands\n") {
using _Cmd_Shutdown = int (*)();
static _Cmd_Shutdown Cmd_Shutdown = nullptr;
if (!Cmd_Shutdown) {
auto result = Memory::MultiScan(engine->Name(), Offsets::Cmd_ShutdownSig, Offsets::Cmd_ShutdownOff);
if (!result.empty()) {
for (auto const &addr : result) {
if (!std::strcmp(*reinterpret_cast<char **>(addr), "Cmd_Shutdown()")) {
Cmd_Shutdown = Memory::Read<_Cmd_Shutdown>(addr + Offsets::Cmd_ShutdownOff2);
break;
}
}
}
}
if (Cmd_Shutdown) {
Cmd_Shutdown();
} else {
console->Print("Unable to find Cmd_Shutdown() function!\n");
}
}
DECL_AUTO_COMMAND_COMPLETION(sar_fast_load_preset, ({"none", "sla", "normal", "full"}))
CON_COMMAND_F_COMPLETION(sar_fast_load_preset, "sar_fast_load_preset <preset> - sets all loading fixes to preset values\n", FCVAR_DONTRECORD, AUTOCOMPLETION_FUNCTION(sar_fast_load_preset)) {
if (args.ArgC() != 2) {
console->Print(sar_fast_load_preset.ThisPtr()->m_pszHelpString);
return;
}
const char *preset = args.Arg(1);
#define CMD(x) engine->ExecuteCommand(x)
if (!strcmp(preset, "none")) {
if (!Game::IsSpeedrunMod() && ui_loadingscreen_transition_time.ThisPtr()) {
CMD("ui_loadingscreen_transition_time 1.0");
CMD("ui_loadingscreen_fadein_time 1.0");
CMD("ui_loadingscreen_mintransition_time 0.5");
}
CMD("sar_disable_progress_bar_update 0");
CMD("sar_prevent_mat_snapshot_recompute 0");
CMD("sar_loads_uncap 0");
CMD("sar_loads_norender 0");
} else if (!strcmp(preset, "sla")) {
if (!Game::IsSpeedrunMod() && ui_loadingscreen_transition_time.ThisPtr()) {
CMD("ui_loadingscreen_transition_time 0.0");
CMD("ui_loadingscreen_fadein_time 0.0");
CMD("ui_loadingscreen_mintransition_time 0.0");
}
CMD("sar_disable_progress_bar_update 1");
CMD("sar_prevent_mat_snapshot_recompute 1");
CMD("sar_loads_uncap 0");
CMD("sar_loads_norender 0");
} else if (!strcmp(preset, "normal")) {
if (!Game::IsSpeedrunMod() && ui_loadingscreen_transition_time.ThisPtr()) {
CMD("ui_loadingscreen_transition_time 0.0");
CMD("ui_loadingscreen_fadein_time 0.0");
CMD("ui_loadingscreen_mintransition_time 0.0");
}
CMD("sar_disable_progress_bar_update 1");
CMD("sar_prevent_mat_snapshot_recompute 1");
CMD("sar_loads_uncap 1");
CMD("sar_loads_norender 0");
} else if (!strcmp(preset, "full")) {
if (!Game::IsSpeedrunMod() && ui_loadingscreen_transition_time.ThisPtr()) {
CMD("ui_loadingscreen_transition_time 0.0");
CMD("ui_loadingscreen_fadein_time 0.0");
CMD("ui_loadingscreen_mintransition_time 0.0");
}
CMD("sar_disable_progress_bar_update 2");
CMD("sar_prevent_mat_snapshot_recompute 1");
CMD("sar_loads_uncap 1");
CMD("sar_loads_norender 1");
} else {
console->Print("Unknown preset %s!\n", preset);
console->Print(sar_fast_load_preset.ThisPtr()->m_pszHelpString);
}
#undef CMD
}
CON_COMMAND(sar_clear_lines, "sar_clear_lines - clears all active drawline overlays\n") {
// So, hooking this would be really annoying, however Valve's code
// is dumb and bad and only allows 20 lines (after which it'll start
// overwriting old ones), so let's just draw 20 zero-length lines!
for (int i = 0; i < 20; ++i) {
engine->ExecuteCommand("drawline 0 0 0 0 0 0", true);
}
}
struct DrawLineInfo {
Vector start, end;
Color col;
};
static std::vector<DrawLineInfo> g_drawlines;
CON_COMMAND(sar_drawline, "sar_drawline <x> <y> <z> <x> <y> <z> [r] [g] [b] - overlay a line in the world\n") {
if (args.ArgC() != 7 && args.ArgC() != 10) {
return console->Print(sar_drawline.ThisPtr()->m_pszHelpString);
}
float x0 = atof(args[1]);
float y0 = atof(args[2]);
float z0 = atof(args[3]);
float x1 = atof(args[4]);
float y1 = atof(args[5]);
float z1 = atof(args[6]);
uint8_t r = 255;
uint8_t g = 255;
uint8_t b = 255;
if (args.ArgC() == 10) {
r = (uint8_t)atoi(args[7]);
g = (uint8_t)atoi(args[8]);
b = (uint8_t)atoi(args[9]);
}
g_drawlines.push_back({
{x0, y0, z0},
{x1, y1, z1},
{r, g, b},
});
}
CON_COMMAND(sar_drawline_clear, "sar_drawline_clear - clear all active sar_drawlines\n") {
g_drawlines.clear();
}
ON_EVENT(RENDER) {
if (!sv_cheats.GetBool()) return;
std::map<int, MeshId> meshes;
for (auto l : g_drawlines) {
int col_int = *(int *)&l.col;
if (meshes.count(col_int) == 0) {
meshes[col_int] = OverlayRender::createMesh(RenderCallback::none, RenderCallback::constant(l.col, true));
}
OverlayRender::addLine(meshes[col_int], l.start, l.end);
}
}
ON_EVENT(PRE_TICK) {
Cheats::CheckUICoopDots();
Cheats::CheckAutoGrab();
Cheats::CheckPaintInMap();
}
CON_COMMAND(sar_getpos, "sar_getpos [slot] [server|client] - get the absolute origin and angles of a particular player from either the server or client. Defaults to slot 0 and server.\n") {
if (args.ArgC() > 3) {
return console->Print(sar_getpos.ThisPtr()->m_pszHelpString);
}
bool use_serv = true;
if (args.ArgC() == 3) {
if (!strcmp(args[2], "client")) {
use_serv = false;
} else if (strcmp(args[2], "server")) {
return console->Print(sar_getpos.ThisPtr()->m_pszHelpString);
}
}
int slot = args.ArgC() >= 2 ? atoi(args[1]) : 0;
if (slot >= engine->GetMaxClients()) return console->Print("Could not get player at slot %d\n", slot);
Vector origin;
QAngle angles;
if (use_serv) {
void *player = server->GetPlayer(slot + 1);
if (!player) return console->Print("Could not get player at slot %d\n", slot);
origin = server->GetAbsOrigin(player);
angles = server->GetAbsAngles(player);
} else {
void *player = client->GetPlayer(slot + 1);
if (!player) return console->Print("Could not get player at slot %d\n", slot);
origin = client->GetAbsOrigin(player);
angles = client->GetAbsAngles(player);
}
console->Print("origin: %.6f %.6f %.6f\n", origin.x, origin.y, origin.z);
console->Print("angles: %.6f %.6f %.6f\n", angles.x, angles.y, angles.z);
}
CON_COMMAND(sar_geteyepos, "sar_geteyepos [slot] - get the view position (portal shooting origin) and view angles of a certain player.\n") {
if (args.ArgC() > 2) {
return console->Print(sar_geteyepos.ThisPtr()->m_pszHelpString);
}
int slot = args.ArgC() >= 2 ? atoi(args[1]) : 0;
if (slot >= engine->GetMaxClients()) return console->Print("Could not get player at slot %d\n", slot);
Vector eye;
QAngle angles;
void *player = server->GetPlayer(slot + 1);
if (!player) return console->Print("Could not get player at slot %d\n", slot);
eye = server->GetAbsOrigin(player) + server->GetViewOffset(player) + server->GetPortalLocal(player).m_vEyeOffset;
angles = engine->GetAngles(slot);
console->Print("eye: %.6f %.6f %.6f\n", eye.x, eye.y, eye.z);
console->Print("angles: %.6f %.6f %.6f\n", angles.x, angles.y, angles.z);
}
CON_COMMAND_F(sar_challenge_autosubmit_reload_api_key, "sar_challenge_autosubmit_reload_api_key - reload the boards API key from its file.\n", FCVAR_DONTRECORD) {
if (args.ArgC() != 1) {
return console->Print(sar_challenge_autosubmit_reload_api_key.ThisPtr()->m_pszHelpString);
}
AutoSubmit::LoadApiKey(true);
}
Memory::Patch *g_floorReportalPatch;
Memory::Patch *g_coopLoadingDotsPatch;
Memory::Patch *g_autoGrabPatchServer;
Memory::Patch *g_autoGrabPatchClient;
Memory::Patch *g_promoFlagsPatch;
Memory::Patch *g_forcePaintInMap;
void Cheats::Init() {
sv_laser_cube_autoaim = Variable("sv_laser_cube_autoaim");
ui_loadingscreen_transition_time = Variable("ui_loadingscreen_transition_time");
ui_loadingscreen_fadein_time = Variable("ui_loadingscreen_fadein_time");
ui_loadingscreen_mintransition_time = Variable("ui_loadingscreen_mintransition_time");
ui_transition_effect = Variable("ui_transition_effect");
ui_transition_time = Variable("ui_transition_time");
ui_pvplobby_show_offline = Variable("ui_pvplobby_show_offline");
mm_session_sys_delay_create_host = Variable("mm_session_sys_delay_create_host");
hide_gun_when_holding = Variable("hide_gun_when_holding");
r_flashlightbrightness = Variable("r_flashlightbrightness");
sar_disable_challenge_stats_hud.UniqueFor(SourceGame_Portal2);
sar_disable_challenge_stats_hud_partner.UniqueFor(SourceGame_Portal2);
sar_disable_weapon_sway.UniqueFor(SourceGame_Portal2);
sar_disable_viewmodel_shadows.UniqueFor(SourceGame_Portal2 | SourceGame_PortalStoriesMel | SourceGame_PortalReloaded);
startbhop.UniqueFor(SourceGame_StanleyParable);
endbhop.UniqueFor(SourceGame_StanleyParable);
sar_anti_anti_cheat.UniqueFor(SourceGame_StanleyParable);
// Thinking with Time Machine also has workshop support, but we don't support it yet
// | SourceGame_ThinkingWithTimeMachine
sar_workshop.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag);
sar_workshop_update.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag);
sar_workshop_list.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag);
sar_workshop_skip.UniqueFor(SourceGame_Portal2 | SourceGame_ApertureTag);
sar_fix_reloaded_cheats.UniqueFor(SourceGame_PortalReloaded);
cvars->Unlock();
if (sar.game->Is(SourceGame_PortalStoriesMel)) {
Variable("give_portalgun").RemoveFlag(FCVAR_CHEAT);
Variable("setmodel").RemoveFlag(FCVAR_CHEAT);
Variable("upgrade_portalgun").RemoveFlag(FCVAR_CHEAT);
}
g_floorReportalPatch = new Memory::Patch();
auto floorReportalBranch = Memory::Scan(MODULE("server"), Offsets::FloorReportalBranch);
if (floorReportalBranch) {
unsigned char floorReportalBranchByte = 0x70;
g_floorReportalPatch->Execute(floorReportalBranch, &floorReportalBranchByte, 1);
g_floorReportalPatch->Restore();
}
g_coopLoadingDotsPatch = new Memory::Patch();
auto coopLoadingDotsBool = Memory::Scan(MODULE("client"), Offsets::LoadingProgress__SetupControlStatesInstruction, Offsets::LoadingProgress__SetupControlStatesBoolOffset);
if (coopLoadingDotsBool) {
unsigned char coopLoadingDotsBoolByte = 0x1;
g_coopLoadingDotsPatch->Execute(coopLoadingDotsBool, &coopLoadingDotsBoolByte, 1);
g_coopLoadingDotsPatch->Restore();
}
g_autoGrabPatchServer = new Memory::Patch();
g_autoGrabPatchClient = new Memory::Patch();
auto autoGrabServerBranch = Memory::Scan(MODULE("server"), Offsets::CPortal_Player__PollForUseEntity_CheckMP);
auto autoGrabClientBranch = Memory::Scan(MODULE("client"), Offsets::CPortal_Player__PollForUseEntity_CheckMP); // Note: Same signature as the server.
if (autoGrabServerBranch && autoGrabClientBranch) {
unsigned char autoGrabBranchByte = 0xEB;
g_autoGrabPatchServer->Execute(autoGrabServerBranch, &autoGrabBranchByte, 1);
g_autoGrabPatchServer->Restore();
g_autoGrabPatchClient->Execute(autoGrabClientBranch, &autoGrabBranchByte, 1);
g_autoGrabPatchClient->Restore();
}
g_promoFlagsPatch = new Memory::Patch();
auto portal2PromoFlags = Memory::Scan(MODULE("server"), Offsets::Portal2PromoFlagsSig, Offsets::Portal2PromoFlagsOff);
if (portal2PromoFlags) {
unsigned char promoFlagsByte = 0x00;
g_promoFlagsPatch->Execute(Memory::Deref<uintptr_t>(portal2PromoFlags), &promoFlagsByte, 1); // Note: Has to be active before map loads.
g_promoFlagsPatch->Restore();
}
g_forcePaintInMap = new Memory::Patch();
auto paintInMapBool = Memory::Scan(MODULE("engine"), Offsets::CM_RegisterPaintMap_PaintCheck);
if (paintInMapBool) {
unsigned char forcePaintBytes[] = {0xB1, 0x01};
g_forcePaintInMap->Execute(paintInMapBool, forcePaintBytes, 2);
g_forcePaintInMap->Restore();
}
Variable::RegisterAll();
Command::RegisterAll();
}
void Cheats::Shutdown() {
if (cvars) cvars->Lock();
if (sar.game && sar.game->Is(SourceGame_PortalStoriesMel)) {
Variable("give_portalgun").AddFlag(FCVAR_CHEAT);
Variable("setmodel").AddFlag(FCVAR_CHEAT);
Variable("upgrade_portalgun").AddFlag(FCVAR_CHEAT);
}
Variable::UnregisterAll();
Command::UnregisterAll();
g_floorReportalPatch->Restore();
SAFE_DELETE(g_floorReportalPatch);
g_coopLoadingDotsPatch->Restore();
SAFE_DELETE(g_coopLoadingDotsPatch);
g_autoGrabPatchServer->Restore();
SAFE_DELETE(g_autoGrabPatchServer);
g_autoGrabPatchClient->Restore();
SAFE_DELETE(g_autoGrabPatchClient);
g_promoFlagsPatch->Restore();
SAFE_DELETE(g_promoFlagsPatch);
g_forcePaintInMap->Restore();
SAFE_DELETE(g_forcePaintInMap);
}
// FUN PATCHES :))))))
void Cheats::PatchBhop(int slot, void *player, CUserCmd *cmd) {
if (!server->AllowsMovementChanges() || !sar_patch_bhop.GetBool()) return;
TasPlayerInfo info = tasPlayer->GetPlayerInfo(slot, player, cmd);
float currVel = info.velocity.Length2D();
float predictVel = autoStrafeTool[info.slot].GetVelocityAfterMove(info, cmd->forwardmove, cmd->sidemove).Length2D();
float maxSpeed = autoStrafeTool[info.slot].GetMaxSpeed(info, Vector(0, 1));
if (maxSpeed == 0) return;
// player surpassed max speed through its own movement - limit wishdir
if (predictVel > maxSpeed && predictVel > currVel) {
float mult = (maxSpeed - currVel) / (predictVel - currVel);
mult = fminf(fmaxf(mult, 0.0f), 1.0f);
cmd->forwardmove *= mult;
cmd->sidemove *= mult;
}
}
ON_EVENT(PROCESS_MOVEMENT) {
if (!server->AllowsMovementChanges() || !sar_patch_cfg.GetBool()) return;
auto player = server->GetPlayer(event.slot + 1);
if (player == nullptr) return;
auto portalLocal = server->GetPortalLocal(player);
void *tbeamHandle = reinterpret_cast<void *>(portalLocal.m_hTractorBeam);
if (!tbeamHandle || (uint32_t)tbeamHandle == (unsigned)Offsets::INVALID_EHANDLE_INDEX) return;
for (int i = 0; i < 2; i++) {
int hitboxOffset = i == 0 ? Offsets::m_pShadowCrouch : Offsets::m_pShadowStand;
auto shadow = *reinterpret_cast<void **>((uintptr_t)player + hitboxOffset);
// WAKE UP YOU MORON YOU'RE RUINING MY FUNNELS ARGGHHH
Memory::VMT<void(__rescall *)(void *)>(shadow, Offsets::Wake)(shadow);
}
}
void Cheats::AutoStrafe(int slot, void *player, CUserCmd *cmd) {
if (!server->AllowsMovementChanges() || !sar_autostrafe.GetBool()) return;
if (cmd->forwardmove == 0 && cmd->sidemove == 0) return;
auto m_MoveType = SE(player)->field<char>("m_MoveType");
if (m_MoveType == MOVETYPE_NOCLIP) return;
TasPlayerInfo info = tasPlayer->GetPlayerInfo(slot, player, cmd);
float angle = Math::AngleNormalize(RAD2DEG(DEG2RAD(info.angles.y) + atan2(-cmd->sidemove, cmd->forwardmove)));
TasFramebulk fb;
tasPlayer->playbackInfo.slots[slot].header.version = MAX_SCRIPT_VERSION;
autoJumpTool[info.slot].SetParams(autoJumpTool[info.slot].ParseParams(std::vector<std::string>{sar_autojump.GetBool() && (cmd->buttons & IN_JUMP) ? "on" : "off"}));
autoStrafeTool[info.slot].SetParams(autoStrafeTool[info.slot].ParseParams(std::vector<std::string> {"vec", "max", std::to_string(angle) + "deg"}));
autoStrafeTool[info.slot].Apply(fb, info);
if (sar.game->Is(SourceGame_INFRA)) {
fb.moveAnalog.y *= 2;
}
tasPlayer->ApplyMoveAnalog(fb.moveAnalog, cmd);
}
void Cheats::EnsureSlopeBoost(const CHLMoveData *move, void *player, CGameTrace **tr) {
if ((*tr) == NULL) {
return;
}
if (!server->AllowsMovementChanges() || !sar_ensure_slope_boost.GetBool()) {
return;
}
Vector velocity = move->m_vecVelocity;
Vector hitNormal = (*tr)->plane.normal;
bool goingDown = velocity.z < 0;
bool isntAlreadyGrounded = !(SE(player)->ground_entity());
bool landedOnSlope = hitNormal.z < 1.0f;
bool wantsToSnapToGround = (*tr)->fraction >= 0.000001f;
bool boostingTowardsVelocity = hitNormal.x * velocity.x + hitNormal.y * velocity.y >= 0;
if (goingDown && isntAlreadyGrounded && landedOnSlope && wantsToSnapToGround && boostingTowardsVelocity) {
// Nulling out pointer by reference, so that it's passed in CGameMovement::SetGroundEntity,
// preventing being grounded on this call, letting the player to boost off slope
*tr = NULL;
}
}
void Cheats::CheckFloorReportals() {
bool enabled = sar_floor_reportals.GetBool();
if (enabled && (!g_floorReportalPatch || !g_floorReportalPatch->IsInit())) {
console->Print("sar_floor_reportals is not available.\n");
sar_floor_reportals.SetValue(0);
return;
}
if (!sv_cheats.GetBool() && enabled) {
console->Print("sar_floor_reportals requires sv_cheats 1.\n");
sar_floor_reportals.SetValue(0);
enabled = false;
}
if (enabled == g_floorReportalPatch->IsPatched()) {
return;
}
if (enabled) {
g_floorReportalPatch->Execute();
} else {
g_floorReportalPatch->Restore();
}
}
void Cheats::CheckUICoopDots() {
bool enabled = sar_loads_coop_dots.GetBool();
if (enabled && (!g_coopLoadingDotsPatch || !g_coopLoadingDotsPatch->IsInit())) {
console->Print("sar_loads_coop_dots is not available.\n");
sar_loads_coop_dots.SetValue(0);
return;
}
if (enabled == g_coopLoadingDotsPatch->IsPatched()) {
return;
}
if (enabled) {
g_coopLoadingDotsPatch->Execute();
} else {
g_coopLoadingDotsPatch->Restore();
}
}
void Cheats::CheckAutoGrab() {
bool enabled = sar_disable_autograb.GetBool();
if (enabled && (!g_autoGrabPatchServer || !g_autoGrabPatchServer->IsInit())) {
console->Print("sar_disable_autograb is not available (Server).\n");
sar_disable_autograb.SetValue(0);
return;
}
if (enabled && (!g_autoGrabPatchClient || !g_autoGrabPatchClient->IsInit())) {
console->Print("sar_disable_autograb is not available (Client).\n");
sar_disable_autograb.SetValue(0);
return;
}
if (!sv_cheats.GetBool() && enabled) {
console->Print("sar_disable_autograb requires sv_cheats 1.\n");
sar_disable_autograb.SetValue(0);
enabled = false;
}
if (enabled == g_autoGrabPatchServer->IsPatched() && enabled == g_autoGrabPatchClient->IsPatched()) {
return;
}
if (enabled) {
g_autoGrabPatchServer->Execute();
g_autoGrabPatchClient->Execute();
} else {
g_autoGrabPatchServer->Restore();
g_autoGrabPatchClient->Restore();
}
}
DECL_AUTO_COMMAND_COMPLETION(sar_set_promo_items_state, ({"skins", "helmet", "antenna"})) // TODO: Add support for autofilling multiple args.
CON_COMMAND_F_COMPLETION(sar_set_promo_items_state, "sar_set_promo_items_state <off|all|skins|helmet|antenna>... - enables coop promotional items on spawn.\n", FCVAR_CHEAT, AUTOCOMPLETION_FUNCTION(sar_set_promo_items_state)) {
if (!g_promoFlagsPatch || !g_promoFlagsPatch->IsInit()) {
return console->Print("sar_set_promo_items_state is not available.\n");
}
if (args.ArgC() < 2) {
return console->Print(sar_set_promo_items_state.ThisPtr()->m_pszHelpString);
}
unsigned char targetFlags = 0;
for (int i = 1; i < args.ArgC(); i++) {
if (strcasecmp(args[i], "off") == 0) {
g_promoFlagsPatch->Restore();
return;
}
if (strcasecmp(args[i], "all") == 0) {
targetFlags = 0b111;
break;
}
if (strcasecmp(args[i], "skins") == 0) {;
targetFlags |= 0b001;
} else if (strcasecmp(args[i], "helmet") == 0) {
targetFlags |= 0b010;
} else if (strcasecmp(args[i], "antenna") == 0) {
targetFlags |= 0b100;
} else {
return console->Print(sar_set_promo_items_state.ThisPtr()->m_pszHelpString);
}
}
g_promoFlagsPatch->Restore();
g_promoFlagsPatch->Execute(&targetFlags, 1);
}
void Cheats::CheckPaintInMap() {
bool enabled = sar_force_enable_paint_in_map.GetBool();
if (enabled && (!g_forcePaintInMap || !g_forcePaintInMap->IsInit())) {
console->Print("sar_force_enable_paint_in_map is not available.\n");
sar_force_enable_paint_in_map.SetValue(0);
return;
}
if (!sv_cheats.GetBool() && enabled) {
console->Print("sar_force_enable_paint_in_map requires sv_cheats 1.\n");
sar_force_enable_paint_in_map.SetValue(0);
enabled = false;
}
if (enabled == g_forcePaintInMap->IsPatched()) {
return;
}
if (enabled) {
g_forcePaintInMap->Execute();
} else {
g_forcePaintInMap->Restore();
}
}