1/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
2#include "gamecontext.h"
3
4#include <engine/antibot.h>
5#include <engine/shared/config.h>
6
7#include <game/server/entities/character.h>
8#include <game/server/gamemodes/DDRace.h>
9#include <game/server/player.h>
10#include <game/server/save.h>
11#include <game/server/teams.h>
12
13void CGameContext::ConGoLeft(IConsole::IResult *pResult, void *pUserData)
14{
15 CGameContext *pSelf = (CGameContext *)pUserData;
16 int Tiles = pResult->NumArguments() == 1 ? pResult->GetInteger(Index: 0) : 1;
17
18 if(!CheckClientId(ClientId: pResult->m_ClientId))
19 return;
20 pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: -1 * Tiles, Y: 0);
21}
22
23void CGameContext::ConGoRight(IConsole::IResult *pResult, void *pUserData)
24{
25 CGameContext *pSelf = (CGameContext *)pUserData;
26 int Tiles = pResult->NumArguments() == 1 ? pResult->GetInteger(Index: 0) : 1;
27
28 if(!CheckClientId(ClientId: pResult->m_ClientId))
29 return;
30 pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: Tiles, Y: 0);
31}
32
33void CGameContext::ConGoDown(IConsole::IResult *pResult, void *pUserData)
34{
35 CGameContext *pSelf = (CGameContext *)pUserData;
36 int Tiles = pResult->NumArguments() == 1 ? pResult->GetInteger(Index: 0) : 1;
37
38 if(!CheckClientId(ClientId: pResult->m_ClientId))
39 return;
40 pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: 0, Y: Tiles);
41}
42
43void CGameContext::ConGoUp(IConsole::IResult *pResult, void *pUserData)
44{
45 CGameContext *pSelf = (CGameContext *)pUserData;
46 int Tiles = pResult->NumArguments() == 1 ? pResult->GetInteger(Index: 0) : 1;
47
48 if(!CheckClientId(ClientId: pResult->m_ClientId))
49 return;
50 pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: 0, Y: -1 * Tiles);
51}
52
53void CGameContext::ConMove(IConsole::IResult *pResult, void *pUserData)
54{
55 CGameContext *pSelf = (CGameContext *)pUserData;
56 if(!CheckClientId(ClientId: pResult->m_ClientId))
57 return;
58 pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: pResult->GetInteger(Index: 0),
59 Y: pResult->GetInteger(Index: 1));
60}
61
62void CGameContext::ConMoveRaw(IConsole::IResult *pResult, void *pUserData)
63{
64 CGameContext *pSelf = (CGameContext *)pUserData;
65 if(!CheckClientId(ClientId: pResult->m_ClientId))
66 return;
67 pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: pResult->GetInteger(Index: 0),
68 Y: pResult->GetInteger(Index: 1), Raw: true);
69}
70
71void CGameContext::MoveCharacter(int ClientId, int X, int Y, bool Raw)
72{
73 CCharacter *pChr = GetPlayerChar(ClientId);
74
75 if(!pChr)
76 return;
77
78 pChr->Move(RelPos: vec2((Raw ? 1 : 32) * X, (Raw ? 1 : 32) * Y));
79 pChr->ResetVelocity();
80 pChr->m_DDRaceState = ERaceState::CHEATED;
81}
82
83void CGameContext::ConKillPlayer(IConsole::IResult *pResult, void *pUserData)
84{
85 CGameContext *pSelf = (CGameContext *)pUserData;
86 if(!CheckClientId(ClientId: pResult->m_ClientId))
87 return;
88 int Victim = pResult->GetVictim();
89
90 if(pSelf->m_apPlayers[Victim])
91 {
92 pSelf->m_apPlayers[Victim]->KillCharacter(Weapon: WEAPON_GAME);
93 char aBuf[512];
94 if(pResult->NumArguments() == 2)
95 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s was killed by authorized player (%s)",
96 pSelf->Server()->ClientName(ClientId: Victim),
97 pResult->GetString(Index: 1));
98 else
99 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s was killed by authorized player",
100 pSelf->Server()->ClientName(ClientId: Victim));
101 pSelf->SendChat(ClientId: -1, Team: TEAM_ALL, pText: aBuf);
102 }
103}
104
105void CGameContext::ConNinja(IConsole::IResult *pResult, void *pUserData)
106{
107 CGameContext *pSelf = (CGameContext *)pUserData;
108 pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_NINJA, Remove: false);
109}
110
111void CGameContext::ConUnNinja(IConsole::IResult *pResult, void *pUserData)
112{
113 CGameContext *pSelf = (CGameContext *)pUserData;
114 pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_NINJA, Remove: true);
115}
116
117void CGameContext::ConEndlessHook(IConsole::IResult *pResult, void *pUserData)
118{
119 CGameContext *pSelf = (CGameContext *)pUserData;
120 if(!CheckClientId(ClientId: pResult->m_ClientId))
121 return;
122 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
123 if(pChr)
124 {
125 pChr->SetEndlessHook(true);
126 }
127}
128
129void CGameContext::ConUnEndlessHook(IConsole::IResult *pResult, void *pUserData)
130{
131 CGameContext *pSelf = (CGameContext *)pUserData;
132 if(!CheckClientId(ClientId: pResult->m_ClientId))
133 return;
134 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
135 if(pChr)
136 {
137 pChr->SetEndlessHook(false);
138 }
139}
140
141void CGameContext::ConSuper(IConsole::IResult *pResult, void *pUserData)
142{
143 CGameContext *pSelf = (CGameContext *)pUserData;
144 if(!CheckClientId(ClientId: pResult->m_ClientId))
145 return;
146 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
147 if(pChr && !pChr->IsSuper())
148 {
149 pChr->SetSuper(true);
150 pChr->UnFreeze();
151 }
152}
153
154void CGameContext::ConUnSuper(IConsole::IResult *pResult, void *pUserData)
155{
156 CGameContext *pSelf = (CGameContext *)pUserData;
157 if(!CheckClientId(ClientId: pResult->m_ClientId))
158 return;
159 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
160 if(pChr && pChr->IsSuper())
161 {
162 pChr->SetSuper(false);
163 }
164}
165
166void CGameContext::ConToggleInvincible(IConsole::IResult *pResult, void *pUserData)
167{
168 CGameContext *pSelf = (CGameContext *)pUserData;
169 if(!CheckClientId(ClientId: pResult->m_ClientId))
170 return;
171 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
172 if(pChr)
173 pChr->SetInvincible(pResult->NumArguments() == 0 ? !pChr->Core()->m_Invincible : pResult->GetInteger(Index: 0));
174}
175
176void CGameContext::ConSolo(IConsole::IResult *pResult, void *pUserData)
177{
178 CGameContext *pSelf = (CGameContext *)pUserData;
179 if(!CheckClientId(ClientId: pResult->m_ClientId))
180 return;
181 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
182 if(pChr)
183 pChr->SetSolo(true);
184}
185
186void CGameContext::ConUnSolo(IConsole::IResult *pResult, void *pUserData)
187{
188 CGameContext *pSelf = (CGameContext *)pUserData;
189 if(!CheckClientId(ClientId: pResult->m_ClientId))
190 return;
191 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
192 if(pChr)
193 pChr->SetSolo(false);
194}
195
196void CGameContext::ConFreeze(IConsole::IResult *pResult, void *pUserData)
197{
198 CGameContext *pSelf = (CGameContext *)pUserData;
199 if(!CheckClientId(ClientId: pResult->m_ClientId))
200 return;
201 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
202 if(pChr)
203 pChr->Freeze();
204}
205
206void CGameContext::ConUnFreeze(IConsole::IResult *pResult, void *pUserData)
207{
208 CGameContext *pSelf = (CGameContext *)pUserData;
209 if(!CheckClientId(ClientId: pResult->m_ClientId))
210 return;
211 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
212 if(pChr)
213 pChr->UnFreeze();
214}
215
216void CGameContext::ConDeep(IConsole::IResult *pResult, void *pUserData)
217{
218 CGameContext *pSelf = (CGameContext *)pUserData;
219 if(!CheckClientId(ClientId: pResult->m_ClientId))
220 return;
221 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
222 if(pChr)
223 pChr->SetDeepFrozen(true);
224}
225
226void CGameContext::ConUnDeep(IConsole::IResult *pResult, void *pUserData)
227{
228 CGameContext *pSelf = (CGameContext *)pUserData;
229 if(!CheckClientId(ClientId: pResult->m_ClientId))
230 return;
231 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
232 if(pChr)
233 {
234 pChr->SetDeepFrozen(false);
235 pChr->UnFreeze();
236 }
237}
238
239void CGameContext::ConLiveFreeze(IConsole::IResult *pResult, void *pUserData)
240{
241 CGameContext *pSelf = (CGameContext *)pUserData;
242 if(!CheckClientId(ClientId: pResult->m_ClientId))
243 return;
244 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
245 if(pChr)
246 pChr->SetLiveFrozen(true);
247}
248
249void CGameContext::ConUnLiveFreeze(IConsole::IResult *pResult, void *pUserData)
250{
251 CGameContext *pSelf = (CGameContext *)pUserData;
252 if(!CheckClientId(ClientId: pResult->m_ClientId))
253 return;
254 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
255 if(pChr)
256 pChr->SetLiveFrozen(false);
257}
258
259void CGameContext::ConShotgun(IConsole::IResult *pResult, void *pUserData)
260{
261 CGameContext *pSelf = (CGameContext *)pUserData;
262 pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_SHOTGUN, Remove: false);
263}
264
265void CGameContext::ConGrenade(IConsole::IResult *pResult, void *pUserData)
266{
267 CGameContext *pSelf = (CGameContext *)pUserData;
268 pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_GRENADE, Remove: false);
269}
270
271void CGameContext::ConLaser(IConsole::IResult *pResult, void *pUserData)
272{
273 CGameContext *pSelf = (CGameContext *)pUserData;
274 pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_LASER, Remove: false);
275}
276
277void CGameContext::ConJetpack(IConsole::IResult *pResult, void *pUserData)
278{
279 CGameContext *pSelf = (CGameContext *)pUserData;
280 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
281 if(pChr)
282 pChr->SetJetpack(true);
283}
284
285void CGameContext::ConEndlessJump(IConsole::IResult *pResult, void *pUserData)
286{
287 CGameContext *pSelf = (CGameContext *)pUserData;
288 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
289 if(pChr)
290 pChr->SetEndlessJump(true);
291}
292
293void CGameContext::ConSetJumps(IConsole::IResult *pResult, void *pUserData)
294{
295 CGameContext *pSelf = (CGameContext *)pUserData;
296 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
297 if(pChr)
298 pChr->SetJumps(pResult->GetInteger(Index: 0));
299}
300
301void CGameContext::ConWeapons(IConsole::IResult *pResult, void *pUserData)
302{
303 CGameContext *pSelf = (CGameContext *)pUserData;
304 pSelf->ModifyWeapons(pResult, pUserData, Weapon: -1, Remove: false);
305}
306
307void CGameContext::ConUnShotgun(IConsole::IResult *pResult, void *pUserData)
308{
309 CGameContext *pSelf = (CGameContext *)pUserData;
310 pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_SHOTGUN, Remove: true);
311}
312
313void CGameContext::ConUnGrenade(IConsole::IResult *pResult, void *pUserData)
314{
315 CGameContext *pSelf = (CGameContext *)pUserData;
316 pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_GRENADE, Remove: true);
317}
318
319void CGameContext::ConUnLaser(IConsole::IResult *pResult, void *pUserData)
320{
321 CGameContext *pSelf = (CGameContext *)pUserData;
322 pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_LASER, Remove: true);
323}
324
325void CGameContext::ConUnJetpack(IConsole::IResult *pResult, void *pUserData)
326{
327 CGameContext *pSelf = (CGameContext *)pUserData;
328 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
329 if(pChr)
330 pChr->SetJetpack(false);
331}
332
333void CGameContext::ConUnEndlessJump(IConsole::IResult *pResult, void *pUserData)
334{
335 CGameContext *pSelf = (CGameContext *)pUserData;
336 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
337 if(pChr)
338 pChr->SetEndlessJump(false);
339}
340
341void CGameContext::ConUnWeapons(IConsole::IResult *pResult, void *pUserData)
342{
343 CGameContext *pSelf = (CGameContext *)pUserData;
344 pSelf->ModifyWeapons(pResult, pUserData, Weapon: -1, Remove: true);
345}
346
347void CGameContext::ConAddWeapon(IConsole::IResult *pResult, void *pUserData)
348{
349 CGameContext *pSelf = (CGameContext *)pUserData;
350 pSelf->ModifyWeapons(pResult, pUserData, Weapon: pResult->GetInteger(Index: 0), Remove: false);
351}
352
353void CGameContext::ConRemoveWeapon(IConsole::IResult *pResult, void *pUserData)
354{
355 CGameContext *pSelf = (CGameContext *)pUserData;
356 pSelf->ModifyWeapons(pResult, pUserData, Weapon: pResult->GetInteger(Index: 0), Remove: true);
357}
358
359void CGameContext::ModifyWeapons(IConsole::IResult *pResult, void *pUserData,
360 int Weapon, bool Remove)
361{
362 CGameContext *pSelf = (CGameContext *)pUserData;
363 CCharacter *pChr = GetPlayerChar(ClientId: pResult->m_ClientId);
364 if(!pChr)
365 return;
366
367 if(std::clamp(val: Weapon, lo: -1, hi: NUM_WEAPONS - 1) != Weapon)
368 {
369 pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "info",
370 pStr: "invalid weapon id");
371 return;
372 }
373
374 if(Weapon == -1)
375 {
376 pChr->GiveWeapon(Weapon: WEAPON_SHOTGUN, Remove);
377 pChr->GiveWeapon(Weapon: WEAPON_GRENADE, Remove);
378 pChr->GiveWeapon(Weapon: WEAPON_LASER, Remove);
379 }
380 else
381 {
382 pChr->GiveWeapon(Weapon, Remove);
383 }
384
385 pChr->m_DDRaceState = ERaceState::CHEATED;
386}
387
388void CGameContext::Teleport(CCharacter *pChr, vec2 Pos)
389{
390 pChr->SetPosition(Pos);
391 pChr->m_Pos = Pos;
392 pChr->m_PrevPos = Pos;
393 pChr->m_DDRaceState = ERaceState::CHEATED;
394}
395
396void CGameContext::ConToTeleporter(IConsole::IResult *pResult, void *pUserData)
397{
398 CGameContext *pSelf = (CGameContext *)pUserData;
399 unsigned int TeleTo = pResult->GetInteger(Index: 0);
400
401 if(!pSelf->Collision()->TeleOuts(Number: TeleTo - 1).empty())
402 {
403 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
404 if(pChr)
405 {
406 int TeleOut = pSelf->m_World.m_Core.RandomOr0(BelowThis: pSelf->Collision()->TeleOuts(Number: TeleTo - 1).size());
407 pSelf->Teleport(pChr, Pos: pSelf->Collision()->TeleOuts(Number: TeleTo - 1)[TeleOut]);
408 }
409 }
410}
411
412void CGameContext::ConToCheckTeleporter(IConsole::IResult *pResult, void *pUserData)
413{
414 CGameContext *pSelf = (CGameContext *)pUserData;
415 unsigned int TeleTo = pResult->GetInteger(Index: 0);
416
417 if(!pSelf->Collision()->TeleCheckOuts(Number: TeleTo - 1).empty())
418 {
419 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId);
420 if(pChr)
421 {
422 int TeleOut = pSelf->m_World.m_Core.RandomOr0(BelowThis: pSelf->Collision()->TeleCheckOuts(Number: TeleTo - 1).size());
423 pSelf->Teleport(pChr, Pos: pSelf->Collision()->TeleCheckOuts(Number: TeleTo - 1)[TeleOut]);
424 pChr->m_TeleCheckpoint = TeleTo;
425 }
426 }
427}
428
429void CGameContext::ConTeleport(IConsole::IResult *pResult, void *pUserData)
430{
431 CGameContext *pSelf = (CGameContext *)pUserData;
432 if(!CheckClientId(ClientId: pResult->m_ClientId))
433 return;
434 int Tele = pResult->NumArguments() == 2 ? pResult->GetInteger(Index: 0) : pResult->m_ClientId;
435 int TeleTo = pResult->NumArguments() ? pResult->GetInteger(Index: pResult->NumArguments() - 1) : pResult->m_ClientId;
436 int AuthLevel = pSelf->Server()->GetAuthedState(ClientId: pResult->m_ClientId);
437
438 if(Tele != pResult->m_ClientId && AuthLevel < g_Config.m_SvTeleOthersAuthLevel)
439 {
440 pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "tele", pStr: "you aren't allowed to tele others");
441 return;
442 }
443
444 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: Tele);
445 CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId];
446
447 if(pChr && pPlayer && pSelf->GetPlayerChar(ClientId: TeleTo))
448 {
449 // default to view pos when character is not available
450 vec2 Pos = pPlayer->m_ViewPos;
451 if(pResult->NumArguments() == 0 && !pPlayer->IsPaused() && pChr->IsAlive())
452 {
453 vec2 Target = vec2(pChr->Core()->m_Input.m_TargetX, pChr->Core()->m_Input.m_TargetY);
454 Pos = pPlayer->m_CameraInfo.ConvertTargetToWorld(Position: pChr->GetPos(), Target);
455 }
456 pSelf->Teleport(pChr, Pos);
457 pChr->ResetJumps();
458 pChr->UnFreeze();
459 pChr->SetVelocity(vec2(0, 0));
460 }
461}
462
463void CGameContext::ConKill(IConsole::IResult *pResult, void *pUserData)
464{
465 CGameContext *pSelf = (CGameContext *)pUserData;
466 if(!CheckClientId(ClientId: pResult->m_ClientId))
467 return;
468 CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId];
469
470 if(!pPlayer || (pPlayer->m_LastKill && pPlayer->m_LastKill + pSelf->Server()->TickSpeed() * g_Config.m_SvKillDelay > pSelf->Server()->Tick()))
471 return;
472
473 pPlayer->m_LastKill = pSelf->Server()->Tick();
474 pPlayer->KillCharacter(Weapon: WEAPON_SELF);
475}
476
477void CGameContext::ConForcePause(IConsole::IResult *pResult, void *pUserData)
478{
479 CGameContext *pSelf = (CGameContext *)pUserData;
480 int Victim = pResult->GetVictim();
481 int Seconds = 0;
482 if(pResult->NumArguments() > 1)
483 Seconds = std::clamp(val: pResult->GetInteger(Index: 1), lo: 0, hi: 360);
484
485 CPlayer *pPlayer = pSelf->m_apPlayers[Victim];
486 if(!pPlayer)
487 return;
488
489 pPlayer->ForcePause(Time: Seconds);
490}
491
492void CGameContext::ConModerate(IConsole::IResult *pResult, void *pUserData)
493{
494 CGameContext *pSelf = (CGameContext *)pUserData;
495 if(!CheckClientId(ClientId: pResult->m_ClientId))
496 return;
497
498 bool HadModerator = pSelf->PlayerModerating();
499
500 CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId];
501 pPlayer->m_Moderating = !pPlayer->m_Moderating;
502
503 if(!HadModerator && pPlayer->m_Moderating)
504 pSelf->SendChat(ClientId: -1, Team: TEAM_ALL, pText: "Server kick/spec votes will now be actively moderated.", SpamProtectionClientId: 0);
505
506 if(!pSelf->PlayerModerating())
507 pSelf->SendChat(ClientId: -1, Team: TEAM_ALL, pText: "Server kick/spec votes are no longer actively moderated.", SpamProtectionClientId: 0);
508
509 if(pPlayer->m_Moderating)
510 pSelf->SendChatTarget(To: pResult->m_ClientId, pText: "Active moderator mode enabled for you.");
511 else
512 pSelf->SendChatTarget(To: pResult->m_ClientId, pText: "Active moderator mode disabled for you.");
513}
514
515void CGameContext::ConSetDDRTeam(IConsole::IResult *pResult, void *pUserData)
516{
517 CGameContext *pSelf = (CGameContext *)pUserData;
518 auto *pController = pSelf->m_pController;
519
520 if(g_Config.m_SvTeam == SV_TEAM_FORBIDDEN || g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO)
521 {
522 pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "join",
523 pStr: "Teams are disabled");
524 return;
525 }
526
527 int Target = pResult->GetVictim();
528 int Team = pResult->GetInteger(Index: 1);
529
530 if(!pController->Teams().IsValidTeamNumber(Team))
531 return;
532
533 CCharacter *pChr = pSelf->GetPlayerChar(ClientId: Target);
534
535 if((pSelf->GetDDRaceTeam(ClientId: Target) && pController->Teams().GetDDRaceState(Player: pSelf->m_apPlayers[Target]) == ERaceState::STARTED) || (pChr && pController->Teams().IsPractice(Team: pChr->Team())))
536 pSelf->m_apPlayers[Target]->KillCharacter(Weapon: WEAPON_GAME);
537
538 pController->Teams().SetForceCharacterTeam(ClientId: Target, Team);
539 pController->Teams().SetTeamLock(Team, Lock: true);
540}
541
542void CGameContext::ConUninvite(IConsole::IResult *pResult, void *pUserData)
543{
544 CGameContext *pSelf = (CGameContext *)pUserData;
545 auto *pController = pSelf->m_pController;
546
547 pController->Teams().SetClientInvited(Team: pResult->GetInteger(Index: 1), ClientId: pResult->GetVictim(), Invited: false);
548}
549
550void CGameContext::ConVoteNo(IConsole::IResult *pResult, void *pUserData)
551{
552 CGameContext *pSelf = (CGameContext *)pUserData;
553
554 pSelf->ForceVote(Success: false);
555}
556
557void CGameContext::ConDrySave(IConsole::IResult *pResult, void *pUserData)
558{
559 CGameContext *pSelf = (CGameContext *)pUserData;
560 if(!CheckClientId(ClientId: pResult->m_ClientId))
561 return;
562 CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId];
563 if(!pPlayer || !pSelf->Server()->IsRconAuthedAdmin(ClientId: pResult->m_ClientId))
564 return;
565
566 CSaveTeam SavedTeam;
567 int Team = pSelf->GetDDRaceTeam(ClientId: pResult->m_ClientId);
568 ESaveResult Result = SavedTeam.Save(pGameServer: pSelf, Team, Dry: true);
569 if(CSaveTeam::HandleSaveError(Result, ClientId: pResult->m_ClientId, pGameContext: pSelf))
570 return;
571
572 char aTimestamp[32];
573 str_timestamp(buffer: aTimestamp, buffer_size: sizeof(aTimestamp));
574 char aBuf[64];
575 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s_%s_%s.save", pSelf->Server()->GetMapName(), aTimestamp, pSelf->Server()->GetAuthName(ClientId: pResult->m_ClientId));
576 IOHANDLE File = pSelf->Storage()->OpenFile(pFilename: aBuf, Flags: IOFLAG_WRITE, Type: IStorage::TYPE_SAVE);
577 if(!File)
578 return;
579
580 int Len = str_length(str: SavedTeam.GetString());
581 io_write(io: File, buffer: SavedTeam.GetString(), size: Len);
582 io_close(io: File);
583}
584
585void CGameContext::ConReloadCensorlist(IConsole::IResult *pResult, void *pUserData)
586{
587 CGameContext *pSelf = (CGameContext *)pUserData;
588 pSelf->ReadCensorList();
589}
590
591void CGameContext::ConDumpAntibot(IConsole::IResult *pResult, void *pUserData)
592{
593 CGameContext *pSelf = (CGameContext *)pUserData;
594 pSelf->Antibot()->ConsoleCommand(pCommand: "dump");
595}
596
597void CGameContext::ConAntibot(IConsole::IResult *pResult, void *pUserData)
598{
599 CGameContext *pSelf = (CGameContext *)pUserData;
600 pSelf->Antibot()->ConsoleCommand(pCommand: pResult->GetString(Index: 0));
601}
602
603void CGameContext::ConDumpLog(IConsole::IResult *pResult, void *pUserData)
604{
605 CGameContext *pSelf = (CGameContext *)pUserData;
606 int LimitSecs = MAX_LOG_SECONDS;
607 if(pResult->NumArguments() > 0)
608 LimitSecs = pResult->GetInteger(Index: 0);
609
610 if(LimitSecs < 0)
611 return;
612
613 int Iterator = pSelf->m_LatestLog;
614 for(int i = 0; i < MAX_LOGS; i++)
615 {
616 CLog *pEntry = &pSelf->m_aLogs[Iterator];
617 Iterator = (Iterator + 1) % MAX_LOGS;
618
619 if(!pEntry->m_Timestamp)
620 continue;
621
622 int Seconds = (time_get() - pEntry->m_Timestamp) / time_freq();
623 if(Seconds > LimitSecs)
624 continue;
625
626 char aBuf[sizeof(pEntry->m_aDescription) + 128];
627 if(pEntry->m_FromServer)
628 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s, %d seconds ago", pEntry->m_aDescription, Seconds);
629 else
630 str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s, %d seconds ago < addr=<{%s}> name='%s' client=%d",
631 pEntry->m_aDescription, Seconds, pEntry->m_aClientAddrStr, pEntry->m_aClientName, pEntry->m_ClientVersion);
632 pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "log", pStr: aBuf);
633 }
634}
635
636void CGameContext::LogEvent(const char *Description, int ClientId)
637{
638 CLog *pNewEntry = &m_aLogs[m_LatestLog];
639 m_LatestLog = (m_LatestLog + 1) % MAX_LOGS;
640
641 pNewEntry->m_Timestamp = time_get();
642 str_copy(dst&: pNewEntry->m_aDescription, src: Description);
643 pNewEntry->m_FromServer = ClientId < 0;
644 if(!pNewEntry->m_FromServer)
645 {
646 pNewEntry->m_ClientVersion = Server()->GetClientVersion(ClientId);
647 str_copy(dst&: pNewEntry->m_aClientAddrStr, src: Server()->ClientAddrString(ClientId, IncludePort: false));
648 str_copy(dst&: pNewEntry->m_aClientName, src: Server()->ClientName(ClientId));
649 }
650}
651