1/*
2 * LegacyClonk
3 *
4 * Copyright (c) 1998-2000, Matthes Bender (RedWolf Design)
5 * Copyright (c) 2017-2020, The LegacyClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16
17/* Control packets contain all player input in the message queue */
18
19#pragma once
20
21#include "C4AulScriptStrict.h"
22#include "C4ForwardDeclarations.h"
23#include "C4Id.h"
24#include "C4PacketBase.h"
25#include "C4PlayerInfo.h"
26#include "C4Client.h"
27
28#include <format>
29#include <string>
30
31class C4Record;
32
33// *** control base classes
34
35class C4ControlPacket : public C4PacketBase
36{
37public:
38 C4ControlPacket();
39 ~C4ControlPacket();
40
41protected:
42 int32_t iByClient;
43
44public:
45 int32_t getByClient() const { return iByClient; }
46 bool LocalControl() const;
47 bool HostControl() const { return iByClient == C4ClientIDHost; }
48
49 void SetByClient(int32_t iByClient);
50
51 virtual bool PreExecute(const std::shared_ptr<spdlog::logger> &logger) const { return true; }
52 virtual void Execute(const std::shared_ptr<spdlog::logger> &logger) const = 0;
53 virtual void PreRec(C4Record *pRecord) {}
54
55 // allowed in lobby (without dynamic loaded)?
56 virtual bool Lobby() const { return false; }
57 // allowed as direct/private control?
58 virtual bool Sync() const { return true; }
59
60 virtual void CompileFunc(StdCompiler *pComp) override;
61};
62
63#define DECLARE_C4CONTROL_VIRTUALS \
64 virtual void Execute(const std::shared_ptr<spdlog::logger> &logger) const override; \
65 virtual void CompileFunc(StdCompiler *pComp) override;
66
67class C4Control : public C4PacketBase
68{
69public:
70 C4Control();
71 ~C4Control();
72
73protected:
74 C4PacketList Pkts;
75
76public:
77 void Clear();
78
79 // packet list wrappers
80 C4IDPacket *firstPkt() const { return Pkts.firstPkt(); }
81 C4IDPacket *nextPkt(C4IDPacket *pPkt) const { return Pkts.nextPkt(pPkt); }
82
83 void Add(C4PacketType eType, C4ControlPacket *pCtrl) { Pkts.Add(eType, pPkt: pCtrl); }
84
85 void Take(C4Control &Ctrl) { Pkts.Take(List&: Ctrl.Pkts); }
86 void Append(const C4Control &Ctrl) { Pkts.Append(List: Ctrl.Pkts); }
87 void Copy(const C4Control &Ctrl) { Clear(); Pkts.Append(List: Ctrl.Pkts); }
88 void Remove(C4IDPacket *pPkt) { Pkts.Remove(pPkt); }
89 void Delete(C4IDPacket *pPkt) { Pkts.Delete(pPkt); }
90
91 // control execution
92 bool PreExecute(const std::shared_ptr<spdlog::logger> &logger) const;
93 void Execute(const std::shared_ptr<spdlog::logger> &logger) const;
94 void PreRec(C4Record *pRecord) const;
95
96 virtual void CompileFunc(StdCompiler *pComp) override;
97};
98
99// *** control packets
100
101enum C4CtrlValueType
102{
103 C4CVT_None = -1,
104 C4CVT_ControlRate = 0,
105 C4CVT_DisableDebug = 1,
106 C4CVT_MaxPlayer = 2,
107 C4CVT_TeamDistribution = 3,
108 C4CVT_TeamColors = 4,
109 C4CVT_FairCrew = 5,
110};
111
112class C4ControlSet : public C4ControlPacket // sync, lobby
113{
114public:
115 C4ControlSet()
116 : eValType(C4CVT_None), iData(0) {}
117 C4ControlSet(C4CtrlValueType eValType, int32_t iData)
118 : eValType(eValType), iData(iData) {}
119
120protected:
121 C4CtrlValueType eValType;
122 int32_t iData;
123
124public:
125 // C4CVT_TeamDistribution and C4CVT_TeamColors are lobby-packets
126 virtual bool Lobby() const override { return eValType == C4CVT_TeamDistribution || eValType == C4CVT_TeamColors; }
127
128 DECLARE_C4CONTROL_VIRTUALS
129};
130
131class C4ControlScript : public C4ControlPacket // sync
132{
133public:
134 enum { SCOPE_Console = -2, SCOPE_Global = -1, }; // special scopes to be passed as target objects
135
136 C4ControlScript()
137 : iTargetObj(-1) {}
138 C4ControlScript(const char *szScript, int32_t iTargetObj = SCOPE_Global, C4AulScriptStrict strict = C4AulScriptStrict::MAXSTRICT)
139 : iTargetObj(iTargetObj), Strict{strict}, Script(szScript, true) {}
140
141protected:
142 int32_t iTargetObj;
143 C4AulScriptStrict Strict;
144 StdStrBuf Script;
145
146public:
147 void SetTargetObj(int32_t iObj) { iTargetObj = iObj; }
148 DECLARE_C4CONTROL_VIRTUALS
149
150public:
151 static void CheckStrictness(const C4AulScriptStrict strict, StdCompiler &comp);
152};
153
154class C4ControlPlayerSelect : public C4ControlPacket // sync
155{
156public:
157 C4ControlPlayerSelect()
158 : iPlr(-1), iObjCnt(0), pObjNrs(nullptr) {}
159 C4ControlPlayerSelect(int32_t iPlr, const C4ObjectList &Objs);
160 ~C4ControlPlayerSelect() { delete[] pObjNrs; }
161
162protected:
163 int32_t iPlr;
164 int32_t iObjCnt;
165 int32_t *pObjNrs;
166
167public:
168 DECLARE_C4CONTROL_VIRTUALS
169};
170
171class C4ControlPlayerControl : public C4ControlPacket // sync
172{
173public:
174 C4ControlPlayerControl()
175 : iPlr(-1), iCom(-1), iData(-1) {}
176 C4ControlPlayerControl(int32_t iPlr, int32_t iCom, int32_t iData)
177 : iPlr(iPlr), iCom(iCom), iData(iData) {}
178
179protected:
180 int32_t iPlr, iCom, iData;
181
182public:
183 DECLARE_C4CONTROL_VIRTUALS
184};
185
186class C4ControlPlayerCommand : public C4ControlPacket // sync
187{
188public:
189 C4ControlPlayerCommand()
190 : iPlr(-1), iCmd(-1) {}
191 C4ControlPlayerCommand(int32_t iPlr, int32_t iCmd, int32_t iX, int32_t iY,
192 C4Object *pTarget, C4Object *pTarget2, int32_t iData, int32_t iAddMode);
193
194protected:
195 int32_t iPlr, iCmd, iX, iY, iTarget, iTarget2, iData, iAddMode;
196
197public:
198 DECLARE_C4CONTROL_VIRTUALS
199};
200
201class C4ControlSyncCheck : public C4ControlPacket // not sync
202{
203public:
204 C4ControlSyncCheck();
205
206protected:
207 int32_t Frame;
208 int32_t ControlTick;
209 int32_t Random3;
210 int32_t RandomCount;
211 int32_t AllCrewPosX;
212 int32_t PXSCount;
213 int32_t MassMoverIndex;
214 int32_t ObjectCount;
215 int32_t ObjectEnumerationIndex;
216 int32_t SectShapeSum;
217
218public:
219 void Set();
220 int32_t getFrame() const { return Frame; }
221 virtual bool Sync() const override { return false; }
222 DECLARE_C4CONTROL_VIRTUALS
223
224protected:
225 static int32_t GetAllCrewPosX();
226};
227
228class C4ControlSynchronize : public C4ControlPacket // sync
229{
230public:
231 C4ControlSynchronize(bool fSavePlrFiles = false, bool fSyncClearance = false)
232 : fSavePlrFiles(fSavePlrFiles), fSyncClearance(fSyncClearance) {}
233
234protected:
235 bool fSavePlrFiles, fSyncClearance;
236
237public:
238 DECLARE_C4CONTROL_VIRTUALS
239};
240
241class C4ControlClientJoin : public C4ControlPacket // not sync, lobby
242{
243public:
244 C4ControlClientJoin() {}
245 C4ControlClientJoin(const C4ClientCore &Core) : Core(Core) {}
246
247public:
248 C4ClientCore Core;
249
250public:
251 virtual bool Sync() const override { return false; }
252 virtual bool Lobby() const override { return true; }
253 DECLARE_C4CONTROL_VIRTUALS
254};
255
256enum C4ControlClientUpdType
257{
258 CUT_None = -1, CUT_Activate = 0, CUT_SetObserver = 1
259};
260
261class C4ControlClientUpdate : public C4ControlPacket // sync, lobby
262{
263public:
264 C4ControlClientUpdate() {}
265 C4ControlClientUpdate(int32_t iID, C4ControlClientUpdType eType, int32_t iData = 0)
266 : iID(iID), eType(eType), iData(iData) {}
267
268public:
269 int32_t iID;
270 C4ControlClientUpdType eType;
271 int32_t iData;
272
273public:
274 virtual bool Sync() const override { return false; }
275 virtual bool Lobby() const override { return true; }
276 DECLARE_C4CONTROL_VIRTUALS
277};
278
279class C4ControlClientRemove : public C4ControlPacket // not sync, lobby
280{
281public:
282 C4ControlClientRemove() {}
283 C4ControlClientRemove(int32_t iID, const char *szReason = "") : iID(iID), strReason(szReason) {}
284
285public:
286 int32_t iID;
287 StdStrBuf strReason;
288
289public:
290 virtual bool Sync() const override { return false; }
291 virtual bool Lobby() const override { return true; }
292 DECLARE_C4CONTROL_VIRTUALS
293};
294
295// control used for initial player info, as well as for player info updates
296class C4ControlPlayerInfo : public C4ControlPacket // not sync, lobby
297{
298public:
299 C4ControlPlayerInfo() {}
300 C4ControlPlayerInfo(const C4ClientPlayerInfos &PlrInfo)
301 : PlrInfo(PlrInfo) {}
302
303protected:
304 C4ClientPlayerInfos PlrInfo;
305
306public:
307 const C4ClientPlayerInfos &GetInfo() const { return PlrInfo; }
308 virtual bool Sync() const override { return false; }
309 virtual bool Lobby() const override { return true; }
310 DECLARE_C4CONTROL_VIRTUALS
311};
312
313struct C4ControlJoinPlayer : public C4ControlPacket // sync
314{
315public:
316 C4ControlJoinPlayer() : iAtClient(-1), idInfo(-1) {}
317 C4ControlJoinPlayer(const char *szFilename, int32_t iAtClient, int32_t iIDInfo, const C4Network2ResCore &ResCore);
318 C4ControlJoinPlayer(const char *szFilename, int32_t iAtClient, int32_t iIDInfo);
319
320protected:
321 StdStrBuf Filename;
322 int32_t iAtClient;
323 int32_t idInfo;
324 bool fByRes;
325 StdBuf PlrData; // for fByRes == false
326 C4Network2ResCore ResCore; // for fByRes == true
327
328public:
329 DECLARE_C4CONTROL_VIRTUALS
330 virtual bool PreExecute(const std::shared_ptr<spdlog::logger> &logger) const override;
331 virtual void PreRec(C4Record *pRecord) override;
332 void Strip();
333};
334
335enum C4ControlEMObjectAction
336{
337 EMMO_Move, // move objects by offset
338 EMMO_Enter, // enter objects into iTargetObj
339 EMMO_Duplicate, // duplicate objects at same position; reset EditCursor
340 EMMO_Script, // execute Script
341 EMMO_Remove, // remove objects
342 EMMO_Exit, // exit objects
343};
344
345class C4ControlEMMoveObject : public C4ControlPacket // sync
346{
347public:
348 C4ControlEMMoveObject() : pObjects(nullptr) {}
349 C4ControlEMMoveObject(C4ControlEMObjectAction eAction, int32_t tx, int32_t ty, C4Object *pTargetObj,
350 int32_t iObjectNum = 0, int32_t *pObjects = nullptr, const char *szScript = nullptr, C4AulScriptStrict strict = C4AulScriptStrict::MAXSTRICT);
351 ~C4ControlEMMoveObject();
352
353protected:
354 C4ControlEMObjectAction eAction; // action to be performed
355 int32_t tx, ty; // target position
356 int32_t iTargetObj; // enumerated ptr to target object
357 int32_t iObjectNum; // number of objects moved
358 C4AulScriptStrict Strict; // strictness for the script to execute
359 int32_t *pObjects; // pointer on array of objects moved
360 StdStrBuf Script; // script to execute
361
362public:
363 DECLARE_C4CONTROL_VIRTUALS
364};
365
366enum C4ControlEMDrawAction
367{
368 EMDT_SetMode, // set new landscape mode
369 EMDT_Brush, // drawing tool
370 EMDT_Fill, // drawing tool
371 EMDT_Line, // drawing tool
372 EMDT_Rect, // drawing tool
373};
374
375class C4ControlEMDrawTool : public C4ControlPacket // sync
376{
377public:
378 C4ControlEMDrawTool() {}
379 C4ControlEMDrawTool(C4ControlEMDrawAction eAction, int32_t iMode,
380 int32_t iX = -1, int32_t iY = -1, int32_t iX2 = -1, int32_t iY2 = -1, int32_t iGrade = -1,
381 bool fIFT = true, const char *szMaterial = nullptr, const char *szTexture = nullptr);
382
383protected:
384 C4ControlEMDrawAction eAction; // action to be performed
385 int32_t iMode; // new mode, or mode action was performed in (action will fail if changed)
386 int32_t iX, iY, iX2, iY2, iGrade; // drawing parameters
387 bool fIFT; // sky/tunnel-background
388 StdStrBuf Material; // used material
389 StdStrBuf Texture; // used texture
390
391public:
392 DECLARE_C4CONTROL_VIRTUALS
393};
394
395enum C4ControlMessageType
396{
397 C4CMT_Normal = 0,
398 C4CMT_Me = 1,
399 C4CMT_Say = 2,
400 C4CMT_Team = 3,
401 C4CMT_Private = 4,
402 C4CMT_Sound = 5, // "message" is played as a sound instead
403 C4CMT_Alert = 6, // no message. just flash taskbar for inactive clients.
404 C4CMT_System = 10,
405};
406
407class C4ControlMessage : public C4ControlPacket // not sync, lobby
408{
409public:
410 C4ControlMessage()
411 : eType(C4CMT_Normal), iPlayer(-1) {}
412 C4ControlMessage(C4ControlMessageType eType, const char *szMessage, int32_t iPlayer = -1, int32_t iToPlayer = -1)
413 : eType(eType), iPlayer(iPlayer), iToPlayer(iToPlayer), Message(szMessage, true) {}
414
415protected:
416 C4ControlMessageType eType;
417 int32_t iPlayer, iToPlayer;
418 StdStrBuf Message;
419
420public:
421 virtual bool Sync() const override { return false; }
422 virtual bool Lobby() const override { return true; }
423 DECLARE_C4CONTROL_VIRTUALS
424};
425
426class C4ControlRemovePlr : public C4ControlPacket // sync
427{
428public:
429 C4ControlRemovePlr()
430 : iPlr(-1) {}
431 C4ControlRemovePlr(int32_t iPlr, bool fDisconnected)
432 : iPlr(iPlr), fDisconnected(fDisconnected) {}
433
434protected:
435 int32_t iPlr;
436 bool fDisconnected;
437
438public:
439 DECLARE_C4CONTROL_VIRTUALS
440};
441
442class C4ControlDebugRec : public C4ControlPacket // sync
443{
444public:
445 C4ControlDebugRec() {}
446 C4ControlDebugRec(StdBuf &Data)
447 : Data(StdBuf::TakeOrRef(other&: Data)) {}
448
449protected:
450 StdBuf Data;
451
452public:
453 DECLARE_C4CONTROL_VIRTUALS
454};
455
456enum C4ControlVoteType
457{
458 VT_None = -1,
459 VT_Cancel,
460 VT_Kick,
461 VT_Pause
462};
463
464class C4ControlVote : public C4ControlPacket
465{
466public:
467 C4ControlVote(C4ControlVoteType eType = VT_None, bool fApprove = true, int iData = 0)
468 : eType(eType), fApprove(fApprove), iData(iData) {}
469
470private:
471 C4ControlVoteType eType;
472 bool fApprove;
473 int32_t iData;
474
475public:
476 C4ControlVoteType getType() const { return eType; }
477 bool isApprove() const { return fApprove; }
478 int32_t getData() const { return iData; }
479
480 StdStrBuf getDesc() const;
481 StdStrBuf getDescWarning() const;
482
483 virtual bool Sync() const override { return false; }
484
485 DECLARE_C4CONTROL_VIRTUALS
486};
487
488class C4ControlVoteEnd : public C4ControlVote
489{
490public:
491 C4ControlVoteEnd(C4ControlVoteType eType = VT_None, bool fApprove = true, int iData = 0)
492 : C4ControlVote(eType, fApprove, iData) {}
493
494 virtual bool Sync() const override { return true; }
495
496 DECLARE_C4CONTROL_VIRTUALS
497};
498
499class C4ControlInternalScriptBase : public C4ControlPacket
500{
501public:
502 virtual int32_t Scope() const { return C4ControlScript::SCOPE_Global; }
503 virtual bool Allowed() const { return true; }
504 virtual std::string FormatScript() const = 0;
505 virtual void Execute(const std::shared_ptr<spdlog::logger> &logger) const override;
506};
507
508class C4ControlEMDropDef : public C4ControlInternalScriptBase
509{
510 C4ID id = C4ID_None;
511 int32_t x = 0;
512 int32_t y = 0;
513
514public:
515 C4ControlEMDropDef() {}
516 C4ControlEMDropDef(C4ID id, int32_t x, int32_t y) : id(id), x(x), y(y) {}
517 virtual void CompileFunc(StdCompiler *pComp) override;
518 virtual bool Allowed() const override;
519 virtual std::string FormatScript() const override;
520};
521
522class C4ControlInternalPlayerScriptBase : public C4ControlInternalScriptBase
523{
524protected:
525 int32_t plr = NO_OWNER;
526
527public:
528 C4ControlInternalPlayerScriptBase() {}
529 C4ControlInternalPlayerScriptBase(int32_t plr) : plr(plr) {}
530 virtual void CompileFunc(StdCompiler *pComp) override;
531 virtual bool Allowed() const override;
532};
533
534class C4ControlMessageBoardAnswer : public C4ControlInternalPlayerScriptBase
535{
536 int32_t obj = 0;
537 std::string answer;
538
539public:
540 C4ControlMessageBoardAnswer() {}
541 C4ControlMessageBoardAnswer(int32_t obj, int32_t plr, const std::string &answer) : obj(obj), answer(answer), C4ControlInternalPlayerScriptBase(plr) {}
542 virtual void CompileFunc(StdCompiler *pComp) override;
543 virtual std::string FormatScript() const override;
544};
545
546class C4ControlCustomCommand : public C4ControlInternalPlayerScriptBase
547{
548 std::string command;
549 std::string argument;
550
551public:
552 C4ControlCustomCommand() {}
553 C4ControlCustomCommand(int32_t plr, const std::string &command, const std::string &argument) : command(command), argument(argument), C4ControlInternalPlayerScriptBase(plr) {}
554 virtual bool Allowed() const override;
555 virtual void CompileFunc(StdCompiler *pComp) override;
556 virtual std::string FormatScript() const override;
557};
558
559class C4ControlInitScenarioPlayer : public C4ControlInternalPlayerScriptBase
560{
561 int32_t team = 0;
562
563public:
564 C4ControlInitScenarioPlayer() {}
565 C4ControlInitScenarioPlayer(int32_t plr, int32_t team) : team(team), C4ControlInternalPlayerScriptBase(plr) {}
566 virtual void CompileFunc(StdCompiler *pComp) override;
567 virtual std::string FormatScript() const override { return std::format(fmt: "InitScenarioPlayer({},{})", args: plr, args: team); }
568};
569
570class C4ControlActivateGameGoalMenu : public C4ControlInternalPlayerScriptBase
571{
572public:
573 C4ControlActivateGameGoalMenu() {}
574 C4ControlActivateGameGoalMenu(int32_t plr) : C4ControlInternalPlayerScriptBase(plr) {}
575 virtual std::string FormatScript() const override { return std::format(fmt: "ActivateGameGoalMenu({})", args: plr); }
576};
577
578class C4ControlToggleHostility : public C4ControlInternalPlayerScriptBase
579{
580 int32_t opponent = 0;
581
582public:
583 C4ControlToggleHostility() {}
584 C4ControlToggleHostility(int32_t plr, int32_t opponent) : opponent(opponent), C4ControlInternalPlayerScriptBase(plr) {}
585 virtual void CompileFunc(StdCompiler *pComp) override;
586 virtual std::string FormatScript() const override { return std::format(fmt: "SetHostility({},{},!Hostile({},{},true))", args: plr, args: opponent, args: plr, args: opponent); }
587};
588
589class C4ControlSurrenderPlayer : public C4ControlInternalPlayerScriptBase
590{
591public:
592 C4ControlSurrenderPlayer() {}
593 C4ControlSurrenderPlayer(int32_t plr) : C4ControlInternalPlayerScriptBase(plr) {}
594 virtual std::string FormatScript() const override { return std::format(fmt: "SurrenderPlayer({})", args: plr); }
595};
596
597class C4ControlActivateGameGoalRule : public C4ControlInternalPlayerScriptBase
598{
599 int32_t obj = 0;
600
601public:
602 C4ControlActivateGameGoalRule() {}
603 C4ControlActivateGameGoalRule(int32_t plr, int32_t obj) : obj(obj), C4ControlInternalPlayerScriptBase(plr) {}
604 virtual void CompileFunc(StdCompiler *pComp) override;
605 virtual std::string FormatScript() const override { return std::format(fmt: "Activate({})", args: plr); }
606 virtual int32_t Scope() const override { return obj; }
607};
608
609class C4ControlSetPlayerTeam : public C4ControlInternalPlayerScriptBase
610{
611 int32_t team = 0;
612
613public:
614 C4ControlSetPlayerTeam() {}
615 C4ControlSetPlayerTeam(int32_t plr, int32_t team) : team(team), C4ControlInternalPlayerScriptBase(plr) {}
616 virtual void CompileFunc(StdCompiler *pComp) override;
617 virtual std::string FormatScript() const override { return std::format(fmt: "SetPlayerTeam({},{})", args: plr, args: team); }
618};
619
620class C4ControlEliminatePlayer : public C4ControlInternalPlayerScriptBase
621{
622public:
623 C4ControlEliminatePlayer() {}
624 C4ControlEliminatePlayer(int32_t plr) : C4ControlInternalPlayerScriptBase(plr) {}
625 virtual bool Allowed() const override { return HostControl(); }
626 virtual std::string FormatScript() const override { return std::format(fmt: "EliminatePlayer({})", args: plr); }
627};
628