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