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