OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Control.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Control packets contain all player input in the message queue */
19 
20 #include "C4Include.h"
21 #include "control/C4Control.h"
22 
23 #include "control/C4GameControl.h"
24 #include "control/C4GameSave.h"
25 #include "control/C4RoundResults.h"
26 #include "editor/C4Console.h"
27 #include "game/C4GameScript.h"
28 #include "game/C4GraphicsSystem.h"
29 #include "gui/C4GameLobby.h"
30 #include "gui/C4GameMessage.h"
31 #include "gui/C4MessageInput.h"
32 #include "gui/C4ScriptGuiWindow.h"
33 #include "landscape/C4Landscape.h"
34 #include "landscape/C4MassMover.h"
35 #include "landscape/C4PXS.h"
36 #include "lib/C4Random.h"
38 #include "object/C4Def.h"
39 #include "object/C4DefList.h"
40 #include "object/C4GameObjects.h"
41 #include "object/C4Object.h"
42 #include "player/C4Player.h"
43 #include "player/C4PlayerList.h"
44 #include "player/C4RankSystem.h"
45 #include "script/C4AulExec.h"
46 
47 #ifndef NOAULDEBUG
48 #include "script/C4AulDebug.h"
49 #endif
50 
51 // *** C4ControlPacket
53  : iByClient(::Control.ClientID())
54 {
55 
56 }
57 
59 
61 {
62  return iByClient == ::Control.ClientID();
63 }
64 
65 void C4ControlPacket::SetByClient(int32_t inByClient)
66 {
67  iByClient = inByClient;
68 }
69 
71 {
72  // Section must be set by caller
73  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iByClient), "ByClient", -1));
74 }
75 
76 // *** C4Control
77 
78 C4Control::C4Control() = default;
79 
81 {
82  Clear();
83 }
84 
86 {
87  Pkts.Clear();
88 }
89 
91 {
92  bool fReady = true;
93  for (C4IDPacket *pPkt = firstPkt(); pPkt; pPkt = nextPkt(pPkt))
94  {
95  // recheck packet type: Must be control
96  if (pPkt->getPktType() & CID_First)
97  {
98  C4ControlPacket *pCtrlPkt = static_cast<C4ControlPacket *>(pPkt->getPkt());
99  if (pCtrlPkt)
100  fReady &= pCtrlPkt->PreExecute();
101  }
102  else
103  {
104  LogF("C4Control::PreExecute: WARNING: Ignoring packet type %2x (not control.)", pPkt->getPktType());
105  }
106  }
107  return fReady;
108 }
109 
110 void C4Control::Execute() const
111 {
112  for (C4IDPacket *pPkt = firstPkt(); pPkt; pPkt = nextPkt(pPkt))
113  {
114  // recheck packet type: Must be control
115  if (pPkt->getPktType() & CID_First)
116  {
117  C4ControlPacket *pCtrlPkt = static_cast<C4ControlPacket *>(pPkt->getPkt());
118  if (pCtrlPkt)
119  pCtrlPkt->Execute();
120  }
121  else
122  {
123  LogF("C4Control::Execute: WARNING: Ignoring packet type %2x (not control.)", pPkt->getPktType());
124  }
125  }
126 }
127 
128 void C4Control::PreRec(C4Record *pRecord) const
129 {
130  for (C4IDPacket *pPkt = firstPkt(); pPkt; pPkt = nextPkt(pPkt))
131  {
132  C4ControlPacket *pCtrlPkt = static_cast<C4ControlPacket *>(pPkt->getPkt());
133  if (pCtrlPkt)
134  pCtrlPkt->PreRec(pRecord);
135  }
136 }
137 
139 {
140  pComp->Value(Pkts);
141 }
142 
143 // *** C4ControlSet
144 
145 void C4ControlSet::Execute() const
146 {
147  switch (eValType)
148  {
149  case C4CVT_None: break;
150 
151  case C4CVT_ControlRate: // adjust control rate
152  // host only
153  if (iByClient != C4ClientIDHost) break;
154  // adjust control rate
158  // write back adjusted control rate to network settings
161  // always show msg
163  break;
164 
165  case C4CVT_DisableDebug: // force debug mode disabled
166  {
167  if (Game.DebugMode)
168  {
169  Game.DebugMode=false;
171  }
172  // save flag, log
173  Game.Parameters.AllowDebug = false;
175  LogF("Debug mode forced disabled by %s", client ? client->getName() : "<unknown client>");
176  break;
177  }
178  break;
179 
180  case C4CVT_MaxPlayer:
181  // host only
182  if (iByClient != C4ClientIDHost) break;
183  // not in league
184  if (Game.Parameters.isLeague())
185  {
186  Log("/set maxplayer disabled in league!");
187  C4GUI::GUISound("UI::Error");
188  break;
189  }
190  // set it
192  LogF("MaxPlayer = %d", (int)Game.Parameters.MaxPlayers);
193  break;
194 
196  // host only
197  if (iByClient != C4ClientIDHost) break;
198  // set new value
199  Game.Teams.SetTeamDistribution(static_cast<C4TeamList::TeamDist>(iData));
200  break;
201 
202  case C4CVT_TeamColors:
203  // host only
204  if (!HostControl()) break;
205  // set new value
207  break;
208  }
209 }
210 
212 {
213  pComp->Value(mkNamingAdapt(mkIntAdapt(eValType), "Type", C4CVT_None));
214  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iData), "Data", 0));
216 }
217 
218 // *** C4ControlScript
219 
220 void C4ControlScript::Execute() const
221 {
222  const char *szScript = Script.getData();
223  // user script: from host only
224  if ((iByClient != C4ClientIDHost) && !Console.Active) return;
225  // only allow scripts when debug mode is not forbidden
226  if (!Game.Parameters.AllowDebug) return;
227 
228  // execute
229  C4PropList *pPropList = nullptr;
230  if (iTargetObj == SCOPE_Console)
231  pPropList = ::GameScript.ScenPropList.getPropList();
232  else if (iTargetObj == SCOPE_Global)
233  pPropList = ::ScriptEngine.GetPropList();
234  else if (!(pPropList = ::Objects.SafeObjectPointer(iTargetObj)))
235  // default: Fallback to global context
236  pPropList = ::ScriptEngine.GetPropList();
237  C4Value rVal(AulExec.DirectExec(pPropList, szScript, "console script", false, fUseVarsFromCallerContext ? AulExec.GetContext(AulExec.GetContextDepth()-1) : nullptr));
238 #ifndef NOAULDEBUG
239  C4AulDebug* pDebug;
240  if ( (pDebug = C4AulDebug::GetDebugger()) )
241  {
242  pDebug->ControlScriptEvaluated(szScript, rVal.GetDataString().getData());
243  }
244 #endif
245  // show messages
246  // print script
247  LogF("-> %s::%s", pPropList->GetName(), szScript);
248  // print result
249  bool is_local_script = true;
250  if (!LocalControl())
251  {
252  C4Network2Client *pClient = nullptr;
253  if (::Network.isEnabled())
254  {
256  if (pClient != ::Network.Clients.GetLocal())
257  {
258  is_local_script = false;
259  }
260  }
261  if (pClient)
262  LogF(" = %s (by %s)", rVal.GetDataString().getData(), pClient->getName());
263  else
264  LogF(" = %s (by client %d)", rVal.GetDataString().getData(), iByClient);
265  }
266  else
267  LogF(" = %s", rVal.GetDataString().getData());
268  // Editor update
269  if (::Console.Active)
270  {
271  C4Object *returned_object = rVal.getObj();
272  if (editor_select_result && is_local_script && returned_object)
273  {
274  ::Console.EditCursor.ClearSelection(returned_object);
275  ::Console.EditCursor.AddToSelection(returned_object);
277  }
278  // Always: refresh property view after script command
280  }
281 }
282 
284 {
285  pComp->Value(mkNamingAdapt(iTargetObj, "TargetObj", -1));
286  pComp->Value(mkNamingAdapt(fUseVarsFromCallerContext, "UseVarsFromCallerContext", false));
287  pComp->Value(mkNamingAdapt(editor_select_result, "EditorSelectResult", false));
288  pComp->Value(mkNamingAdapt(Script, "Script", ""));
290 }
291 
292 // *** C4ControlMsgBoardReply
294 {
295  C4Object *target_object = ::Objects.SafeObjectPointer(target);
296  C4Player *target_player = ::Players.Get(player);
297 
298  // remove query
299  if (!target_player) return;
300  if (!target_player->RemoveMessageBoardQuery(target_object)) return;
301 
302  // execute callback if answer present
303  if (!reply) return;
304  C4AulParSet pars(C4VString(reply), player);
305  if (target_object)
306  target_object->Call(PSF_InputCallback, &pars);
307  else
309 }
310 
312 {
313  pComp->Value(mkNamingAdapt(target, "TargetObj", -1));
314  pComp->Value(mkNamingAdapt(player, "Player", NO_OWNER));
315  pComp->Value(mkNamingAdapt(reply, "Reply", nullptr));
317 }
318 
319 // *** C4ControlMsgBoardCmd
321 {
322  // don't handle this if the game isn't actually running
323  if (!::Game.IsRunning) return;
324 
325  // fetch command script
327  if (!cmd) return;
328  StdCopyStrBuf script(cmd->Script);
329 
330  // interpolate parameters as required
331  script.Replace("%player%", FormatString("%d", player).getData());
332  if (parameter)
333  {
334  script.Replace("%d", FormatString("%d", std::atoi(parameter.getData())).getData());
335  StdCopyStrBuf escaped_param(parameter);
336  escaped_param.EscapeString();
337  script.Replace("%s", escaped_param.getData());
338  }
339 
340  // Run script
341  C4Value rv(::AulExec.DirectExec(::ScriptEngine.GetPropList(), script.getData(), "message board command"));
342 #ifndef NOAULDEBUG
344  if (pDebug)
345  pDebug->ControlScriptEvaluated(script.getData(), rv.GetDataString().getData());
346 #endif
347 }
348 
350 {
351  pComp->Value(mkNamingAdapt(player, "Player", NO_OWNER));
352  pComp->Value(mkNamingAdapt(command, "Command"));
353  pComp->Value(mkNamingAdapt(parameter, "Parameter"));
355 }
356 // *** C4ControlPlayerSelect
357 
358 C4ControlPlayerSelect::C4ControlPlayerSelect(int32_t iPlr, const C4ObjectList &Objs, bool fIsAlt)
359  : iPlr(iPlr), fIsAlt(fIsAlt), iObjCnt(Objs.ObjectCount())
360 {
361  pObjNrs = new int32_t[iObjCnt];
362  int32_t i = 0;
363  for (C4Object *obj : Objs)
364  pObjNrs[i++] = obj->Number;
365  assert(i == iObjCnt);
366 }
367 
369 {
370  // get player
371  C4Player *pPlr = ::Players.Get(iPlr);
372  if (!pPlr) return;
373 
374  // Check object list
375  C4Object *pObj;
376  int32_t iControlChecksum = 0;
377  for (int32_t i = 0; i < iObjCnt; i++)
378  if ((pObj = ::Objects.SafeObjectPointer(pObjNrs[i])))
379  {
380  iControlChecksum += pObj->Number * (iControlChecksum+4787821);
381  // user defined object selection: callback to object
382  if (pObj->Category & C4D_MouseSelect)
383  {
384  if (fIsAlt)
386  else
388  }
389  }
390  // count
391  pPlr->CountControl(C4Player::PCID_Command, iControlChecksum);
392 }
393 
395 {
396  pComp->Value(mkNamingAdapt(iPlr, "Player", -1));
397  pComp->Value(mkNamingAdapt(fIsAlt, "IsAlt", false));
398  pComp->Value(mkNamingAdapt(iObjCnt, "ObjCnt", 0));
399  // Compile array
400  if (pComp->isDeserializer())
401  { delete[] pObjNrs; pObjNrs = new int32_t [iObjCnt]; }
402  pComp->Value(mkNamingAdapt(mkArrayAdapt(pObjNrs, iObjCnt), "Objs", 0));
403 
405 }
406 
407 
408 // *** C4ControlPlayerControl
409 
411 {
412  C4PlayerControl *pTargetCtrl = nullptr;
413  if (iPlr == -1)
414  {
415  // neutral control packet: Execute in global control
416  }
417  else
418  {
419  // player-based control: Execute on control owned by player
420  C4Player *pPlr=::Players.Get(iPlr);
421  if (pPlr)
422  {
423  pTargetCtrl = &(pPlr->Control);
424  }
425  }
426  if (pTargetCtrl) pTargetCtrl->ExecuteControlPacket(this);
427 }
428 
430 {
431  pComp->Value(iControl);
432  pComp->Separator();
433  pComp->Value(iTriggerMode);
434 }
435 
437 {
438  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iPlr), "Player", -1));
439  pComp->Value(mkNamingAdapt(mkIntAdapt(state), "State", 0));
440  pComp->Value(mkNamingAdapt(ExtraData, "ExtraData", C4KeyEventData()));
443 }
444 
445 // *** C4ControlPlayerMouse
446 C4ControlPlayerMouse *C4ControlPlayerMouse::Hover(const C4Player *player, const C4Object *target, const C4Object *old_target, const C4Object *drag)
447 {
448  assert(player != nullptr);
449  if (!player) return nullptr;
450 
451  auto control = new C4ControlPlayerMouse();
452  control->action = CPM_Hover;
453  control->player = player->Number;
454  control->drag_obj = drag ? drag->Number : 0;
455  control->target_obj = target ? target->Number : 0;
456  control->old_obj = old_target ? old_target->Number : 0;
457  return control;
458 }
460 {
461  assert(player != nullptr);
462  if (!player) return nullptr;
463 
464  auto control = new C4ControlPlayerMouse();
465  control->action = CPM_Drop;
466  control->player = player->Number;
467  control->drag_obj = drag ? drag->Number : 0;
468  control->target_obj = target ? target->Number : 0;
469  return control;
470 }
471 
473 {
474  const char *callback_name = nullptr;
475  C4AulParSet pars(player);
476 
477  switch (action)
478  {
479  case CPM_NoAction:
480  return;
481 
482  case CPM_Hover:
483  // Mouse movement, object hover state changed
484  callback_name = PSF_MouseHover;
485  pars[1] = C4VObj(::Objects.SafeObjectPointer(old_obj));
486  pars[2] = C4VObj(::Objects.SafeObjectPointer(target_obj));
487  pars[3] = C4VObj(::Objects.SafeObjectPointer(drag_obj));
488  break;
489 
490  case CPM_Drop:
491  // Drag/Drop operation
492  callback_name = PSF_MouseDragDrop;
493  pars[1] = C4VObj(::Objects.SafeObjectPointer(drag_obj));
494  pars[2] = C4VObj(::Objects.SafeObjectPointer(target_obj));
495  break;
496  }
497 
498  // Do call
499  if (!callback_name) return;
500  ::ScriptEngine.Call(callback_name, &pars);
501 }
502 
504 {
505  pComp->Value(mkNamingAdapt(action, "Action"));
506  pComp->Value(mkNamingAdapt(player, "Player", NO_OWNER));
507  pComp->Value(mkNamingAdapt(target_obj, "TargetObj"));
508  pComp->Value(mkNamingAdapt(drag_obj, "DragObj"));
509  pComp->Value(mkNamingAdapt(old_obj, "OldObj"));
510 }
511 
512 // *** C4ControlMenuCommand
513 
514 C4ControlMenuCommand::C4ControlMenuCommand(int32_t actionID, int32_t player, int32_t menuID, int32_t subwindowID, C4Object *target, int32_t actionType)
515  : actionID(actionID), player(player), menuID(menuID), subwindowID(subwindowID), target(target ? target->Number : 0), actionType(actionType)
516 {
517 
518 }
519 
521 {
522  // invalid action? The action needs to be in bounds!
523  if (actionType < 0 || actionType >= C4ScriptGuiWindowPropertyName::_lastProp)
524  {
525  // this could only come from a malicious attempt to crash the engine!
526  Log("Warning: invalid action type for C4ControlMenuCommand!");
527  return;
528  }
529  C4ScriptGuiWindow *menu = ::Game.ScriptGuiRoot->GetChildByID(menuID);
530  // menu was closed?
531  if (!menu) return;
532 
533  C4Object *obj = target ? ::Objects.ObjectPointer(target) : nullptr;
534  // target has been removed in the meantime? abort now
535  if (target && !obj) return;
536 
538 }
539 
541 {
542  pComp->Value(mkNamingAdapt(mkIntPackAdapt(actionID), "ID", -1));
543  pComp->Value(mkNamingAdapt(mkIntPackAdapt(player), "Player", -1));
544  pComp->Value(mkNamingAdapt(mkIntPackAdapt(menuID), "Menu", 0));
545  pComp->Value(mkNamingAdapt(mkIntPackAdapt(subwindowID), "Window", 0));
546  pComp->Value(mkNamingAdapt(mkIntPackAdapt(actionType), "Action", 0));
547  pComp->Value(mkNamingAdapt(target, "Target", 0));
549 }
550 
551 // *** C4ControlPlayerAction
553  : source(source ? source->Number : NO_OWNER), target(NO_OWNER)
554 {
555 }
556 
558 {
559  assert(source);
560  C4ControlPlayerAction *control = new C4ControlPlayerAction(source);
561  control->action = CPA_Surrender;
562  return control;
563 }
565 {
566  assert(source);
567  C4ControlPlayerAction *control = new C4ControlPlayerAction(source);
568  control->action = CPA_Eliminate;
569  return control;
570 }
572 {
573  assert(source);
574  assert(goal);
575  C4ControlPlayerAction *control = new C4ControlPlayerAction(source);
576  control->action = CPA_ActivateGoal;
577  control->target = goal->Number;
578  return control;
579 }
581 {
582  assert(source);
583  C4ControlPlayerAction *control = new C4ControlPlayerAction(source);
584  control->action = CPA_ActivateGoalMenu;
585  return control;
586 }
588 {
589  assert(source);
590  assert(target);
591  C4ControlPlayerAction *control = new C4ControlPlayerAction(source);
592  control->action = CPA_SetHostility;
593  control->target = target ? target->Number : NO_OWNER;
594  control->param_int = hostile;
595  return control;
596 }
598 {
599  assert(source);
600  C4ControlPlayerAction *control = new C4ControlPlayerAction(source);
601  control->action = CPA_SetTeam;
602  control->target = team;
603  return control;
604 }
606 {
607  assert(source);
608  C4ControlPlayerAction *control = new C4ControlPlayerAction(source);
609  control->action = CPA_InitScenarioPlayer;
610  control->target = team;
611  return control;
612 }
614 {
615  assert(source);
616  C4ControlPlayerAction *control = new C4ControlPlayerAction(source);
617  control->action = CPA_InitPlayerControl;
618  if (ctrl_set)
619  {
620  control->param_str = ctrl_set->GetName();
621  if (ctrl_set->HasKeyboard())
622  control->param_int |= CPA_IPC_HasKeyboard;
623  if (ctrl_set->HasMouse())
624  control->param_int |= CPA_IPC_HasMouse;
625  if (ctrl_set->HasGamepad())
626  control->param_int |= CPA_IPC_HasGamepad;
627  }
628  return control;
629 }
630 
632 {
633  // The originating player must exist
634  C4Player *source_player = ::Players.Get(source);
635  if (!source_player) return;
636 
637  switch (action)
638  {
639  case CPA_Surrender:
640  source_player->Surrender();
641  break;
642 
643  case CPA_Eliminate:
644  source_player->Eliminate();
645  break;
646 
647  case CPA_ActivateGoal:
648  {
649  // Make sure the object actually exists
650  C4Object *goal = ::Objects.SafeObjectPointer(target);
651  if (!goal) return;
652  // Call it
653  C4AulParSet pars(source_player->Number);
654  goal->Call("Activate", &pars);
655  break;
656  }
657 
659  // open menu
660  source_player->Menu.ActivateGoals(source_player->Number, source_player->LocalControl && !::Control.isReplay());
661  break;
662 
663  case CPA_SetHostility:
664  {
665  // Can only set hostility towards a player that exists
666  C4Player *target_player = ::Players.Get(target);
667  if (!target_player) return;
668 
669  // Proxy the hostility change through C4Aul, in case a script wants to capture it
670  C4AulParSet pars(source_player->Number, target_player->Number, param_int != 0);
671  ::ScriptEngine.Call("SetHostility", &pars);
672  break;
673  }
674 
675  case CPA_SetTeam:
676  {
677  // Make sure team switching is allowed in the first place
678  if (!::Game.Teams.IsTeamSwitchAllowed()) return;
679 
680  // We can't change teams to one that doesn't exist
681  C4Team *team = ::Game.Teams.GetTeamByID(target);
682  if (!team && target != TEAMID_New) return;
683 
684  // Proxy the team switch through C4Aul, in case a script wants to capture it
685  C4AulParSet pars(source_player->Number, target);
686  ::ScriptEngine.Call("SetPlayerTeam", &pars);
687  break;
688  }
689 
691  {
692  // Proxy the call through C4Aul, in case a script wants to capture it
693  C4AulParSet pars(source_player->Number, target);
694  ::ScriptEngine.Call("InitScenarioPlayer", &pars);
695  break;
696  }
697 
699  {
700  // Notify scripts about player control selection
701  const char *callback_name = PSF_InitializePlayerControl;
702 
703  C4AulParSet pars(source_player->Number);
704  // If the player is using a control set, its name is stored in param_str
705  if (param_str)
706  {
707  pars[1] = C4VString(param_str);
708  pars[2] = C4VBool(CPA_IPC_HasKeyboard == (param_int & CPA_IPC_HasKeyboard));
709  pars[3] = C4VBool(CPA_IPC_HasMouse == (param_int & CPA_IPC_HasMouse));
710  pars[4] = C4VBool(CPA_IPC_HasGamepad == (param_int & CPA_IPC_HasGamepad));
711  }
712  ::ScriptEngine.Call(callback_name, &pars);
713  break;
714  }
715 
716  case CPA_NoAction: break;
717  }
718 }
719 
721 {
722  pComp->Value(mkNamingAdapt(source, "Player", NO_OWNER));
723  const StdEnumEntry<Action> ActionNames[] =
724  {
725  { "Surrender", CPA_Surrender },
726  { "ActivateGoal", CPA_ActivateGoal },
727  { "ActivateGoalMenu", CPA_ActivateGoalMenu },
728  { "Eliminate", CPA_Eliminate },
729  { "SetHostility", CPA_SetHostility },
730  { "SetTeam", CPA_SetTeam },
731  { "InitScenarioPlayer", CPA_InitScenarioPlayer },
732  { "InitPlayerControl", CPA_InitPlayerControl },
733  { nullptr, CPA_NoAction }
734  };
735  pComp->Value(mkNamingAdapt(mkEnumAdapt<Action, int32_t>(action, ActionNames), "Action", CPA_NoAction));
736  pComp->Value(mkNamingAdapt(target, "Target", NO_OWNER));
737  pComp->Value(mkNamingAdapt(param_int, "DataI", 0));
738  pComp->Value(mkNamingAdapt(param_str, "DataS", nullptr));
740 }
741 
742 // *** C4ControlSyncCheck
743 
745 
747 {
752  PXSCount = ::PXS.Count;
757 }
758 
760 {
761  int32_t cpx=0;
762  for (C4Player *pPlr=::Players.First; pPlr; pPlr=pPlr->Next)
763  for (C4Object *member : pPlr->Crew)
764  cpx += fixtoi(member->fix_x, 100);
765  return cpx;
766 }
767 
768 void C4ControlSyncCheck::Execute() const
769 {
770  // control host?
771  if (::Control.isCtrlHost()) return;
772 
773  // get the saved sync check data
774  C4ControlSyncCheck* pSyncCheck = ::Control.GetSyncCheck(Frame), &SyncCheck = *pSyncCheck;
775  if (!pSyncCheck)
776  {
778  return;
779  }
780 
781  // Not equal
782  if ( Frame != pSyncCheck->Frame
783  ||(ControlTick != pSyncCheck->ControlTick && !::Control.isReplay())
784  || RandomCount != pSyncCheck->RandomCount
785  || AllCrewPosX != pSyncCheck->AllCrewPosX
786  || PXSCount != pSyncCheck->PXSCount
787  || MassMoverIndex != pSyncCheck->MassMoverIndex
788  || ObjectCount != pSyncCheck->ObjectCount
790  || SectShapeSum != pSyncCheck->SectShapeSum)
791  {
792  const char *szThis = "Client", *szOther = ::Control.isReplay() ? "Rec ":"Host";
793  if (iByClient != ::Control.ClientID())
794  { const char *szTemp = szThis; szThis = szOther; szOther = szTemp; }
795  // Message
796  LogFatal("Network: Synchronization loss!");
797  LogFatal(FormatString("Network: %s Frm %i Ctrl %i Rnc %i Cpx %i PXS %i MMi %i Obc %i Oei %i Sct %i", szThis, Frame,ControlTick,RandomCount,AllCrewPosX,PXSCount,MassMoverIndex,ObjectCount,ObjectEnumerationIndex, SectShapeSum).getData());
798  LogFatal(FormatString("Network: %s Frm %i Ctrl %i Rnc %i Cpx %i PXS %i MMi %i Obc %i Oei %i Sct %i", szOther, SyncCheck.Frame,SyncCheck.ControlTick,SyncCheck.RandomCount,SyncCheck.AllCrewPosX,SyncCheck.PXSCount,SyncCheck.MassMoverIndex,SyncCheck.ObjectCount,SyncCheck.ObjectEnumerationIndex, SyncCheck.SectShapeSum).getData());
799  StartSoundEffect("UI::SyncError");
800 #ifdef _DEBUG
801  // Debug safe
802  C4GameSaveNetwork SaveGame(false);
803  SaveGame.Save(Config.AtExePath("Desync.ocs"));
804 #endif
805  // league: Notify regular client disconnect within the game
807  // Deactivate / end
808  if (::Control.isReplay())
809  Game.DoGameOver();
810  else if (::Control.isNetwork())
811  {
812  Game.RoundResults.EvaluateNetwork(C4RoundResults::NR_NetError, "Network: Synchronization loss!");
813  ::Network.Clear();
814  }
815  }
816 
817 }
818 
820 {
821  pComp->Value(mkNamingAdapt(mkIntPackAdapt(Frame), "Frame", -1));
822  pComp->Value(mkNamingAdapt(mkIntPackAdapt(ControlTick), "ControlTick", 0));
823  pComp->Value(mkNamingAdapt(RandomCount, "RandomCount", 0));
824  pComp->Value(mkNamingAdapt(mkIntPackAdapt(AllCrewPosX), "AllCrewPosX", 0));
825  pComp->Value(mkNamingAdapt(mkIntPackAdapt(PXSCount), "PXSCount", 0));
826  pComp->Value(mkNamingAdapt(MassMoverIndex, "MassMoverIndex", 0));
827  pComp->Value(mkNamingAdapt(mkIntPackAdapt(ObjectCount), "ObjectCount", 0));
828  pComp->Value(mkNamingAdapt(mkIntPackAdapt(ObjectEnumerationIndex), "ObjectEnumerationIndex", 0));
829  pComp->Value(mkNamingAdapt(mkIntPackAdapt(SectShapeSum), "SectShapeSum", 0));
831 }
832 
833 // *** C4ControlSynchronize
834 
836 {
839 }
840 
842 {
843  pComp->Value(mkNamingAdapt(fSavePlrFiles, "SavePlrs", false));
844  pComp->Value(mkNamingAdapt(fSyncClearance, "SyncClear", false));
846 }
847 
848 // *** C4ControlClientJoin
849 
850 void C4ControlClientJoin::Execute() const
851 {
852  // host only
853  if (iByClient != C4ClientIDHost) return;
854  // add client
855  C4Client *pClient = Game.Clients.Add(Core);
856  if (!pClient) return;
857  // log
858  LogF(LoadResStr("IDS_NET_CLIENT_JOIN"), Core.getName());
859  // lobby callback
861  if (pLobby) pLobby->OnClientJoin(pClient);
862  // console callback
864 }
865 
867 {
868  pComp->Value(mkNamingAdapt(Core, "ClientCore"));
870 }
871 
872 // *** C4Control
873 
875 {
876  // host only
877  if (iByClient != C4ClientIDHost && eType != CUT_SetReady) return;
878  // find client
879  C4Client *pClient = Game.Clients.getClientByID(iID);
880  if (!pClient) return;
881  StdCopyStrBuf strClient(LoadResStr(pClient->isLocal() ? "IDS_NET_LOCAL_CLIENT" : "IDS_NET_CLIENT"));
882  // do whatever specified
883  switch (eType)
884  {
885  case CUT_None: break;
886  case CUT_Activate:
887  // nothing to do?
888  if (pClient->isActivated() == !!iData) break;
889  // log
890  LogF(LoadResStr(iData ? "IDS_NET_CLIENT_ACTIVATED" : "IDS_NET_CLIENT_DEACTIVATED"), strClient.getData(), pClient->getName());
891  // activate/deactivate
892  pClient->SetActivated(!!iData);
893  // local?
894  if (pClient->isLocal())
896  break;
897  case CUT_SetObserver:
898  // nothing to do?
899  if (pClient->isObserver()) break;
900  // log
901  LogF(LoadResStr("IDS_NET_CLIENT_OBSERVE"), strClient.getData(), pClient->getName());
902  // set observer (will deactivate)
903  pClient->SetObserver();
904  // local?
905  if (pClient->isLocal())
906  ::Control.SetActivated(false);
907  // remove all players ("soft kick")
909  break;
910  case CUT_SetReady:
911  {
912  // nothing to do?
913  if (pClient->isLobbyReady() == !!iData) break;
914  // ready/unready (while keeping track of time)
915  time_t last_change_time = MinReadyAnnouncementDelay;
916  pClient->SetLobbyReady(!!iData, &last_change_time);
917  // log to others, but don't spam
918  if (last_change_time >= MinReadyAnnouncementDelay)
919  {
920  if (!pClient->isLocal())
921  {
922  LogF(LoadResStr(iData ? "IDS_NET_CLIENT_READY" : "IDS_NET_CLIENT_UNREADY"), strClient.getData(), pClient->getName());
923  }
924  // Also update icons
926  if (lobby) lobby->OnClientReadyStateChange();
927  }
928  break;
929  }
930  }
931  // Update console net menu to reflect activation/etc.
933 }
934 
936 {
937  pComp->Value(mkNamingAdapt(mkIntAdaptT<uint8_t>(eType), "Type", CUT_None));
938  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iID), "ClientID", C4ClientIDUnknown));
939  if (eType == CUT_Activate)
940  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iData), "Data", 0));
941  if (eType == CUT_SetReady)
942  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iData), "Data", 0));
944 }
945 
946 // *** C4ControlClientRemove
947 
949 {
950  // host only
951  if (iByClient != C4ClientIDHost) return;
952  if (iID == C4ClientIDHost) return;
953  // find client
954  C4Client *pClient = Game.Clients.getClientByID(iID);
955  if (!pClient)
956  {
957  // TODO: in replays, client list is not yet synchronized
958  // remove players anyway
959  if (::Control.isReplay()) ::Players.RemoveAtClient(iID, true);
960  return;
961  }
962  StdCopyStrBuf strClient(LoadResStr(pClient->isLocal() ? "IDS_NET_LOCAL_CLIENT" : "IDS_NET_CLIENT"));
963  // local?
964  if (pClient->isLocal())
965  {
966  StdStrBuf sMsg;
967  sMsg.Format(LoadResStr("IDS_NET_CLIENT_REMOVED"), strClient.getData(), pClient->getName(), strReason.getData());
968  Log(sMsg.getData());
971  return;
972  }
973  // remove client
974  if (!Game.Clients.Remove(pClient)) return;
975  // log
976  LogF(LoadResStr("IDS_NET_CLIENT_REMOVED"), strClient.getData(), pClient->getName(), strReason.getData());
977  // remove all players
979  // remove all resources
980  if (::Network.isEnabled())
982  // lobby callback
984  if (pLobby && ::pGUI) pLobby->OnClientPart(pClient);
985  // player list callback
986  ::Network.Players.OnClientPart(pClient);
987  // console callback
989 
990  // delete
991  delete pClient;
992 }
993 
995 {
996  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iID), "ClientID", CUT_None));
997  pComp->Value(mkNamingAdapt(strReason, "Reason", ""));
999 }
1000 
1001 // *** C4ControlJoinPlayer
1002 
1003 C4ControlJoinPlayer::C4ControlJoinPlayer(const char *szFilename, int32_t iAtClient, int32_t iIDInfo, C4Network2ResCore ResCore)
1004  : Filename(szFilename, true), iAtClient(iAtClient),
1005  idInfo(iIDInfo), fByRes(true), ResCore(std::move(ResCore))
1006 {
1007 }
1008 
1009 C4ControlJoinPlayer::C4ControlJoinPlayer(const char *szFilename, int32_t iAtClient, int32_t iIDInfo)
1010  : Filename(szFilename, true), iAtClient(iAtClient),
1011  idInfo(iIDInfo)
1012 {
1013  // load from file if filename is given - which may not be the case for script players
1014  StdStrBuf filename;
1015  if (szFilename && Reloc.LocateItem(szFilename, filename))
1016  {
1017  bool file_is_temp = false;
1018  if (DirectoryExists(filename.getData()))
1019  {
1020  // the player file is unpacked - temp pack and read
1021  StdStrBuf filename_buf;
1022  filename_buf.Copy(Config.AtTempPath(GetFilenameOnly(filename.getData())));
1023  MakeTempFilename(&filename_buf);
1024  if (C4Group_PackDirectoryTo(filename.getData(), filename_buf.getData()))
1025  {
1026  filename.Take(filename_buf);
1027  file_is_temp = true;
1028  }
1029  else
1030  {
1031  // pack failed
1032  LogF("[!]Error packing player file %s to %s for join: Pack failed.", filename.getData(), filename_buf.getData());
1033  assert(false);
1034  }
1035  }
1036  bool fSuccess = PlrData.LoadFromFile(filename.getData());
1037  if (!fSuccess)
1038  {
1039  LogF("[!]Error loading player file from %s.", filename.getData());
1040  assert(false);
1041  }
1042  if (file_is_temp) EraseFile(filename.getData());
1043  }
1044  else if(szFilename)
1045  {
1046  LogF("[!]Error loading player file from %s.", szFilename);
1047  assert(false);
1048  }
1049 }
1050 
1051 void C4ControlJoinPlayer::Execute() const
1052 {
1053  const char *szFilename = Filename.getData();
1054 
1055  // get client
1057  if (pClient)
1058  {
1059  // get info
1061  if (!pInfo)
1062  {
1063  LogF("ERROR: Ghost player join: No info for %d", idInfo);
1064  assert(false);
1065  }
1066  else if (LocalControl())
1067  {
1068  // Local player: Just join from local file
1069  Game.JoinPlayer(szFilename, iAtClient, pClient->getName(), pInfo);
1070  }
1071  else if (!fByRes)
1072  {
1073  if (PlrData.getSize())
1074  {
1075  // create temp file
1076  StdStrBuf PlayerFilename; PlayerFilename.Format("%s-%s", pClient->getName(), GetFilename(szFilename));
1077  PlayerFilename = Config.AtTempPath(PlayerFilename.getData());
1078  // copy to it
1079  if (PlrData.SaveToFile(PlayerFilename.getData()))
1080  {
1081  Game.JoinPlayer(PlayerFilename.getData(), iAtClient, pClient->getName(), pInfo);
1082  EraseFile(PlayerFilename.getData());
1083  }
1084  }
1085  else if (pInfo->GetType() == C4PT_Script)
1086  {
1087  // script players may join without data
1088  Game.JoinPlayer(nullptr, iAtClient, pClient->getName(), pInfo);
1089  }
1090  else
1091  {
1092  // no player data for user player present: Must not happen
1093  LogF("ERROR: Ghost player join: No player data for %s", (const char*)pInfo->GetName());
1094  assert(false);
1095  }
1096  }
1097  else if (::Control.isNetwork())
1098  {
1099  // Find resource
1101  if (pRes && pRes->isComplete())
1102  Game.JoinPlayer(pRes->getFile(), iAtClient, pClient->getName(), pInfo);
1103  }
1104  else if (::Control.isReplay())
1105  {
1106  // Expect player in scenario file
1107  StdStrBuf PlayerFilename; PlayerFilename.Format("%s" DirSep "%d-%s", Game.ScenarioFilename, ResCore.getID(), GetFilename(ResCore.getFileName()));
1108  Game.JoinPlayer(PlayerFilename.getData(), iAtClient, pClient ? pClient->getName() : "Unknown", pInfo);
1109  }
1110  else
1111  {
1112  // Shouldn't happen
1113  assert(false);
1114  }
1115  }
1116  // After last of the initial player joins, do a game callback
1118 }
1119 
1121 {
1122  // By resource? Can't touch player file, then.
1123  if (fByRes) return;
1124  // create temp file
1125  StdStrBuf PlayerFilename; PlayerFilename = GetFilename(Filename.getData());
1126  PlayerFilename = Config.AtTempPath(PlayerFilename.getData());
1127  // Copy to it
1128  if (PlrData.SaveToFile(PlayerFilename.getData()))
1129  {
1130  // open as group
1131  C4Group Grp;
1132  if (!Grp.Open(PlayerFilename.getData()))
1133  { EraseFile(PlayerFilename.getData()); return; }
1134  // remove bigicon, if the file size is too large
1135  size_t iBigIconSize=0;
1136  if (Grp.FindEntry(C4CFN_BigIcon, nullptr, &iBigIconSize))
1137  if (iBigIconSize > C4NetResMaxBigicon*1024)
1138  Grp.Delete(C4CFN_BigIcon);
1139  Grp.Close();
1140  // Set new data
1141  StdBuf NewPlrData;
1142  if (!NewPlrData.LoadFromFile(PlayerFilename.getData()))
1143  { EraseFile(PlayerFilename.getData()); return; }
1144  PlrData = std::move(NewPlrData);
1145  // Done
1146  EraseFile(PlayerFilename.getData());
1147  }
1148 }
1149 
1151 {
1152  // all data included in control packet?
1153  if (!fByRes) return true;
1154  // client lost?
1155  if (!Game.Clients.getClientByID(iAtClient)) return true;
1156  // network only
1157  if (!::Control.isNetwork()) return true;
1158  // search resource
1160  // doesn't exist? start loading
1161  if (!pRes) { pRes = ::Network.ResList.AddByCore(ResCore, true); }
1162  if (!pRes) return true;
1163  // is loading or removed?
1164  return !pRes->isLoading();
1165 }
1166 
1168 {
1169  if (!pRecord) return;
1170  if (fByRes)
1171  {
1172  // get local file by id
1174  if (!pRes || pRes->isRemoved()) return;
1175  // create a copy of the resource
1176  StdStrBuf szTemp; szTemp.Copy(pRes->getFile());
1177  MakeTempFilename(&szTemp);
1178  if (C4Group_CopyItem(pRes->getFile(), szTemp.getData()))
1179  {
1180  // add to record
1181  StdStrBuf szTarget = FormatString("%d-%s", ResCore.getID(), GetFilename(ResCore.getFileName()));
1182  pRecord->AddFile(szTemp.getData(), szTarget.getData(), true);
1183  }
1184  }
1185  else
1186  {
1187  // player data raw within control: Will be used directly in record
1188  }
1189 }
1190 
1192 {
1193  pComp->Value(mkNamingAdapt(mkNetFilenameAdapt(Filename), "Filename", ""));
1194  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iAtClient), "AtClient", -1));
1195  pComp->Value(mkNamingAdapt(mkIntPackAdapt(idInfo), "InfoID", -1));
1196  pComp->Value(mkNamingAdapt(fByRes, "ByRes", false));
1197  if (fByRes)
1198  pComp->Value(mkNamingAdapt(ResCore, "ResCore"));
1199  else
1200  pComp->Value(mkNamingAdapt(PlrData, "PlrData"));
1202 }
1203 
1204 // *** C4ControlEMMoveObject
1205 
1207  int32_t iObjectNum, int32_t *pObjects, const char *szScript, bool drag_finished)
1208  : eAction(eAction), tx(tx), ty(ty), iTargetObj(pTargetObj ? pTargetObj->Number : 0),
1209  iObjectNum(iObjectNum), pObjects(pObjects), StringParam(szScript, true), drag_finished(drag_finished)
1210 {
1211 
1212 }
1213 
1215 {
1216 #ifdef WITH_QT_EDITOR
1217  ::StartSoundEffect("UI::Click2");
1218 #endif
1219  auto ctl = new C4ControlEMMoveObject(EMMO_Create, x, y, container);
1220  ctl->StringParam = id.ToString();
1221  return ctl;
1222 }
1223 
1225 {
1226  delete [] pObjects; pObjects = nullptr;
1227 }
1228 
1229 void C4ControlEMMoveObject::MoveObject(C4Object *moved_object, bool move_forced) const
1230 {
1231  // move given object by this->tx/ty and do callbacks
1232  if (!moved_object || !moved_object->Status) return;
1233  int32_t old_x = moved_object->GetX(), old_y = moved_object->GetY();
1234  C4Real tx = this->tx;
1235  if (moved_object->Def->NoHorizontalMove && !move_forced) tx = Fix0;
1236  moved_object->ForcePosition(moved_object->fix_x + tx, moved_object->fix_y + ty);
1237  moved_object->xdir = moved_object->ydir = 0;
1238  moved_object->Mobile = false;
1239  C4AulParSet pars(C4VInt(old_x), C4VInt(old_y), C4VBool(drag_finished));
1240  if (moved_object->Call(PSF_EditCursorMoved, &pars))
1241  {
1243  }
1244 }
1245 
1246 void C4ControlEMMoveObject::Execute() const
1247 {
1248  bool fLocalCall = LocalControl();
1249  switch (eAction)
1250  {
1251  case EMMO_Move:
1252  case EMMO_MoveForced:
1253  {
1254  if (!pObjects) break;
1255  // move all given objects
1256  C4Object *pObj;
1257  for (int i=0; i<iObjectNum; ++i)
1258  if ((pObj = ::Objects.SafeObjectPointer(pObjects[i])))
1259  if (pObj->Status)
1260  {
1261  MoveObject(pObj, eAction == EMMO_MoveForced);
1262  // attached objects: Also move attachment target
1263  while (pObj->GetProcedure() == DFA_ATTACH)
1264  {
1265  pObj = pObj->Action.Target;
1266  if (!pObj) break; // leftover action cancelled next frame
1267  for (int j = 0; j < iObjectNum; ++j) if (pObjects[j] == pObj->Number) { pObj = nullptr; break; } // ensure we aren't moving twice
1268  if (!pObj) break;
1269  MoveObject(pObj, eAction==EMMO_MoveForced);
1270  }
1271  }
1272  }
1273  break;
1274  case EMMO_Enter:
1275  {
1276  if (!pObjects) break;
1277  // enter all given objects into target
1278  C4Object *pObj, *pTarget = ::Objects.SafeObjectPointer(iTargetObj);
1279  if (pTarget)
1280  for (int i=0; i<iObjectNum; ++i)
1281  if ((pObj = ::Objects.SafeObjectPointer(pObjects[i])))
1282  {
1283  pObj->Enter(pTarget);
1284  if (!pTarget->Status) break;
1285  C4AulParSet pars(C4VObj(pObj));
1286  if (pObj && pObj->Status && pTarget->Status) pTarget->Call(P_EditorCollection, &pars);
1287  if (!pTarget->Status) break;
1288  }
1289  }
1290  break;
1291  case EMMO_Duplicate:
1292  {
1293  if (!pObjects) break;
1294  // perform duplication
1295  ::Console.EditCursor.PerformDuplication(pObjects, iObjectNum, fLocalCall);
1296  }
1297  break;
1298  case EMMO_Script:
1299  {
1300  if (!pObjects) return;
1301  // execute script ...
1303  ScriptCtrl.SetByClient(iByClient);
1304  // ... for each object in selection
1305  for (int i=0; i<iObjectNum; ++i)
1306  {
1307  ScriptCtrl.SetTargetObj(pObjects[i]);
1308  ScriptCtrl.Execute();
1309  }
1310  }
1311  break;
1312  case EMMO_Remove:
1313  {
1314  if (!pObjects) return;
1315  // remove all objects
1316  C4Object *pObj;
1317  for (int i=0; i<iObjectNum; ++i)
1318  if ((pObj = ::Objects.SafeObjectPointer(pObjects[i])))
1319  pObj->AssignRemoval();
1320  }
1321  break;
1322  case EMMO_Exit:
1323  {
1324  if (!pObjects) return;
1325  // exit all objects
1326  C4Object *pObj;
1327  for (int i=0; i<iObjectNum; ++i)
1328  if ((pObj = ::Objects.SafeObjectPointer(pObjects[i])))
1329  pObj->Exit(pObj->GetX(), pObj->GetY(), pObj->GetR());
1330  }
1331  break;
1332  case EMMO_Create:
1333  {
1334  // Check max object count
1335  C4ID iddef = C4ID(StringParam);
1336  C4Def *def = C4Id2Def(iddef);
1337  if (!def) return;
1338  int32_t placement_limit = def->GetPropertyInt(P_EditorPlacementLimit);
1339  if (placement_limit)
1340  {
1341  if (Game.ObjectCount(iddef) >= placement_limit)
1342  {
1343  // Too many objects
1344  ::Console.Message(FormatString(LoadResStr("IDS_CNS_CREATORTOOMANYINSTANCES"), int(placement_limit)).getData());
1345  return;
1346  }
1347  }
1348  // Create object outside or contained
1349  // If container is desired but not valid, do nothing (don't create object outside instead)
1350  C4Object *container = nullptr;
1351  if (iTargetObj)
1352  {
1353  container = ::Objects.SafeObjectPointer(iTargetObj);
1354  if (!container || !container->Status) return;
1355  }
1356  bool create_centered = false;
1357 #ifdef WITH_QT_EDITOR
1358  // Qt editor: Object creation is done through creator; centered creation is usually more convenient
1359  create_centered = true;
1360 #endif
1361  C4Object *obj = ::Game.CreateObject(iddef, nullptr, NO_OWNER, fixtoi(tx), fixtoi(ty), 0, create_centered);
1362  if (container && obj && container->Status && obj->Status)
1363  {
1364  obj->Enter(container);
1365  C4AulParSet pars(C4VObj(obj));
1366  if (obj && obj->Status) container->Call(P_EditorCollection, &pars);
1367  }
1368  if (obj && obj->Status) obj->Call(P_EditorInitialize); // specific initialization when placed in editor
1369  }
1370  break;
1371  case EMMO_Transform:
1372  {
1374  if (pTarget)
1375  {
1376  int32_t new_rot = fixtoi(this->tx, 1);
1377  int32_t new_con = fixtoi(this->ty, FullCon/100);
1378  if (pTarget->Def->Rotateable) pTarget->SetRotation(new_rot);
1379  if (pTarget->Def->GrowthType) pTarget->DoCon(new_con - pTarget->GetCon(), false);
1380  }
1381  }
1382  }
1383  // update property dlg & status bar
1384  if (fLocalCall && eAction != EMMO_Move && eAction != EMMO_MoveForced)
1386 }
1387 
1389 {
1390  pComp->Value(mkNamingAdapt(mkIntAdaptT<uint8_t>(eAction), "Action"));
1391  pComp->Value(mkNamingAdapt(tx, "tx", 0));
1392  pComp->Value(mkNamingAdapt(ty, "ty", 0));
1393  pComp->Value(mkNamingAdapt(iTargetObj, "TargetObj", -1));
1394  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iObjectNum), "ObjectNum", 0));
1395  if (pComp->isDeserializer()) { delete [] pObjects; pObjects = new int32_t [iObjectNum]; }
1396  pComp->Value(mkNamingAdapt(mkArrayAdapt(pObjects, iObjectNum), "Objs", -1));
1397  if (eAction == EMMO_Script)
1398  pComp->Value(mkNamingAdapt(StringParam, "Script", ""));
1399  else if (eAction == EMMO_Create)
1400  pComp->Value(mkNamingAdapt(StringParam, "ID", ""));
1402 }
1403 
1404 // *** C4ControlEMDrawTool
1405 
1407  int32_t iX, int32_t iY, int32_t iX2, int32_t iY2, int32_t iGrade,
1408  const char *szMaterial, const char *szTexture, const char *szBackMaterial, const char *szBackTexture)
1409  : eAction(eAction), iMode(iMode), iX(iX), iY(iY), iX2(iX2), iY2(iY2), iGrade(iGrade),
1410  Material(szMaterial, true), Texture(szTexture, true),
1411  BackMaterial(szBackMaterial, true), BackTexture(szBackTexture, true)
1412 {
1413 
1414 }
1415 
1416 void C4ControlEMDrawTool::Execute() const
1417 {
1418  // set new mode
1419  if (eAction == EMDT_SetMode)
1420  {
1422  return;
1423  }
1424  // check current mode
1425  assert(::Landscape.GetMode() == iMode);
1426  if (::Landscape.GetMode() != iMode) return;
1427  // assert validity of parameters
1428  if (!Material.getSize()) return;
1429  const char *szMaterial = Material.getData(),
1430  *szTexture = Texture.getData();
1431  const char *szBackMaterial = BackMaterial.getData(),
1432  *szBackTexture = BackTexture.getData();
1433  // perform action
1434  switch (eAction)
1435  {
1436  case EMDT_Brush: // brush tool
1437  if (!Texture.getSize()) break;
1438  ::Landscape.DrawBrush(iX, iY, iGrade, szMaterial, szTexture, szBackMaterial, szBackTexture);
1439  break;
1440  case EMDT_Line: // line tool
1441  if (!Texture.getSize()) break;
1442  ::Landscape.DrawLine(iX,iY,iX2,iY2, iGrade, szMaterial, szTexture, szBackMaterial, szBackTexture);
1443  break;
1444  case EMDT_Rect: // rect tool
1445  if (!Texture.getSize()) break;
1446  ::Landscape.DrawBox(iX,iY,iX2,iY2, iGrade, szMaterial, szTexture, szBackMaterial, szBackTexture);
1447  break;
1448  case EMDT_Fill: // fill tool
1449  {
1450  int iMat = ::MaterialMap.Get(szMaterial);
1451  if (!MatValid(iMat)) return;
1452  for (int cnt=0; cnt<iGrade; cnt++)
1453  {
1454  int32_t itX=iX+Random(iGrade)-iGrade/2;
1455  int32_t itY=iY+Random(iGrade)-iGrade/2;
1456  ::Landscape.InsertMaterial(iMat,&itX,&itY);
1457  }
1458  }
1459  break;
1460  default:
1461  break;
1462  }
1463 }
1464 
1465 
1467 {
1468  pComp->Value(mkNamingAdapt(mkIntAdaptT<uint8_t>(eAction), "Action"));
1469  pComp->Value(mkNamingAdapt(mkIntAdaptT<uint8_t>(iMode), "Mode", LandscapeMode::Undefined));
1470  pComp->Value(mkNamingAdapt(iX, "X", 0));
1471  pComp->Value(mkNamingAdapt(iY, "Y", 0));
1472  pComp->Value(mkNamingAdapt(iX2, "X2", 0));
1473  pComp->Value(mkNamingAdapt(iY2, "Y2", 0));
1474  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iGrade), "Grade", 0));
1475  pComp->Value(mkNamingAdapt(Material, "Material", ""));
1476  pComp->Value(mkNamingAdapt(Texture, "Texture", ""));
1477  pComp->Value(mkNamingAdapt(BackMaterial, "BackMaterial", ""));
1478  pComp->Value(mkNamingAdapt(BackTexture, "BackTexture", ""));
1480 }
1481 
1482 // *** C4ControlMessage
1483 
1484 void C4ControlMessage::Execute() const
1485 {
1486  const char *szMessage = Message.getData();
1487  // get player
1488  C4Player *pPlr = (iPlayer < 0 ? nullptr : ::Players.Get(iPlayer));
1489  // security
1490  if (pPlr && pPlr->AtClient != iByClient) return;
1491  // do not record message as control, because it is not synced!
1492  // get lobby to forward to
1494  StdStrBuf str;
1495  switch (eType)
1496  {
1497  case C4CMT_Normal:
1498  case C4CMT_Me:
1499  // log it
1500  if (pPlr)
1501  {
1502  if (pPlr->AtClient != iByClient) break;
1503  str.Format((eType == C4CMT_Normal ? "<c %x><<i></i>%s> %s</c>" : "<c %x> * %s %s</c>"),
1504  pPlr->ColorDw, pPlr->GetName(), szMessage);
1505  }
1506  else
1507  {
1509  str.Format((eType == C4CMT_Normal ? "<%s> %s" : " * %s %s"),
1510  pClient ? pClient->getNick() : "???", szMessage);
1511  }
1512  // to lobby
1513  if (pLobby)
1515 #ifndef USE_CONSOLE
1516  else
1517 #endif
1518  // to log
1519  Log(str.getData());
1520  break;
1521 
1522  case C4CMT_Say:
1523  // show as game message above player cursor
1524  if (pPlr && pPlr->Cursor)
1525  {
1527  {
1528  StdStrBuf sMessage; sMessage.Format("<%s> %s", pPlr->Cursor->GetName(), szMessage);
1529  uint32_t dwClr = pPlr->Cursor->Color;
1530  if (!dwClr) dwClr = 0xff;
1531  GameMsgObjectDw(sMessage.getData(), pPlr->Cursor, dwClr|0xff000000);
1532  }
1533  else
1534  GameMsgObjectDw(szMessage, pPlr->Cursor, pPlr->ColorDw|0xff000000);
1535  }
1536  break;
1537 
1538  case C4CMT_Team:
1539  {
1540  // show only if sending player is allied with a local one
1541  if (pPlr)
1542  {
1543  // for running game mode, check actual hostility
1544  C4Player *pLocalPlr;
1545  for (int cnt = 0; (pLocalPlr = ::Players.GetLocalByIndex(cnt)); cnt++)
1546  if (!Hostile(pLocalPlr->Number, iPlayer))
1547  break;
1548  if (pLocalPlr) Log(FormatString("<c %x>{%s} %s</c>", pPlr->ColorDw, pPlr->GetName(), szMessage).getData());
1549  }
1550  else if (pLobby)
1551  {
1552  // in lobby mode, no player has joined yet - check teams of unjoined players
1554  // OK - permit message
1557  FormatString("{%s} %s", pClient ? pClient->getNick() : "???", szMessage).getData());
1558  }
1559  }
1560  break;
1561 
1562  case C4CMT_Private:
1563  {
1564  if (!pPlr) break;
1565  // show only if the target player is local
1566  C4Player *pLocalPlr;
1567  for (int cnt = 0; (pLocalPlr = ::Players.GetLocalByIndex(cnt)); cnt++)
1568  if (pLocalPlr->ID == iToPlayer)
1569  break;
1570  if (pLocalPlr)
1571  {
1572  Log(FormatString("<c %x>[%s] %s</c>", pPlr->ColorDw, pPlr->GetName(), szMessage).getData());
1573  }
1574  }
1575  break;
1576 
1577  case C4CMT_Sound:
1578  {
1579  // tehehe, sound!
1581  if (!singer || !singer->IsIgnored())
1582  if (!StartSoundEffect(szMessage, false, 100, nullptr))
1583  // probably wrong sound file name
1584  break;
1585  // Sound icon even if someone you ignored just tried. So you know you still need to ignore.
1586  if (pLobby) pLobby->OnClientSound(singer);
1588  break;
1589  }
1590 
1591  case C4CMT_Alert:
1592  // notify inactive users
1594  break;
1595 
1596  case C4CMT_System:
1597  // sender must be host
1598  if (!HostControl()) break;
1599  // show
1600  LogF("Network: %s", szMessage);
1601  break;
1602 
1603  }
1604 }
1605 
1607 {
1608  pComp->Value(mkNamingAdapt(mkIntAdaptT<uint8_t>(eType), "Type", C4CMT_Normal));
1609  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iPlayer), "Player", -1));
1610  if (eType == C4CMT_Private)
1611  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iToPlayer), "ToPlayer", -1));
1612  pComp->Value(mkNamingAdapt(Message, "Message", ""));
1614 }
1615 
1616 // *** C4ControlPlayerInfo
1617 
1618 void C4ControlPlayerInfo::Execute() const
1619 {
1620  // join to player info list
1621  // replay and local control: direct join
1622  if (::Control.isReplay() || !::Control.isNetwork())
1623  {
1624  // add info directly
1626  // make sure team list reflects teams set in player infos
1628  // replay: actual player join packet will follow
1629  // offline game: Issue the join
1630  if (::Control.isLocal())
1632  }
1633  else
1634  // network:
1636 }
1637 
1639 {
1640  pComp->Value(PlrInfo);
1642 }
1643 
1644 // *** C4ControlRemovePlr
1645 
1646 void C4ControlRemovePlr::Execute() const
1647 {
1648  // host only
1649  if (iByClient != C4ClientIDHost) return;
1650  // remove
1652 }
1653 
1655 {
1656  pComp->Value(mkNamingAdapt(mkIntPackAdapt(iPlr), "Plr", -1));
1657  pComp->Value(mkNamingAdapt(fDisconnected, "Disconnected", false));
1659 }
1660 
1661 // *** C4ControlDebugRec
1662 
1663 void C4ControlDebugRec::Execute() const
1664 {
1665 
1666 }
1667 
1669 {
1670  pComp->Value(Data);
1671 }
1672 
1673 // *** C4ControlVote
1674 
1676 {
1677  // Describe action
1678  StdStrBuf Action;
1679  switch (eType)
1680  {
1681  case VT_Cancel:
1682  Action = LoadResStr("IDS_VOTE_CANCELTHEROUND"); break;
1683  case VT_Kick:
1684  if (iData == iByClient)
1685  Action = LoadResStr("IDS_VOTE_LEAVETHEGAME");
1686  else
1687  {
1688  C4Client *pTargetClient = Game.Clients.getClientByID(iData);
1689  Action.Format(LoadResStr("IDS_VOTE_KICKCLIENT"), pTargetClient ? pTargetClient->getName() : "???");
1690  }
1691  break;
1692  case VT_Pause:
1693  if (iData)
1694  Action = LoadResStr("IDS_TEXT_PAUSETHEGAME");
1695  else
1696  Action = LoadResStr("IDS_TEXT_UNPAUSETHEGAME");
1697  break;
1698  default:
1699  Action = "perform some mysterious action"; break;
1700  }
1701  return Action;
1702 }
1703 
1705 {
1706  StdStrBuf Warning;
1707  switch (eType)
1708  {
1709  case VT_Cancel:
1710  Warning = LoadResStr("IDS_TEXT_WARNINGIFTHEGAMEISCANCELL"); break;
1711  case VT_Kick:
1712  Warning = LoadResStr("IDS_TEXT_WARNINGNOLEAGUEPOINTSWILL"); break;
1713  default:
1714  Warning = ""; break;
1715  }
1716  return Warning;
1717 }
1718 
1719 void C4ControlVote::Execute() const
1720 {
1721  // Log
1723  if (fApprove)
1724  LogF(LoadResStr("IDS_VOTE_WANTSTO"), pClient->getName(), getDesc().getData());
1725  else
1726  LogF(LoadResStr("IDS_VOTE_DOESNOTWANTTO"), pClient->getName(), getDesc().getData());
1727  // Save vote back
1728  if (::Network.isEnabled())
1729  ::Network.AddVote(*this);
1730  // Vote done?
1731  if (::Control.isCtrlHost())
1732  {
1733  // Count votes
1734  int32_t iPositive = 0, iNegative = 0, iVotes = 0;
1735  // If there are no teams, count as if all were in the same team
1736  // (which happens to be equivalent to "everyone is in his own team" here)
1737  for (int32_t i = 0; i < std::max<int32_t>(Game.Teams.GetTeamCount(), 1); i++)
1738  {
1739  C4Team *pTeam = Game.Teams.GetTeamByIndex(i);
1740  // Votes for this team
1741  int32_t iPositiveTeam = 0, iNegativeTeam = 0, iVotesTeam = 0;
1742  // Check each player
1743  for (int32_t j = 0; j < (pTeam ? pTeam->GetPlayerCount() : Game.PlayerInfos.GetPlayerCount()); j++)
1744  {
1745  int32_t iClientID = C4ClientIDUnknown;
1746  C4PlayerInfo *pNfo;
1747  if (!pTeam)
1748  {
1750  if (!pNfo) continue; // shouldn't happen
1751  iClientID = Game.PlayerInfos.GetClientInfoByPlayerID(pNfo->GetID())->GetClientID();
1752  }
1753  else
1754  {
1755  pNfo = Game.PlayerInfos.GetPlayerInfoByID(pTeam->GetIndexedPlayer(j), &iClientID);
1756  if (!pNfo) continue; // shouldn't happen
1757  }
1758  if (iClientID < 0) continue;
1759  // Client disconnected?
1760  if (!Game.Clients.getClientByID(iClientID)) continue;
1761  // Player eliminated or never joined?
1762  if (!pNfo->IsJoined()) continue;
1763  // Okay, this player can vote
1764  iVotesTeam++;
1765  // Search vote of this client on the subject
1766  C4IDPacket *pPkt; C4ControlVote *pVote;
1767  if ((pPkt = ::Network.GetVote(iClientID, eType, iData)))
1768  if ((pVote = static_cast<C4ControlVote *>(pPkt->getPkt())))
1769  {
1770  if (pVote->isApprove())
1771  iPositiveTeam++;
1772  else
1773  iNegativeTeam++;
1774  }
1775  }
1776  // Any votes available?
1777  if (iVotesTeam)
1778  {
1779  iVotes++;
1780  // Approval by team? More then 50% needed
1781  if (iPositiveTeam * 2 > iVotesTeam)
1782  iPositive++;
1783  // Disapproval by team? More then 50% needed
1784  else if (iNegativeTeam * 2 >= iVotesTeam)
1785  iNegative++;
1786  }
1787  }
1788  // Approval? More then 50% needed
1789  if (iPositive * 2 > iVotes)
1791  new C4ControlVoteEnd(eType, true, iData),
1792  CDT_Sync);
1793  // Disapproval?
1794  else if (iNegative * 2 >= iVotes)
1796  new C4ControlVoteEnd(eType, false, iData),
1797  CDT_Sync);
1798  }
1799 }
1800 
1802 {
1803  pComp->Value(mkNamingAdapt(mkIntAdaptT<uint8_t>(eType), "Type", VT_None));
1804  pComp->Value(mkNamingAdapt(fApprove, "Approve", true));
1805  pComp->Value(mkNamingAdapt(iData, "Data", 0));
1807 }
1808 
1809 // *** C4ControlVoteEnd
1810 
1811 void C4ControlVoteEnd::Execute() const
1812 {
1813  // End the voting process
1814  if (!HostControl()) return;
1815  if (::Network.isEnabled())
1817  // Log
1818  StdStrBuf sMsg;
1819  if (isApprove())
1820  sMsg.Format(LoadResStr("IDS_TEXT_ITWASDECIDEDTO"), getDesc().getData());
1821  else
1822  sMsg.Format(LoadResStr("IDS_TEXT_ITWASDECIDEDNOTTO"), getDesc().getData());
1823  Log(sMsg.getData());
1824  // Approved?
1825  if (!isApprove()) return;
1826  // Do it
1827  C4ClientPlayerInfos *pInfos; C4PlayerInfo *pInfo;
1828  int iClient, iInfo;
1829  switch (getType())
1830  {
1831  case VT_Cancel:
1832  // Flag players
1833  if (!Game.GameOver)
1834  for (iClient = 0; (pInfos = Game.PlayerInfos.GetIndexedInfo(iClient)); iClient++)
1835  for (iInfo = 0; (pInfo = pInfos->GetPlayerInfo(iInfo)); iInfo++)
1836  if (!pInfo->IsRemoved())
1837  pInfo->SetVotedOut();
1838  // Abort the game
1839  Game.Abort(true);
1840  break;
1841  case VT_Kick:
1842  // Flag players
1844  if (!Game.GameOver)
1845  if (pInfos)
1846  for (iInfo = 0; (pInfo = pInfos->GetPlayerInfo(iInfo)); iInfo++)
1847  if (!pInfo->IsRemoved())
1848  pInfo->SetVotedOut();
1849  // Remove the client
1850  if (::Control.isCtrlHost())
1851  {
1852  C4Client *pClient = Game.Clients.getClientByID(getData());
1853  if (pClient)
1854  Game.Clients.CtrlRemove(pClient, LoadResStr("IDS_VOTE_VOTEDOUT"));
1855  }
1856  // It is ourselves that have been voted out?
1857  if (getData() == Game.Clients.getLocalID())
1858  {
1859  // otherwise, we have been kicked by the host.
1860  // Do a regular disconnect and display reason in game over dialog, so the client knows what has happened!
1861  Game.RoundResults.EvaluateNetwork(C4RoundResults::NR_NetError, FormatString(LoadResStr("IDS_ERR_YOUHAVEBEENREMOVEDBYVOTIN"), sMsg.getData()).getData());
1862  ::Network.Clear();
1863  // Game over immediately, so poor player won't continue game alone
1864  Game.DoGameOver();
1865  }
1866  break;
1867  default:
1868  // TODO
1869  break;
1870  }
1871 }
1872 
1874 {
1876 }
1877 
1878 
1879 // *** C4ControlReInitScenario
1880 
1882 {
1883  // Create a temp file with the scenario files to be loaded as a section
1884  char *tmp_fn = const_cast<char *>(Config.AtTempPath("ReinitSectionSave.ocs"));
1885  MakeTempFilename(tmp_fn);
1886  C4Group grp;
1887  grp.Open(tmp_fn, true);
1888  StdBuf buf;
1889  bool success = true;
1891  for (const char *section_component : section_components)
1892  {
1893  if (::Game.ScenarioFile.LoadEntry(section_component, &buf))
1894  {
1895  if (!grp.Add(section_component, buf, false, true)) success = false;
1896  }
1897  buf.Clear();
1898  }
1899  if (!grp.Save(false)) success = false;
1900  if (!success) return;
1901  // Move into buffer to be sent via queue
1902  success = data.LoadFromFile(tmp_fn);
1903  EraseFile(tmp_fn);
1904  if (!success) return;
1905 }
1906 
1908 {
1909  comp->Value(data);
1910 }
1911 
1913 {
1914  // Valid?
1915  if (!data.getSize()) return;
1916  // Store section group to temp file
1917  char *tmp_fn = const_cast<char *>(Config.AtTempPath("ReinitSection.ocs"));
1918  MakeTempFilename(tmp_fn);
1919  if (!data.SaveToFile(tmp_fn)) return;
1920  // Group to section
1921  const char *reinit_section_name = "EditorReloadSection";
1922  if (!::Game.CreateSectionFromTempFile(reinit_section_name, tmp_fn))
1923  {
1924  EraseFile(tmp_fn);
1925  return;
1926  }
1927  // Load that section!
1928  ::Game.LoadScenarioSection(reinit_section_name, C4S_REINIT_SCENARIO);
1929 }
1930 
1932 {
1933  comp->Value(mkNamingAdapt(path, "Path", StdCopyStrBuf()));
1934  comp->Value(mkNamingAdapt(mkIntAdaptT<uint8_t>(action), "Action", CEG_None));
1935  comp->Value(mkNamingAdapt(index, "Index", -1));
1936  comp->Value(mkNamingAdapt(x, "x", 0));
1937  comp->Value(mkNamingAdapt(y, "y", 0));
1939 }
1940 
1941 void C4ControlEditGraph::Execute() const
1942 {
1943  // Forward to console for execution
1945 }
char * GetFilename(char *szPath)
Definition: StdFile.cpp:45
const char * getData() const
Definition: StdBuf.h:442
StdStrBuf BackTexture
Definition: C4Control.h:500
bool DoGameOver()
Definition: C4Game.cpp:3095
const char * GetName() const
bool ExecuteCommand(int32_t actionID, int32_t player, int32_t subwindowID, int32_t actionType, C4Object *target)
C4EditCursor EditCursor
Definition: C4Console.h:90
#define PSF_EditCursorMoved
Definition: C4GameScript.h:98
int32_t GetPlayerCount() const
Definition: C4Teams.h:64
bool FindEntry(const char *szWildCard, StdStrBuf *sFileName=nullptr, size_t *iSize=nullptr)
Definition: C4Group.cpp:1774
int32_t GetY() const
Definition: C4Object.h:287
void RecheckPlayers()
Definition: C4Teams.cpp:663
void ExecuteControlPacket(const class C4ControlPlayerControl *pCtrl)
class C4GameLobby::MainDlg * GetLobby() const
Definition: C4Network2.h:216
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:119
C4IDPacket * firstPkt() const
Definition: C4Control.h:78
bool IsRunning
Definition: C4Game.h:139
bool DrawBox(int32_t iX1, int32_t iY1, int32_t iX2, int32_t iY2, int32_t iGrade, const char *szMaterial, const char *szTexture, const char *szBackMaterial, const char *szBackTexture)
bool CreateSectionFromTempFile(const char *section_name, const char *temp_filename)
Definition: C4Game.cpp:3425
C4ControlEMDrawTool()=default
void OnClientPart(C4Client *pPartClient)
int32_t iTargetObj
Definition: C4Control.h:137
char ScenarioFilename[_MAX_PATH+1]
Definition: C4Game.h:102
void SetByClient(int32_t iByClient)
Definition: C4Control.cpp:65
StdStrBuf Message
Definition: C4Control.h:527
C4Config Config
Definition: C4Config.cpp:833
C4ControlMessageType eType
Definition: C4Control.h:525
C4Network2Res::Ref AddByCore(const C4Network2ResCore &Core, bool fLoad=true)
const char * GetName() const
Definition: C4PlayerInfo.h:157
void GUISound(const char *szSound)
Definition: C4Gui.cpp:1175
Definition: StdBuf.h:29
bool Enter(C4Object *pTarget, bool fCalls=true, bool fCopyMotion=true, bool *pfRejectCollect=nullptr)
Definition: C4Object.cpp:1260
C4Network2ResCore ResCore
Definition: C4Control.h:432
C4Network2Client * GetClientByID(int32_t iID) const
void ForcePosition(C4Real tx, C4Real ty)
Definition: C4Movement.cpp:515
int32_t GetCon() const
Definition: C4Object.h:272
C4ObjectPtr Cursor
Definition: C4Player.h:130
uint32_t Random()
Definition: C4Random.cpp:43
void AddVote(const C4ControlVote &Vote)
int32_t ControlTick
Definition: C4GameControl.h:89
static int32_t GetAllCrewPosX()
Definition: C4Control.cpp:759
C4Console Console
Definition: C4Globals.cpp:45
Definition: StdAdaptors.h:762
C4PropListStatic * GetPropList()
Definition: C4Aul.h:151
C4MainMenu Menu
Definition: C4Player.h:103
static C4ControlPlayerAction * ActivateGoalMenu(const C4Player *source)
Definition: C4Control.cpp:580
void SyncClearance()
Definition: C4Game.cpp:3129
int32_t GetPlayerCount() const
bool isCtrlHost() const
Definition: C4GameControl.h:99
void PreRec(C4Record *pRecord) const
Definition: C4Control.cpp:128
C4Game Game
Definition: C4Globals.cpp:52
int32_t Number
Definition: C4Player.h:86
C4GameScriptHost GameScript
void PerformDuplication(int32_t *object_numbers, int32_t object_count, bool local_call)
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
C4Scenario C4S
Definition: C4Game.h:74
bool isLobbyReady() const
Definition: C4Client.h:112
Definition: C4Teams.h:30
void OnClientJoin(C4Client *pNewClient)
void EvaluateNetwork(NetResult eResult, const char *szResultsString)
C4ControlPlayerSelect()=default
bool isComplete() const
#define C4CFN_MapFg
Definition: C4Components.h:58
#define C4CFN_Map
Definition: C4Components.h:57
C4ToolsDlg ToolsDlg
Definition: C4Console.h:88
void OnPlayerJoinFinished()
Definition: C4Game.cpp:3080
#define C4S_REINIT_SCENARIO
Definition: C4Scenario.h:51
void Clear()
Definition: StdBuf.h:190
C4Value Call(const char *szFunction, C4AulParSet *pPars=nullptr, bool fPassError=false)
void Eliminate()
Definition: C4Player.cpp:1472
bool isLocal() const
Definition: C4GameControl.h:96
bool LoadFromFile(const char *szFile)
Definition: StdBuf.cpp:32
bool DrawLine(int32_t iX1, int32_t iY1, int32_t iX2, int32_t iY2, int32_t iGrade, const char *szMaterial, const char *szTexture, const char *szBackMaterial, const char *szBackTexture)
C4Value C4VInt(int32_t i)
Definition: C4Value.h:242
bool isActivated() const
Definition: C4Client.h:110
void Add(C4PacketType eType, C4ControlPacket *pCtrl)
Definition: C4Control.h:82
C4ControlJoinPlayer()=default
void SetLobbyReady(bool fnLobbyReady, time_t *time_since_last_change=nullptr)
Definition: C4Client.cpp:128
C4ControlEMDrawAction
Definition: C4Control.h:475
void UpdateNetMenu()
Definition: C4Console.cpp:542
C4PlayerInfo * GetPlayerInfoByIndex(int32_t index) const
int32_t ObjectCount(C4ID id)
Definition: C4Game.cpp:1289
int32_t iByClient
Definition: C4Control.h:39
bool LoadEntry(const char *szEntryName, char **lpbpBuf, size_t *ipSize=nullptr, int iAppendZeros=0)
Definition: C4Group.cpp:1893
C4Player * First
Definition: C4PlayerList.h:31
bool PreExecute() const
Definition: C4Control.cpp:90
LandscapeMode iMode
Definition: C4Control.h:495
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
bool isApprove() const
Definition: C4Control.h:581
C4MessageInput MessageInput
C4AulExec AulExec
Definition: C4AulExec.cpp:29
StdStrBuf Filename
Definition: C4Control.h:427
C4PlayerControl Control
Definition: C4Player.h:129
bool LoadScenarioSection(const char *szSection, DWORD dwFlags)
Definition: C4Game.cpp:3467
bool Delete(const char *szFiles, bool fRecursive=false)
Definition: C4Group.cpp:1334
int32_t ControlRate
Definition: C4Config.h:139
static C4ControlPlayerAction * SetHostility(const C4Player *source, const C4Player *target, bool hostile)
Definition: C4Control.cpp:587
C4PacketList Pkts
Definition: C4Control.h:71
C4Team * GetTeamByID(int32_t iID) const
Definition: C4Teams.cpp:383
bool InsertMaterial(int32_t mat, int32_t *tx, int32_t *ty, int32_t vx=0, int32_t vy=0, bool query_only=false)
static C4Network2ClientListDlg * GetInstance()
~C4Control() override
Definition: C4Control.cpp:80
const char * GetFilenameOnly(const char *strFilename)
Definition: StdFile.cpp:60
void UpdateMenus()
Definition: C4Console.cpp:504
void CtrlRemove(const C4Client *pClient, const char *szReason)
Definition: C4Client.cpp:333
const char * getFileName() const
Definition: C4Network2Res.h:94
C4GameParameters & Parameters
Definition: C4Game.h:67
C4Value C4VObj(C4Object *pObj)
Definition: C4Value.cpp:88
int32_t NoHorizontalMove
Definition: C4Def.h:122
C4Player * JoinPlayer(const char *szFilename, int32_t iAtClient, const char *szAtClientName, C4PlayerInfo *pInfo)
Definition: C4Game.cpp:3056
char Script[_MAX_FNAME+30+1]
C4ClientPlayerInfos * GetIndexedInfo(int32_t iIndex) const
Definition: C4PlayerInfo.h:358
C4PlayerInfo * GetPlayerInfoByID(int32_t id) const
size_t getSize() const
Definition: StdBuf.h:101
C4TeamList & Teams
Definition: C4Game.h:70
C4ClientPlayerInfos * GetClientInfoByPlayerID(int32_t id) const
C4ControlPlayerAction(const C4Player *source=nullptr)
Definition: C4Control.cpp:552
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
void RemoveAtClient(int32_t iClientID)
bool DrawBrush(int32_t iX, int32_t iY, int32_t iGrade, const char *szMaterial, const char *szTexture, const char *szBackMaterial, const char *szBackTexture)
Definition: C4Real.h:58
C4KeyEventData ExtraData
Definition: C4Control.h:221
bool Mobile
Definition: C4Object.h:128
bool Save(bool fReOpen)
Definition: C4Group.cpp:797
const int32_t FullCon
Definition: C4Constants.h:181
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:92
void ClearSelection(C4PropList *next_selection=nullptr)
bool OnMessage(C4Client *pOfClient, const char *szMessage)
uint32_t ColorDw
Definition: C4Player.h:89
C4SoundInstance * StartSoundEffect(const char *szSndName, bool fLoop, int32_t iVolume, C4Object *pObj, int32_t iCustomFalloffDistance, int32_t iPitch, C4SoundModifier *modifier)
int32_t Rotateable
Definition: C4Def.h:119
bool isLoading() const
void ControlScriptEvaluated(const char *script, const char *result)
Definition: C4AulDebug.cpp:438
C4CtrlValueType eValType
Definition: C4Control.h:118
C4AulScriptContext * GetContext(int iLevel)
Definition: C4AulExec.h:88
C4ClientPlayerInfos PlrInfo
Definition: C4Control.h:412
C4ControlEMObjectAction eAction
Definition: C4Control.h:462
bool C4Group_PackDirectoryTo(const char *szFilename, const char *szFilenameTo)
Definition: C4Group.cpp:221
void LeagueNotifyDisconnect(int32_t iClientID, enum C4LeagueDisconnectReason eReason)
bool fUseVarsFromCallerContext
Definition: C4Control.h:138
void OnClientSound(C4Client *pOfClient)
void Execute() const
Definition: C4Control.cpp:110
const int32_t C4D_MouseSelect
Definition: C4Def.h:52
C4Player * Get(int iPlayer) const
const char * getFile() const
int32_t FrameCounter
Definition: C4Game.h:128
C4GUIScreen * pGUI
Definition: C4Gui.cpp:1191
int32_t getID() const
Definition: C4Network2Res.h:86
static C4ControlPlayerAction * SetTeam(const C4Player *source, int32_t team)
Definition: C4Control.cpp:597
bool isNetwork() const
Definition: C4GameControl.h:97
int32_t AllCrewPosX
Definition: C4Control.h:325
std::vector< ControlItem > ControlItemVec
Definition: C4Control.h:217
virtual void PreRec(C4Record *pRecord)
Definition: C4Control.h:50
C4PlayerInfo * GetPlayerInfo(int32_t iIndex) const
C4Control SyncChecks
Definition: C4GameControl.h:80
static int32_t GetEnumerationIndex()
Definition: C4PropList.h:225
bool IsTeamSwitchAllowed() const
Definition: C4Teams.h:165
int32_t GrowthType
Definition: C4Def.h:111
bool isObserver() const
Definition: C4Client.h:111
C4Network2 Network
Definition: C4Globals.cpp:53
C4Def * Def
Definition: C4Object.h:143
bool LocalControl() const
Definition: C4Control.cpp:60
#define C4CFN_ScenarioObjectsScript
Definition: C4Components.h:74
C4ControlSyncCheck * GetSyncCheck(int32_t iTick)
void OnSelectionChanged(bool by_objectlist=false)
bool GameOver
Definition: C4Game.h:114
bool LocalJoinUnjoinedPlayersInQueue()
int32_t getLocalID() const
Definition: C4Client.h:171
int32_t iData
Definition: C4Control.h:119
int32_t GetR() const
Definition: C4Object.h:288
#define PSF_InputCallback
Definition: C4GameScript.h:82
static C4AulDebug * GetDebugger()
Definition: C4AulDebug.h:31
C4ClientPlayerInfos * AddInfo(C4ClientPlayerInfos *pNewClientInfo)
void PreRec(C4Record *pRecord) override
Definition: C4Control.cpp:1167
C4GameControl Control
StdArrayAdapt< T > mkArrayAdapt(T *pArray, int iSize)
Definition: StdAdaptors.h:310
C4Landscape Landscape
void SetVotedOut()
Definition: C4PlayerInfo.h:141
void SetTeamColors(bool fEnabled)
Definition: C4Teams.cpp:826
bool HostControl() const
Definition: C4Control.h:44
bool RemoveAtClient(int iClient, bool fDisconnect)
virtual const char * GetName() const
Definition: C4PropList.cpp:649
C4GraphicsSystem GraphicsSystem
Definition: C4Globals.cpp:51
bool IsJoined() const
Definition: C4PlayerInfo.h:166
bool Open(const char *szGroupName, bool fCreate=false)
Definition: C4Group.cpp:514
static C4ControlPlayerAction * Eliminate(const C4Player *source)
Definition: C4Control.cpp:564
C4Value ScenPropList
Definition: C4ScriptHost.h:163
#define PSF_MouseDragDrop
Definition: C4GameScript.h:121
virtual bool PreExecute() const
Definition: C4Control.h:48
C4ClientCore Core
Definition: C4Control.h:358
~C4ControlPacket() override
void DoInput(C4PacketType eCtrlType, C4ControlPacket *pPkt, C4ControlDeliveryType eDelivery)
void Take(char *pnData)
Definition: StdBuf.h:457
void EditGraphControl(const class C4ControlEditGraph *control)
Definition: C4ConsoleGUI.h:118
C4Group ScenarioFile
Definition: C4Game.h:86
void Abort(bool fApproved=false)
Definition: C4Game.cpp:3666
bool Remove(C4Client *pClient, bool fTemporary=false)
Definition: C4Client.cpp:270
C4Team * GetTeamByIndex(int32_t iIndex) const
Definition: C4Teams.cpp:404
C4PlayerList Players
bool C4Group_CopyItem(const char *szSource, const char *szTarget1, bool fNoSort, bool fResetAttributes)
Definition: C4Group.cpp:100
void Clear()
Definition: C4Control.cpp:85
bool Exit(int32_t iX=0, int32_t iY=0, int32_t iR=0, C4Real iXDir=Fix0, C4Real iYDir=Fix0, C4Real iRDir=Fix0, bool fCalls=true)
Definition: C4Object.cpp:1224
void SetActivated(bool fActivated)
C4ConfigNetwork Network
Definition: C4Config.h:255
C4ControlEMObjectAction
Definition: C4Control.h:440
uint32_t Color
Definition: C4Object.h:120
bool IsRemoved() const
Definition: C4PlayerInfo.h:164
C4Player * GetLocalByIndex(int iIndex) const
int32_t GetX() const
Definition: C4Object.h:286
void AssignRemoval(bool fExitContents=false)
Definition: C4Object.cpp:254
Definition: C4Def.h:98
const int NO_OWNER
Definition: C4Constants.h:137
int32_t Hostile(int32_t plr1, int32_t plr2)
bool Close()
Definition: C4Group.cpp:755
void Clear()
Definition: C4Network2.cpp:711
const char * getName() const
void SetObserver()
Definition: C4Client.h:123
bool LogFatal(const char *szMessage)
Definition: C4Log.cpp:227
C4PXSSystem PXS
Definition: C4PXS.cpp:525
int32_t ControlTick
Definition: C4Control.h:323
int32_t Status
Definition: C4PropList.h:168
void Clear()
Definition: C4Packet2.cpp:317
bool EraseFile(const char *szFileName)
C4Network2Res::Ref getRefRes(int32_t iResID)
StdStrBuf Script
Definition: C4Control.h:140
void Value(const T &rStruct)
Definition: StdCompiler.h:161
static C4ControlPlayerAction * InitScenarioPlayer(const C4Player *source, int32_t team)
Definition: C4Control.cpp:605
bool isEnabled() const
Definition: C4Network2.h:203
Definition: C4Id.h:25
const int32_t C4ClientIDUnknown
Definition: C4Client.h:24
#define PSF_MouseHover
Definition: C4GameScript.h:122
C4RoundResults & RoundResults
Definition: C4Game.h:73
C4Network2ResList ResList
Definition: C4Network2.h:113
const int32_t TEAMID_New
Definition: C4Teams.h:27
C4ObjectList Crew
Definition: C4Player.h:125
C4ClientPlayerInfos * GetInfoByClientID(int32_t iClientID) const
Definition: C4PlayerInfo.h:361
static C4ControlPlayerMouse * Hover(const C4Player *player, const C4Object *target, const C4Object *old_target, const C4Object *drag=nullptr)
Definition: C4Control.cpp:446
void EndVote(C4ControlVoteType eType, bool fApprove, int32_t iData)
bool SaveToFile(const char *szFile) const
Definition: StdBuf.cpp:53
C4Reloc Reloc
Definition: C4Reloc.cpp:21
LandscapeMode GetMode() const
StdCopyStrBuf strReason
Definition: C4Control.h:396
StdStrBuf BackMaterial
Definition: C4Control.h:499
int32_t Category
Definition: C4Object.h:113
void DoCon(int32_t iChange, bool grow_from_center)
Definition: C4Object.cpp:1152
C4ControlMenuCommand()=default
C4LSectors Sectors
Definition: C4GameObjects.h:42
bool ActivateGoals(int32_t iPlayer, bool fDoActivate)
Definition: C4MainMenu.cpp:304
static C4ControlPlayerAction * InitPlayerControl(const C4Player *source, const C4PlayerControlAssignmentSet *ctrl_set=nullptr)
Definition: C4Control.cpp:613
bool isRemoved() const
C4Value C4VBool(bool b)
Definition: C4Value.h:243
virtual bool isDeserializer()
Definition: StdCompiler.h:53
StdStrBuf Material
Definition: C4Control.h:497
StdStrBuf getDesc() const
Definition: C4Control.cpp:1675
int32_t AtClient
Definition: C4Player.h:97
#define C4CFN_MapBg
Definition: C4Components.h:59
int32_t ID
Definition: C4Player.h:87
bool editor_select_result
Definition: C4Control.h:139
C4ControlVoteType getType() const
Definition: C4Control.h:580
C4ControlClientUpdType eType
Definition: C4Control.h:381
ControlItemVec ControlItems
Definition: C4Control.h:222
StdIntPackAdapt< T > mkIntPackAdapt(T &rVal)
Definition: StdAdaptors.h:759
C4MassMoverSet MassMover
int ObjectCount(C4ID id=C4ID::None) const
void OnClientReadyStateChange()
Definition: C4GameLobby.h:152
bool DirectoryExists(const char *szFilename)
Definition: StdFile.cpp:684
C4ObjectPtr Target
Definition: C4Object.h:87
C4Network2ClientList Clients
Definition: C4Network2.h:116
bool SetLandscapeMode(LandscapeMode iMode, bool flat_chunk_shapes, bool fThroughControl=false)
Definition: C4ToolsDlg.cpp:181
LandscapeMode
Definition: C4Landscape.h:29
C4PlayerInfoList & PlayerInfos
Definition: C4Game.h:71
int32_t Get(const char *szMaterial)
Definition: C4Material.cpp:361
int32_t getData() const
Definition: C4Control.h:582
C4Def * C4Id2Def(C4ID id)
Definition: C4DefList.h:84
int32_t iPlayer
Definition: C4Control.h:526
const char * GetName() const
Definition: C4Player.h:151
C4NetFilenameAdapt mkNetFilenameAdapt(StdStrBuf &FileName)
Definition: C4PacketBase.h:73
C4Client * getClientByID(int32_t iID) const
Definition: C4Client.cpp:200
#define C4CFN_BigIcon
Definition: C4Components.h:111
C4Real fix_x
Definition: C4Object.h:125
void CountControl(ControlType eType, int32_t iID, int32_t iCntAdd=1)
Definition: C4Player.cpp:1631
void FlashMessage(const char *szMessage)
int32_t ClientID() const
size_t getSize() const
Definition: StdBuf.h:444
const char * getName() const
Definition: C4Client.h:107
#define C4CFN_ScenarioCore
Definition: C4Components.h:42
bool IsIgnored() const
Definition: C4Client.h:114
StdSTLContainerAdapt< C > mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep=StdCompiler::SEP_SEP)
Definition: StdAdaptors.h:681
void GameMsgObjectDw(const char *szText, C4Object *pTarget, uint32_t dwClr)
int32_t SectShapeSum
Definition: C4Control.h:330
bool isLocal() const
Definition: C4Client.h:116
C4IDPacket * nextPkt(C4IDPacket *pPkt) const
Definition: C4Control.h:79
bool isReplay() const
Definition: C4GameControl.h:98
static C4ControlPlayerAction * Surrender(const C4Player *source)
Definition: C4Control.cpp:557
void CompileFunc(StdCompiler *pComp)
Definition: C4Control.cpp:429
void NotifyUserIfInactive()
Definition: C4App.cpp:89
void Synchronize(bool fSavePlayerFiles)
Definition: C4Game.cpp:3135
C4Object * SafeObjectPointer(int32_t iNumber)
const char * getNick() const
Definition: C4Client.h:109
int32_t GetProcedure() const
Definition: C4Object.cpp:2860
C4Network2Players Players
Definition: C4Network2.h:119
C4MaterialMap MaterialMap
Definition: C4Material.cpp:969
bool Active
Definition: C4Window.h:273
bool Log(const char *szMessage)
Definition: C4Log.cpp:192
C4ControlEMDrawAction eAction
Definition: C4Control.h:494
C4Player * Next
Definition: C4Player.h:142
C4ClientList & Clients
Definition: C4Game.h:69
void Surrender()
Definition: C4Player.cpp:828
static C4ControlPlayerAction * ActivateGoal(const C4Player *source, const C4Object *target)
Definition: C4Control.cpp:571
bool isLeague() const
C4Value C4VString(C4String *pStr)
Definition: C4Value.h:246
bool Add(const char *szFile, const char *szAddAs)
Definition: C4Group.cpp:1316
void CompileFunc(StdCompiler *pComp) override
Definition: C4Control.cpp:70
void OnClientPart(class C4Client *pPartClient)
#define PSF_InitializePlayerControl
Definition: C4GameScript.h:43
int32_t ObjectEnumerationIndex
Definition: C4Control.h:329
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val=0) const
Definition: C4PropList.cpp:886
C4IDPacket * GetVote(int32_t iClientID, C4ControlVoteType eType, int32_t iData)
void SetTeamDistribution(TeamDist eToVal)
Definition: C4Teams.cpp:796
int32_t MassMoverIndex
Definition: C4Control.h:327
StdStrBuf StringParam
Definition: C4Control.h:467
#define C4CFN_ScenarioObjects
Definition: C4Components.h:87
int32_t GetTeamCount() const
Definition: C4Teams.h:158
static C4ControlEMMoveObject * CreateObject(const C4ID &id, C4Real x, C4Real y, C4Object *container)
Definition: C4Control.cpp:1214
void SetRotation(int32_t nr)
Definition: C4Object.cpp:4106
int32_t GetID() const
Definition: C4PlayerInfo.h:194
C4PlayerType GetType() const
Definition: C4PlayerInfo.h:152
C4Real fix_y
Definition: C4Object.h:125
C4Network2Client * GetLocal() const
~C4ControlEMMoveObject() override
Definition: C4Control.cpp:1224
const char * AtTempPath(const char *szFilename)
Definition: C4Config.cpp:540
void AddToSelection(C4PropList *add_obj)
const char * AtExePath(const char *szFilename)
Definition: C4Config.cpp:519
C4SHead Head
Definition: C4Scenario.h:230
void MakeTempFilename(char *szFilename)
Definition: StdFile.cpp:323
std::unique_ptr< C4ScriptGuiWindow > ScriptGuiRoot
Definition: C4Game.h:233
int32_t RandomCount
Definition: C4Control.h:324
int GetContextDepth() const
Definition: C4AulExec.h:87
C4Action Action
Definition: C4Object.h:147
const char * getName() const
Definition: C4Client.h:69
#define DirSep
void InvalidateSelection()
Definition: C4EditCursor.h:152
void OnSound(class C4Client *singer)
static C4ControlPlayerMouse * DragDrop(const C4Player *player, const C4Object *target, const C4Object *drag)
Definition: C4Control.cpp:459
bool AddFile(const char *szLocalFilename, const char *szAddAs, bool fDelete=false)
Definition: C4Record.cpp:266
int getShapeSum() const
Definition: C4Sector.cpp:199
int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
bool MatValid(int32_t mat)
Definition: C4Material.h:210
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:250
C4Real xdir
Definition: C4Object.h:126
void Copy()
Definition: StdBuf.h:467
int32_t iToPlayer
Definition: C4Control.h:526
void SetActivated(bool fnActivated)
Definition: C4Client.cpp:120
virtual void Execute() const =0
C4PacketBase * getPkt() const
Definition: C4PacketBase.h:255
C4Object * ObjectPointer(int32_t iNumber)
C4Application Application
Definition: C4Globals.cpp:44
void CompileFunc(StdCompiler *pComp) override
Definition: C4Control.cpp:138
C4Real ydir
Definition: C4Object.h:126
C4Value DirectExec(C4PropList *p, const char *szScript, const char *szContext, bool fPassErrors=false, C4AulScriptContext *context=nullptr, bool parse_function=false)
Definition: C4AulExec.cpp:1013
bool Remove(int iPlayer, bool fDisonnected, bool fNoCalls)
#define PSF_MouseSelection
Definition: C4GameScript.h:119
void HandlePlayerInfo(const class C4ClientPlayerInfos &rInfoPacket)
void ChangeToLocal()
bool DebugMode
Definition: C4Game.h:144
C4Object * CreateObject(C4PropList *type, C4Object *pCreator, int32_t owner=NO_OWNER, int32_t x=50, int32_t y=50, int32_t r=0, bool grow_from_center=false, C4Real xdir=Fix0, C4Real ydir=Fix0, C4Real rdir=Fix0, int32_t iController=NO_OWNER)
Definition: C4Game.cpp:1072
int32_t ControlRate
Definition: C4GameControl.h:88
void Add(C4Client *pClient)
Definition: C4Client.cpp:181
bool HasSameTeamPlayers(int32_t iClient1, int32_t iClient2) const
class C4MessageBoardCommand * GetCommand(const char *strName)
const int32_t C4NetResMaxBigicon
Definition: C4Network2Res.h:36
DECLARE_C4CONTROL_VIRTUALS bool PreExecute() const override
Definition: C4Control.cpp:1150
int32_t Film
Definition: C4Scenario.h:73
#define PSF_MouseSelectionAlt
Definition: C4GameScript.h:120
StdStrBuf getDescWarning() const
Definition: C4Control.cpp:1704
bool LocateItem(const char *filename, StdStrBuf &str) const
Definition: C4Reloc.cpp:93
C4GameObjects Objects
Definition: C4Globals.cpp:48
StdIntAdapt< T > mkIntAdapt(T &rValue)
Definition: StdAdaptors.h:229
const int32_t C4ClientIDHost
Definition: C4Client.h:25
const C4Real Fix0
Definition: C4Real.h:312
const int C4MaxControlRate
Definition: C4Constants.h:33
bool RemoveMessageBoardQuery(C4Object *pForObj)
Definition: C4Player.cpp:1673
int32_t GetIndexedPlayer(int32_t iIndex) const
Definition: C4Teams.h:76
bool LocalControl
Definition: C4Player.h:99
int32_t CreatePtr
Definition: C4MassMover.h:44
bool Message(const char *szMessage, bool fQuery=false)
Definition: C4Console.cpp:292
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
int32_t ObjectCount
Definition: C4Control.h:328
int32_t Count
Definition: C4PXS.h:45
C4Value Call(C4PropertyName k, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4PropList.h:110
C4PropList * getPropList() const
Definition: C4Value.h:116
StdStrBuf Texture
Definition: C4Control.h:498