OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Command.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 /* The command stack controls an object's complex and independent behavior */
19 
20 #include "C4Include.h"
21 #include "object/C4Command.h"
22 
23 #include "object/C4Def.h"
24 #include "object/C4DefList.h"
25 #include "object/C4Object.h"
26 #include "object/C4ObjectCom.h"
27 #include "object/C4ObjectInfo.h"
28 #include "lib/C4Random.h"
29 #include "gui/C4GameMessage.h"
30 #include "object/C4ObjectMenu.h"
31 #include "player/C4Player.h"
32 #include "platform/C4SoundSystem.h"
33 #include "landscape/C4Landscape.h"
34 #include "game/C4Game.h"
35 #include "player/C4PlayerList.h"
36 #include "object/C4GameObjects.h"
37 
40 const int32_t PathRange=20,MaxPathRange=1000;
42 const int32_t FlightAngleRange=60;
43 const int32_t DigOutDirectRange=130;
44 const int32_t LetGoHangleAngle=110;
45 
47 
48 const char *CommandName(int32_t iCommand)
49 {
50  switch (iCommand)
51  {
52  case C4CMD_None: return "None";
53  case C4CMD_Follow: return "Follow";
54  case C4CMD_MoveTo: return "MoveTo";
55  case C4CMD_Enter: return "Enter";
56  case C4CMD_Exit: return "Exit";
57  case C4CMD_Grab: return "Grab";
58  case C4CMD_Throw: return "Throw";
59  case C4CMD_UnGrab: return "UnGrab";
60  case C4CMD_Jump: return "Jump";
61  case C4CMD_Wait: return "Wait";
62  case C4CMD_Get: return "Get";
63  case C4CMD_Put: return "Put";
64  case C4CMD_Drop: return "Drop";
65  case C4CMD_Dig: return "Dig";
66  case C4CMD_Activate: return "Activate";
67  case C4CMD_PushTo: return "PushTo";
68  case C4CMD_Transfer: return "Transfer";
69  case C4CMD_Attack: return "Attack";
70  case C4CMD_Buy: return "Buy";
71  case C4CMD_Sell: return "Sell";
72  case C4CMD_Acquire: return "Acquire";
73  case C4CMD_Retry: return "Retry";
74  case C4CMD_Home: return "Home";
75  case C4CMD_Call: return "Call";
76  case C4CMD_Take: return "Take";
77  case C4CMD_Take2: return "Take2";
78  default: return "None";
79  }
80 }
81 
82 const char* CommandNameID(int32_t iCommand)
83 {
84  switch (iCommand)
85  {
86  case C4CMD_None: return "IDS_COMM_NONE";
87  case C4CMD_Follow: return "IDS_COMM_FOLLOW";
88  case C4CMD_MoveTo: return "IDS_COMM_MOVETO";
89  case C4CMD_Enter: return "IDS_COMM_ENTER";
90  case C4CMD_Exit: return "IDS_COMM_EXIT";
91  case C4CMD_Grab: return "IDS_COMM_GRAB";
92  case C4CMD_Throw: return "IDS_COMM_THROW";
93  case C4CMD_UnGrab: return "IDS_COMM_UNGRAB";
94  case C4CMD_Jump: return "IDS_COMM_JUMP";
95  case C4CMD_Wait: return "IDS_COMM_WAIT";
96  case C4CMD_Get: return "IDS_COMM_GET";
97  case C4CMD_Put: return "IDS_COMM_PUT";
98  case C4CMD_Drop: return "IDS_COMM_DROP";
99  case C4CMD_Dig: return "IDS_COMM_DIG";
100  case C4CMD_Activate: return "IDS_COMM_ACTIVATE";
101  case C4CMD_PushTo: return "IDS_COMM_PUSHTO";
102  case C4CMD_Transfer: return "IDS_COMM_TRANSFER";
103  case C4CMD_Attack: return "IDS_COMM_ATTACK";
104  case C4CMD_Buy: return "IDS_COMM_BUY";
105  case C4CMD_Sell: return "IDS_COMM_SELL";
106  case C4CMD_Acquire: return "IDS_COMM_ACQUIRE";
107  case C4CMD_Retry: return "IDS_COMM_RETRY";
108  case C4CMD_Home: return "IDS_CON_HOME";
109  case C4CMD_Call: return "IDS_COMM_CALL";
110  case C4CMD_Take: return "IDS_COMM_TAKE";
111  case C4CMD_Take2: return "IDS_COMM_TAKE2";
112  default: return "IDS_COMM_NONE";
113  }
114 }
115 
117 {
118  for (int32_t i = C4CMD_First; i <= C4CMD_Last; i++)
119  {
120  EnumAdaptCommandEntries[i - C4CMD_First].Name = CommandName(i);
121  EnumAdaptCommandEntries[i - C4CMD_First].Val = i;
122  }
123  EnumAdaptCommandEntries[C4CMD_Last - C4CMD_First + 1].Name = nullptr;
124  return true;
125 }
127 
128 int32_t CommandByName(const char *szCommand)
129 {
130  for (int32_t cnt=C4CMD_First; cnt<=C4CMD_Last; cnt++)
131  if (SEqual(szCommand,CommandName(cnt)))
132  return cnt;
133  return C4CMD_None;
134 }
135 
136 bool FreeMoveTo(C4Object *cObj)
137 {
138  // Floating: we accept any move-to target
139  if (cObj->GetProcedure()==DFA_FLOAT) return true;
140  // Assume we're walking: move-to targets are adjusted
141  return false;
142 }
143 
144 void AdjustMoveToTarget(int32_t &rX, int32_t &rY, bool fFreeMove, int32_t iShapeHgt)
145 {
146  // Above solid (always)
147  int32_t iY=std::min(rY, ::Landscape.GetHeight());
148  while ((iY>=0) && GBackSolid(rX,iY)) iY--;
149  if (iY>=0) rY=iY;
150  // No-free-move adjustments (i.e. if walking)
151  if (!fFreeMove)
152  {
153  // Drop down to bottom of free space
154  if (!GBackSemiSolid(rX,rY))
155  {
156  for (iY=rY; (iY<::Landscape.GetHeight()) && !GBackSemiSolid(rX,iY+1); iY++) {}
157  if (iY<::Landscape.GetHeight()) rY=iY;
158  }
159  // Vertical shape offset above solid
160  if (GBackSolid(rX,rY+1) || GBackSolid(rX,rY+5))
161  if (!GBackSemiSolid(rX,rY-iShapeHgt/2))
162  rY-=iShapeHgt/2;
163  }
164 
165 }
166 
167 bool AdjustSolidOffset(int32_t &rX, int32_t &rY, int32_t iXOff, int32_t iYOff)
168 {
169  // In solid: fail
170  if (GBackSolid(rX,rY)) return false;
171  // Y Offset
172  int32_t cnt;
173  for (cnt=1; cnt<iYOff; cnt++)
174  {
175  if (GBackSolid(rX,rY+cnt) && !GBackSolid(rX,rY-cnt)) rY--;
176  if (GBackSolid(rX,rY-cnt) && !GBackSolid(rX,rY+cnt)) rY++;
177  }
178  // X Offset
179  for (cnt=1; cnt<iXOff; cnt++)
180  {
181  if (GBackSolid(rX+cnt,rY) && !GBackSolid(rX-cnt,rY)) rX--;
182  if (GBackSolid(rX-cnt,rY) && !GBackSolid(rX+cnt,rY)) rX++;
183  }
184  // Done
185  return true;
186 }
187 
188 int32_t SolidOnWhichSide(int32_t iX, int32_t iY)
189 {
190  for (int32_t cx=1; cx<10; cx++)
191  for (int32_t cy=0; cy<10; cy++)
192  {
193  if (GBackSolid(iX-cx,iY-cy) || GBackSolid(iX-cx,iY+cy)) return -1;
194  if (GBackSolid(iX+cx,iY-cy) || GBackSolid(iX+cx,iY+cy)) return +1;
195  }
196  return 0;
197 }
198 
200 {
201  Default();
202 }
203 
205 {
206  Clear();
207 }
208 
210 {
212  cObj=nullptr;
213  Evaluated=false;
214  PathChecked=false;
215  Finished=false;
216  Tx=C4VNull;
217  Ty=0;
218  Target=Target2=nullptr;
219  Data.Set0();
220  UpdateInterval=0;
221  Failures=0;
222  Retries=0;
223  Permit=0;
224  Text=nullptr;
225  Next=nullptr;
226  iExec=0;
228 }
229 
231 {
232  explicit ObjectAddWaypoint(C4Object *obj) : cObj(obj) {}
233  bool operator()(int32_t iX, int32_t iY, C4Object *TransferTarget)
234  {
235  if (!cObj) return false;
236 
237  // Transfer waypoint
238  if (TransferTarget)
239  return cObj->AddCommand(C4CMD_Transfer,TransferTarget,iX,iY,0,nullptr,false);
240 
241  // Solid offset
242  AdjustSolidOffset(iX,iY,cObj->Shape.Wdt/2,cObj->Shape.Hgt/2);
243 
244  // Standard movement waypoint update interval
245  int32_t iUpdate = 25;
246  // Waypoints before transfer zones are not updated (enforce move to that waypoint)
247  if (cObj->Command && (cObj->Command->Command==C4CMD_Transfer)) iUpdate=0;
248  // Add waypoint
249  assert(cObj->Command);
250  if (!cObj->AddCommand(C4CMD_MoveTo,nullptr,iX,iY,iUpdate,nullptr,false,cObj->Command->Data)) return false;
251 
252  return true;
253  }
254 
255 private:
256  C4Object *cObj;
257 };
258 
260 {
261  // Determine move-to range
262  int32_t iMoveToRange = MoveToRange;
263  if (cObj->Def->MoveToRange > 0) iMoveToRange = cObj->Def->MoveToRange;
264 
265  // Current object position
266  int32_t cx,cy; cx=cObj->GetX(); cy=cObj->GetY();
267  bool fWaypoint=false;
268  if (Next && (Next->Command==C4CMD_MoveTo)) fWaypoint=true;
269 
270  // Contained: exit
271  if (cObj->Contained)
272  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
273 
274  // Check path (crew members or specific only)
275  if ((cObj->OCF & OCF_CrewMember) || cObj->Def->Pathfinder)
276  if (!PathChecked)
277  // Not too far
278  if (Distance(cx,cy,Tx._getInt(),Ty)<MaxPathRange)
279  // Not too close
280  if (!(Inside(cx-Tx._getInt(),-PathRange,+PathRange) && Inside(cy-Ty,-PathRange,+PathRange)))
281  {
282  // Path not free: find path
283  if (!PathFree(cx,cy,Tx._getInt(),Ty))
284  {
287  if (!Game.PathFinder.Find( cObj->GetX(),cObj->GetY(),
288  Tx._getInt(),Ty,
290  { /* Path not found: react? */ PathChecked=true; /* recheck delay */ }
291  return;
292  }
293  // Path free: recheck delay
294  else
295  PathChecked=true;
296  }
297  // Path recheck
298  if (!::Game.iTick35) PathChecked=false;
299 
300  // Pushing grab only or not desired: let go (pulling, too?)
301  if (cObj->GetProcedure()==DFA_PUSH)
302  if (cObj->Action.Target)
304  {
305  // Re-evaluate this command because vehicle control might have blocked evaluation
306  Evaluated=false;
307  cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return;
308  }
309 
310  // Special by procedure
311  switch (cObj->GetProcedure())
312  {
313  // Push/pull
314  case DFA_PUSH: case DFA_PULL:
315  // Use target object's position if on final waypoint
316  if (!fWaypoint)
317  if (cObj->Action.Target)
318  { cx=cObj->Action.Target->GetX(); cy=cObj->Action.Target->GetY(); }
319  break;
320  // dig, bridge: stop
321  case DFA_DIG: case DFA_BRIDGE:
323  break;
324  }
325 
326  // Target range
327  int32_t iTargetRange = iMoveToRange;
328  int32_t iRangeFactorTop=1, iRangeFactorBottom=1, iRangeFactorSide=1;
329 
330  // Crew members/pathfinder specific target range
331  if (cObj->OCF & OCF_CrewMember) // || cObj->Def->Pathfinder ? (Sven2)
332  {
333  // Range by size
334  iTargetRange=cObj->Shape.Wdt/2;
335  // Easier range if waypoint
336  if (fWaypoint)
337  if (cObj->GetProcedure()!=DFA_SCALE)
338  { iRangeFactorTop=3; iRangeFactorSide=3; iRangeFactorBottom=2; }
339  }
340 
341  // Target reached (success)
342  if (Inside(cx-Tx._getInt(),-iRangeFactorSide*iTargetRange,+iRangeFactorSide*iTargetRange)
343  && Inside(cy-Ty,-iRangeFactorBottom*iTargetRange,+iRangeFactorTop*iTargetRange))
344  {
346  Finish(true); return;
347  }
348 
349  // Idles can't move to
350  if (!cObj->GetAction())
351  { Finish(); return; }
352 
353  // Action
354  switch (cObj->GetProcedure())
355  {
356  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
357  case DFA_WALK:
358  // Head to target
359  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
360  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
361  // Flight control
362  if (FlightControl()) return;
363  // Jump control
364  if (JumpControl()) return;
365  break;
366  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
367  case DFA_PUSH: case DFA_PULL:
368  // Head to target
369  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
370  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
371  break;
372  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
373  case DFA_SCALE:
374  // Head to target
375  if (cy>Ty+iTargetRange) cObj->Action.ComDir=COMD_Up;
376  if (cy<Ty-iTargetRange) cObj->Action.ComDir=COMD_Down;
377  // Let-Go Control
378  if (cObj->Action.Dir==DIR_Left)
379  {
380  // Target direction
381  if ((Tx._getInt()>cx+LetGoRange1) && (Inside(cy-Ty,-LetGoRange2,+LetGoRange2)))
382  { ObjectComLetGo(cObj,+1); return; }
383  // Contact (not if just started)
384  if (cObj->Action.Time>2)
385  if (cObj->t_contact/* & CNAT_Left*/)
386  { ObjectComLetGo(cObj,+1); return; }
387  }
388  if (cObj->Action.Dir==DIR_Right)
389  {
390  // Target direction
391  if ((Tx._getInt()<cx-LetGoRange1) && (Inside(cy-Ty,-LetGoRange2,+LetGoRange2)))
392  { ObjectComLetGo(cObj,-1); return; }
393  // Contact (not if just started)
394  if (cObj->Action.Time>2)
395  if (cObj->t_contact/* & CNAT_Right*/)
396  { ObjectComLetGo(cObj,-1); return; }
397  }
398  break;
399  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
400  case DFA_SWIM:
401  // Head to target
402  if (::Game.iTick2)
403  {
404  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
405  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
406  }
407  else
408  {
409  if (cy<Ty) cObj->Action.ComDir=COMD_Down;
410  if (cy>Ty) cObj->Action.ComDir=COMD_Up;
411  }
412  break;
413  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
414  case DFA_HANGLE:
415  // Head to target
416  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
417  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
418  // Let-Go Control
419  if (Abs(Angle(cx,cy,Tx._getInt(),Ty))>LetGoHangleAngle)
420  ObjectComLetGo(cObj,0);
421  break;
422  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
423  case DFA_FLOAT:
424  {
425  C4Real dx = itofix(Tx._getInt()) - cObj->fix_x, dy = itofix(Ty) - cObj->fix_y;
426  // normalize
427  C4Real dScale = C4REAL100(cObj->GetAction()->GetPropertyInt(P_Speed)) / std::max(Abs(dx), Abs(dy));
428  dx *= dScale; dy *= dScale;
429  // difference to momentum
430  dx -= cObj->xdir; dy -= cObj->ydir;
431  // steer
432  if (Abs(dx)+Abs(dy) < C4REAL100(20)) cObj->Action.ComDir = COMD_Stop;
433  else if (Abs(dy) * 3 < dx) cObj->Action.ComDir = COMD_Right;
434  else if (Abs(dy) * 3 < -dx) cObj->Action.ComDir = COMD_Left;
435  else if (Abs(dx) * 3 < dy) cObj->Action.ComDir = COMD_Down;
436  else if (Abs(dx) * 3 < -dy) cObj->Action.ComDir = COMD_Up;
437  else if (dx > 0 && dy > 0) cObj->Action.ComDir = COMD_DownRight;
438  else if (dx < 0 && dy > 0) cObj->Action.ComDir = COMD_DownLeft;
439  else if (dx > 0 && dy < 0) cObj->Action.ComDir = COMD_UpRight;
440  else cObj->Action.ComDir = COMD_UpLeft;
441  }
442  break;
443  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
444  case DFA_FLIGHT:
445  // Try to move into right direction
446  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
447  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
448  // Flight control
449  if (FlightControl()) return;
450  break;
451  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
452  }
453 
454 }
455 
457 {
458  // Current object and target coordinates
459  int32_t cx,cy,tx,ty;
460  cx=cObj->GetX(); cy=cObj->GetY();
461  tx=Tx._getInt(); ty=Ty+cObj->Shape.GetY() + 3; // Target coordinates are bottom center
462  bool fDigOutMaterial=Data.getBool();
463 
464  // Grabbing: let go
465  if (cObj->GetProcedure()==DFA_PUSH)
466  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
467 
468  // If contained: exit
469  if (cObj->Contained)
470  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
471 
472  // Scaling or hangling: let go
474  ObjectComLetGo(cObj,(cObj->Action.Dir==DIR_Left) ? +1 : -1);
475 
476  // Determine move-to range
477  int32_t iMoveToRange = MoveToRange;
478  if (cObj->Def->MoveToRange > 0) iMoveToRange = cObj->Def->MoveToRange;
479 
480  // Target reached: success
481  if (Inside(cx - tx, -iMoveToRange, +iMoveToRange)
482  && Inside(cy - ty, -iMoveToRange, +iMoveToRange))
483  {
485  Finish(true); return;
486  }
487 
488  // Can start digging only from walk
489  if (cObj->GetProcedure()!=DFA_DIG)
490  if (cObj->GetProcedure()!=DFA_WALK)
491  // Continue trying (assume currently in flight)
492  return;
493 
494  // Start digging
495  if (cObj->GetProcedure()!=DFA_DIG)
496  if (!ObjectComDig(cObj))
497  { Finish(); return; }
498 
499  // Dig2Object
500  if (fDigOutMaterial) cObj->Action.Data=1;
501 
502  // Head to target
503  if (cx<tx-DigRange) cObj->Action.ComDir=COMD_Right;
504  if (cx>tx+DigRange) cObj->Action.ComDir=COMD_Left;
505  if (cy<ty-DigRange) cObj->Action.ComDir=COMD_Down;
506  if (cx<tx-DigRange) if (cy<ty-DigRange) cObj->Action.ComDir=COMD_DownRight;
507  if (cx>tx-DigRange) if (cy<ty-DigRange) cObj->Action.ComDir=COMD_DownLeft;
508  if (cx<tx-DigRange) if (cy>ty+DigRange) cObj->Action.ComDir=COMD_UpRight;
509  if (cx>tx+DigRange) if (cy>ty+DigRange) cObj->Action.ComDir=COMD_UpLeft;
510 
511 }
512 
513 
515 {
516  // No-one to follow
517  if (!Target) { Finish(); return; }
518 
519  // Follow containment
521  {
522  // Only crew members can follow containment
523  if (!cObj->Def->CrewMember)
524  { Finish(); return; }
525  // Exit/enter
526  if (cObj->Contained) cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50);
527  else cObj->AddCommand(C4CMD_Enter,Target->Contained,0,0,50);
528  return;
529  }
530 
531  // Follow target grabbing
532  if (Target->GetProcedure()==DFA_PUSH)
533  {
534  // Grabbing same: copy ComDir
535  if (cObj->GetProcedure()==DFA_PUSH)
537  {
539  return;
540  }
541  // Else, grab target's grab
543  return;
544  }
545  else if (cObj->GetProcedure()==DFA_PUSH)
546  {
547  // Follow ungrabbing
549  return;
550  }
551 
552  // If in following range
553  if (Inside<int32_t>(cObj->GetX()-Target->GetX(),-FollowRange,+FollowRange)
554  && Inside<int32_t>(cObj->GetY()-Target->GetY(),-FollowRange,+FollowRange))
555  {
556  // Copy target's Action.ComDir
558  }
559  else // Else, move to target
560  {
561  cObj->AddCommand(C4CMD_MoveTo,nullptr,Target->GetX(),Target->GetY(),10);
562  }
563 
564 }
565 
567 {
568  DWORD ocf;
569 
570  // No object to enter or can't enter by def
571  if (!Target || cObj->Def->NoPushEnter) { Finish(); return; }
572 
573  // Already in target object
574  if (cObj->Contained==Target) { Finish(true); return; }
575 
576  // Digging: stop
578 
579  // Pushing grab only or pushing not desired: let go
580  if (cObj->GetProcedure()==DFA_PUSH)
581  if (cObj->Action.Target)
583  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
584 
585  // Pushing target: let go
586  if (cObj->GetProcedure()==DFA_PUSH)
587  if (cObj->Action.Target==Target)
588  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
589 
590  // Grabbing overrides position for target
591  int32_t cx,cy;
592  cx=cObj->GetX(); cy=cObj->GetY();
593  if (cObj->GetProcedure()==DFA_PUSH)
594  if (cObj->Action.Target)
595  { cx=cObj->Action.Target->GetX(); cy=cObj->Action.Target->GetY(); }
596 
597  // If in entrance range
598  ocf=OCF_Entrance;
599  if (!cObj->Contained && Target->At(cx,cy,ocf) && (ocf & OCF_Entrance))
600  {
601  // Stop
603  // Pushing: push target into entrance, then stop
604  if ((cObj->GetProcedure()==DFA_PUSH) && cObj->Action.Target)
605  {
607  Finish(true); return;
608  }
609  // Else, enter self
610  else
611  {
612  // If entrance open, enter object
613  if (Target->EntranceStatus!=0)
614  {
615  cObj->Enter(Target);
616  Finish(true); return;
617  }
618  else // Else, activate entrance
620  }
621 
622  }
623  else // Else, move to object's entrance
624  {
625  int32_t ex,ey,ewdt,ehgt;
626  if (Target->GetEntranceArea(ex,ey,ewdt,ehgt))
627  cObj->AddCommand(C4CMD_MoveTo,nullptr,ex+ewdt/2,ey+ehgt/2,50, nullptr, true, C4VInt((Data.getInt() & C4CMD_Enter_PushTarget) ? C4CMD_MoveTo_PushTarget : 0));
628  }
629 
630 }
631 
633 {
634 
635  // Outside: done
636  if (!cObj->Contained) { Finish(true); return; }
637 
638  // Entrance open, leave object
640  {
641  // Exit to container's container
642  if (cObj->Contained->Contained)
643  { cObj->Enter(cObj->Contained->Contained); Finish(true); return; }
644  // Exit to entrance area
645  int32_t ex,ey,ewdt,ehgt;
646  if (cObj->Contained->OCF & OCF_Entrance)
647  if (cObj->Contained->GetEntranceArea(ex,ey,ewdt,ehgt))
648  { cObj->Exit(ex+ewdt/2,ey+ehgt+cObj->Shape.GetY()-1); Finish(true); return; }
649  // Exit jump out of collection area
652  {
655  Finish(true); return;
656  }
657  // Plain exit
658  cObj->Exit(cObj->GetX(),cObj->GetY());
659  Finish(true); return;
660  }
661 
662  // Entrance closed, activate entrance
663  else
664  {
666  // Entrance activation failed: fail
667  { Finish(); return; }
668  }
669 }
670 
672 {
673  DWORD ocf;
674  // Command fulfilled
675  if (cObj->GetProcedure()==DFA_PUSH)
676  if (cObj->Action.Target==Target)
677  { Finish(true); return; }
678  // Digging: stop
680  // Grabbing: let go
681  if (cObj->GetProcedure()==DFA_PUSH)
682  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
683  // No target
684  if (!Target) { Finish(); return; }
685  // At target object: grab
686  ocf=OCF_All;
687  if (!cObj->Contained && Target->At(cObj->GetX(),cObj->GetY(),ocf))
688  {
689  // Scaling or hangling: let go
691  ObjectComLetGo(cObj,(cObj->Action.Dir==DIR_Left) ? +1 : -1);
692  // Grab
695  }
696  // Else, move to object
697  else
698  {
699  cObj->AddCommand(C4CMD_MoveTo,nullptr,Target->GetX()+Tx._getInt(),Target->GetY()+Ty,50);
700  }
701 }
702 
704 {
705  // Target check
706  if (!Target) { Finish(); return; }
707 
708  // Target is target self: fail
709  if (Target==Target2) { Finish(); return; }
710 
711  // Command fulfilled
712  if (Target2)
713  {
714  // Object in correct target container: success
715  if (Target->Contained==Target2)
716  { Finish(true); return; }
717  }
718  else
719  {
720  // Object at target position: success
723  {
726  cObj->AddCommand(C4CMD_Wait,nullptr,0,0,10);
727  Finish(true); return;
728  }
729  }
730 
731  // Digging: stop
733 
734  // Target contained: activate
735  if (Target->Contained)
736  { cObj->AddCommand(C4CMD_Activate,Target,0,0,40); return; }
737 
738  // Grab target
739  if (!((cObj->GetProcedure()==DFA_PUSH) && (cObj->Action.Target==Target)))
740  { cObj->AddCommand(C4CMD_Grab,Target,0,0,40); return; }
741 
742  // Move to target position / enter target object
743  if (Target2)
744  { cObj->AddCommand(C4CMD_Enter,Target2,0,0,40, nullptr, true, C4Value(C4CMD_Enter_PushTarget)); return; }
745  else
746  { cObj->AddCommand(C4CMD_MoveTo,nullptr,Tx,Ty,40, nullptr, true, C4Value(C4CMD_MoveTo_PushTarget)); return; }
747 
748 }
749 
751 {
754  Finish(true);
755 }
756 
758 {
759 
760  // Digging: stop
762 
763  // Throw specific object not in contents: get object
764  if (Target)
765  if (!cObj->Contents.GetLink(Target))
766  {
767  cObj->AddCommand(C4CMD_Get,Target,0,0,40);
768  return;
769  }
770 
771  // Determine move-to range
772  int32_t iMoveToRange = MoveToRange;
773  if (cObj->Def->MoveToRange > 0) iMoveToRange = cObj->Def->MoveToRange;
774 
775  // Target coordinates are not default 0/0: targeted throw
776  if ((Tx._getInt()!=0) || (Ty!=0))
777  {
778 
779  // Grabbing: let go
780  if (cObj->GetProcedure()==DFA_PUSH)
781  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
782 
783  // Preferred throwing direction
784  int32_t iDir=+1; if (cObj->GetX() > Tx._getInt()) iDir=-1;
785 
786  // Find throwing position
787  int32_t iTx,iTy;
789  int32_t iHeight = cObj->Shape.Hgt;
790  if (!FindThrowingPosition(Tx._getInt(),Ty,pthrow*iDir,-pthrow,iHeight,iTx,iTy))
791  if (!FindThrowingPosition(Tx._getInt(),Ty,pthrow*iDir*-1,-pthrow,iHeight,iTx,iTy))
792  // No throwing position: fail
793  { Finish(); return; }
794 
795  // At throwing position: face target and throw
796  if (Inside<int32_t>(cObj->GetX() - iTx, -iMoveToRange, +iMoveToRange) && Inside<int32_t>(cObj->GetY()-iTy,-15,+15))
797  {
798  if (cObj->GetX() < Tx._getInt()) cObj->SetDir(DIR_Right); else cObj->SetDir(DIR_Left);
801  Finish(true); // Throw successfull: done, else continue
802  return;
803  }
804 
805  // Move to target position
806  cObj->AddCommand(C4CMD_MoveTo,nullptr,iTx,iTy,20);
807 
808  return;
809  }
810 
811  // Contained: put or take
812  if (cObj->Contained)
813  {
815  Finish(true); return;
816  }
817 
818  // Pushing: put or take
819  if (cObj->GetProcedure()==DFA_PUSH)
820  {
821  if (cObj->Action.Target)
823  Finish(true); return;
824  }
825 
826  // Outside: Throw
828  Finish(true);
829 }
830 
832 {
834  Finish(true);
835 }
836 
838 {
840  Finish(true);
841 }
842 
844 {
845 
846  // Digging: stop
848 
849  // Drop specific object not in contents: get object
850  if (Target)
851  if (!cObj->Contents.GetLink(Target))
852  {
853  cObj->AddCommand(C4CMD_Get,Target,0,0,40);
854  return;
855  }
856 
857  // Determine move-to range
858  int32_t iMoveToRange = MoveToRange;
859  if (cObj->Def->MoveToRange > 0) iMoveToRange = cObj->Def->MoveToRange;
860 
861  // Target coordinates are not default 0/0: targeted drop
862  if ((Tx._getInt()!=0) || (Ty!=0))
863  {
864  // Grabbing: let go
865  if (cObj->GetProcedure()==DFA_PUSH)
866  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
867  // At target position: drop
868  if (Inside<int32_t>(cObj->GetX() - Tx._getInt(), -iMoveToRange, +iMoveToRange) && Inside<int32_t>(cObj->GetY()-Ty,-15,+15))
869  {
872  Finish(true);
873  return;
874  }
875  // Move to target position
876  cObj->AddCommand(C4CMD_MoveTo,nullptr,Tx._getInt(),Ty,20);
877  return;
878  }
879 
880  // Contained: put
881  if (cObj->Contained)
882  {
884  Finish(true); return;
885  }
886 
887  // Pushing: put
888  if (cObj->GetProcedure()==DFA_PUSH)
889  {
890  if (cObj->Action.Target)
892  Finish(true); return;
893  }
894 
895  // Outside: Drop
897  Finish(true);
898 }
899 
901 {
902  // Already in air?
903  if (cObj->GetProcedure()==DFA_FLIGHT)
904  {
905  // Check whether target position is given
906  if (Tx._getInt())
907  {
909  else if (cObj->GetX()>Tx._getInt()) cObj->Action.ComDir=COMD_Left;
910  else cObj->Action.ComDir=COMD_Stop;
911  }
912  }
913  else
914  {
916  // Done
917  Finish(true);
918  return;
919  }
920 }
921 
923 {
924  // Digging: stop
926 }
927 
929 {
930  // Target contained and container has RejectContents: fail
931  if (Target->Contained && !!Target->Contained->Call(PSF_RejectContents)) { Finish(); return false; }
932  // FIXME: Drop stuff if full here
933  bool fWasContained = !!Target->Contained;
934  // Grab target object
935  bool fRejectCollect = false;
936  bool fSuccess = !!Target->Enter(cObj, true, true, &fRejectCollect);
937  // target is void?
938  // well...most likely the new container has done something with it
939  // so count it as success
940  if (!Target) { Finish(true); return true; }
941  // collection rejected by target: make room for more contents
942  if (fRejectCollect)
943  {
944  if (cObj->PutAwayUnusedObject(Target)) return false;
945  // Can't get due to RejectCollect: fail
946  Finish();
947  return false;
948  }
949  // if not successfully entered for any other reason, fail
950  if (!fSuccess) { Finish(); return false; }
951  // get-callback for getting out of containers
952  if (fWasContained) cObj->Call(PSF_Get, &C4AulParSet(Target));
953  // entered
954  return true;
955 }
956 
958 {
959 
960  // Data set and target specified: open get menu & done (old style)
961  if (((Data.getInt()==1) || (Data.getInt()==2)) && Target)
962  {
964  Finish(true); return;
965  }
966 
967  // Get target specified by container and type
968  if (!Target && Target2 && Data)
969  if (!(Target = Target2->Contents.Find(Data.getDef())))
970  { Finish(); return; }
971 
972  // No target: failure
973  if (!Target) { Finish(); return; }
974 
975  // Target not carryable: failure
976  if (!(Target->OCF & OCF_Carryable))
977  { Finish(); return; }
978 
979  // Target collected
980  if (Target->Contained == cObj)
981  {
982  // Get-count specified: decrease count and continue with next object
983  if (Tx._getInt() > 1)
984  { Target = nullptr; Tx--; return; }
985  // We're done
986  else
987  { cObj->Action.ComDir=COMD_Stop; Finish(true); return; }
988  }
989 
990  // Grabbing other than target container: let go
991  if (cObj->GetProcedure()==DFA_PUSH)
993  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
994 
995  // Target in solid: dig out
996  if (!Target->Contained && (Target->OCF & OCF_InSolid))
997  {
998  // Check for closest free position
999  int32_t iX=Target->GetX(),iY=Target->GetY();
1000  // Find all-closest dig-out position
1001  if (!FindClosestFree(iX,iY,-120,+120,-1,-1))
1002  // None found
1003  { Finish(); return; }
1004  // Check good-angle left/right dig-out position
1005  int32_t iX2=Target->GetX(),iY2=Target->GetY();
1006  if (FindClosestFree(iX2,iY2,-140,+140,-40,+40))
1007  // Use good-angle position if it's not way worse
1008  if ( Distance(Target->GetX(),Target->GetY(),iX2,iY2) < 10*Distance(Target->GetX(),Target->GetY(),iX,iY) )
1009  { iX=iX2; iY=iY2; }
1010  // Move to closest free position (if not in dig-direct range)
1013  { cObj->AddCommand(C4CMD_MoveTo,nullptr,iX,iY,50); return; }
1014  // DigTo
1015  cObj->AddCommand(C4CMD_Dig,nullptr,Target->GetX(),Target->GetY()+4,50); return;
1016  }
1017 
1018  // Digging: stop
1020 
1021  // Target contained
1022  if (Target->Contained)
1023  {
1024  // target can't be taken out of containers?
1025  if (Target->Def->NoGet) return;
1026  // In same container: grab target
1027  if (cObj->Contained==Target->Contained)
1028  {
1029  GetTryEnter();
1030  // Done
1031  return;
1032  }
1033 
1034  // Leave own container
1035  if (cObj->Contained)
1036  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
1037 
1038  // Target container has grab get: grab target container
1040  {
1041  // Grabbing target container
1043  {
1044  GetTryEnter();
1045  // Done
1046  return;
1047  }
1048  // Grab target container
1050  return;
1051  }
1052 
1053  // Target container has entrance: enter target container
1054  if (Target->Contained->OCF & OCF_Entrance)
1055  { cObj->AddCommand(C4CMD_Enter,Target->Contained,0,0,50); return; }
1056 
1057  // Can't get to target due to target container: fail
1058  Finish();
1059  return;
1060  }
1061 
1062  // Target outside
1063 
1064  // Leave own container
1065  if (cObj->Contained) { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
1066 
1067  // Outside
1068  if (!cObj->Contained)
1069  {
1070 
1071  // Target in collection range
1073  if (cObj->At(Target->GetX(),Target->GetY(),ocf))
1074  {
1075  // stop here
1077  // try getting the object
1078  if (GetTryEnter()) return;
1079  }
1080 
1081  // Target not in range
1082  else
1083  {
1084  // Target in jumping range above clonk: try side-move jump
1085  if (Inside<int32_t>(cObj->GetX()-Target->GetX(),-10,+10))
1086  if (Inside<int32_t>(cObj->GetY()-Target->GetY(),30,50))
1087  {
1088  int32_t iSideX=1; if (Random(2)) iSideX=-1;
1089  iSideX=cObj->GetX()+iSideX*(cObj->GetY()-Target->GetY());
1090  if (PathFree(iSideX,cObj->GetY(),Target->GetX(),Target->GetY()))
1091  {
1092  // Side-move jump
1093  cObj->AddCommand(C4CMD_Jump,nullptr,Tx._getInt(),Ty);
1094  // FIXME: Drop stuff if full here
1095  cObj->AddCommand(C4CMD_MoveTo,nullptr,iSideX,cObj->GetY(),50);
1096  }
1097  }
1098  // Move to target (random offset for difficult pickups)
1099  // ...avoid offsets into solid which would lead to high above surface locations!
1100  cObj->AddCommand(C4CMD_MoveTo,nullptr,Target->GetX()+Random(15)-7,Target->GetY(),25,nullptr);
1101  }
1102 
1103  }
1104 
1105 }
1106 
1108 {
1109 
1110  // Container specified, but no Target & no type: open activate menu for container
1111  if (Target2 && !Target && !Data)
1112  {
1114  Finish(true);
1115  return;
1116  }
1117 
1118  // Target object specified & outside: success
1119  if (Target)
1120  if (!Target->Contained)
1121  { Finish(true); return; }
1122 
1123  // No container specified: determine container by target object
1124  if (!Target2)
1125  if (Target)
1127 
1128  // No container specified: fail
1129  if (!Target2) { Finish(); return; }
1130 
1131  // Digging: stop
1133 
1134  // In container
1135  if (cObj->Contained==Target2)
1136  {
1137  for (Tx.SetInt(Data ? std::max<int32_t>(Tx._getInt(),1) : 1); Tx._getInt(); --Tx)
1138  {
1139  // If not specified get object from target contents by type
1140  // Find first object requested id that has no command exit yet
1141  if (!Target)
1142  for (C4Object *pObj : Target2->Contents)
1143  if (pObj->Status && (pObj->Def==Data.getDef()))
1144  if (!pObj->Command || (pObj->Command->Command!=C4CMD_Exit))
1145  { Target=pObj; break; }
1146  // No target
1147  if (!Target) { Finish(); return; }
1148 
1149  // Thing in own container (target2)
1150  if (Target->Contained!=Target2) { Finish(); return; }
1151 
1152  // Activate object to exit
1155  Target = 0;
1156  }
1157 
1158  Finish(true); return;
1159  }
1160 
1161  // Leave own container
1162  if (cObj->Contained)
1163  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
1164 
1165  // Target container has entrance: enter
1166  if (Target2->OCF & OCF_Entrance)
1167  { cObj->AddCommand(C4CMD_Enter,Target2,0,0,50); return; }
1168 
1169  // Can't get to target due to target container: fail
1170  Finish();
1171 
1172 }
1173 
1174 
1175 void C4Command::Put() // Notice: Put command is currently using Ty as an internal reminder flag for letting go after putting...
1176 {
1177  // No target container: failure
1178  if (!Target) { Finish(); return; }
1179 
1180  // Thing to put specified by type
1181  if (!Target2 && Data)
1182  if (!(Target2 = cObj->Contents.Find(Data.getDef())))
1183  { Finish(); return; }
1184 
1185  // No thing to put specified
1186  if (!Target2)
1187  // Assume first contents object
1188  if (!(Target2 = cObj->Contents.GetObject()))
1189  // No contents object to put - most likely we did have a target but it was deleted,
1190  // e.g. by AutoSellContents in a base. New behaviour: if there is nothing to put, we
1191  // now consider the command succesfully completed.
1192  { Finish(true); return; }
1193 
1194  // Thing is in target
1195  if (Target2->Contained == Target)
1196  {
1197  // Put-count specified: decrease count and continue with next object
1198  if (Tx._getInt() > 1)
1199  { Target2 = nullptr; Tx--; return; }
1200  // We're done
1201  else
1202  { Finish(true); return; }
1203  }
1204 
1205  // Thing to put not in contents: get object
1206  if (!cObj->Contents.GetLink(Target2))
1207  {
1208  // Object is nearby and traveling: wait
1209  if (!Target2->Contained)
1210  if (Distance(cObj->GetX(),cObj->GetY(),Target2->GetX(),Target2->GetY())<80)
1211  if (Target2->OCF & OCF_HitSpeed1)
1212  return;
1213  // Go get it
1214  cObj->AddCommand(C4CMD_Get,Target2,0,0,40); return;
1215  }
1216 
1217  // Target is contained: can't do it
1218  if (Target->Contained)
1219  { Finish(); return; }
1220 
1221  // Digging: stop
1223 
1224  // Grabbing other than target: let go
1225  C4Object *pGrabbing=nullptr;
1226  if (cObj->GetProcedure()==DFA_PUSH)
1227  pGrabbing = cObj->Action.Target;
1228  if (pGrabbing && (pGrabbing!=Target))
1229  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
1230 
1231  // Inside target container
1232  if (cObj->Contained == Target)
1233  {
1234  // Try to put
1236  Finish(); // Putting failed
1237  return;
1238  }
1239 
1240  // Leave own container
1241  if (cObj->Contained)
1242  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
1243 
1244  // Target has collection: throw in if not fragile, not grabbing target and throwing position found
1245  if (Target->OCF & OCF_Collection)
1246  if (!Target2->Def->Fragile)
1247  if (pGrabbing!=Target)
1248  {
1249  int32_t iTx = Target->GetX() + Target->Def->Collection.x + Target->Def->Collection.Wdt/2;
1250  int32_t iTy = Target->GetY() + Target->Def->Collection.y + Target->Def->Collection.Hgt/2;
1252  int32_t iHeight = cObj->Shape.Hgt;
1253  int32_t iPosX,iPosY;
1254  int32_t iObjDist = Distance(cObj->GetX(),cObj->GetY(),Target->GetX(),Target->GetY());
1255  if ( (FindThrowingPosition(iTx,iTy,pthrow,-pthrow,iHeight,iPosX,iPosY) && (Distance(iPosX,iPosY,cObj->GetX(),cObj->GetY()) < iObjDist))
1256  || (FindThrowingPosition(iTx,iTy,pthrow*-1,-pthrow,iHeight,iPosX,iPosY) && (Distance(iPosX,iPosY,cObj->GetX(),cObj->GetY()) < iObjDist)) )
1257  {
1258  // Throw
1259  cObj->AddCommand(C4CMD_Throw,Target2,iTx,iTy,5);
1260  return;
1261  }
1262  }
1263 
1264  // Target has C4D_Grab_Put: grab target and put
1266  {
1267  // Grabbing target container
1268  if (pGrabbing==Target)
1269  {
1270  // Try to put
1272  // Putting failed
1273  { Finish(); return; }
1274  // Let go (if we grabbed the target because of this command)
1275  if (Ty) cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0);
1276  return;
1277  }
1278  // Grab target and let go after putting
1279  cObj->AddCommand(C4CMD_Grab,Target,0,0,50);
1280  Ty = 1;
1281  return;
1282  }
1283 
1284  // Target can be entered: enter target
1285  if (Target->OCF & OCF_Entrance)
1286  { cObj->AddCommand(C4CMD_Enter,Target,0,0,50); return; }
1287 
1288 }
1289 
1291 {
1292  if (cObj==pObj) cObj=nullptr;
1293  if (Target==pObj) Target=nullptr;
1294  if (Target2==pObj) Target2=nullptr;
1295 }
1296 
1298 {
1299 
1300  // Finished?!
1301  if (Finished) return;
1302 
1303  // Parent object safety
1304  if (!cObj) { Finish(); return; }
1305 
1306  // Delegated command failed
1307  if (Failures)
1308  {
1309  // Retry
1310  if (Retries>0)
1311  { Failures=0; Retries--; cObj->AddCommand(C4CMD_Retry,nullptr,0,0,10); return; }
1312  // Too many failures
1313  else
1314  { Finish(); return; }
1315  }
1316 
1317  // Command update
1318  if (UpdateInterval>0)
1319  {
1320  UpdateInterval--;
1321  if (UpdateInterval==0)
1322  {
1323  Finish(true); return;
1324  }
1325  }
1326 
1327  // Initial command evaluation
1328  if (InitEvaluation()) return;
1329 
1330  // from now on, we are executing this command... and nobody
1331  // should dare deleting us
1332  iExec = 1;
1333 
1334  // Execute
1335  switch (Command)
1336  {
1337  case C4CMD_Follow: Follow(); break;
1338  case C4CMD_MoveTo: MoveTo(); break;
1339  case C4CMD_Enter: Enter(); break;
1340  case C4CMD_Exit: Exit(); break;
1341  case C4CMD_Grab: Grab(); break;
1342  case C4CMD_UnGrab: UnGrab(); break;
1343  case C4CMD_Throw: Throw(); break;
1344  case C4CMD_Jump: Jump(); break;
1345  case C4CMD_Wait: Wait(); break;
1346  case C4CMD_Get: Get(); break;
1347  case C4CMD_Put: Put(); break;
1348  case C4CMD_Drop: Drop(); break;
1349  case C4CMD_Dig: Dig(); break;
1350  case C4CMD_Activate: Activate(); break;
1351  case C4CMD_PushTo: PushTo(); break;
1352  case C4CMD_Transfer: Transfer(); break;
1353  case C4CMD_Attack: Attack(); break;
1354  case C4CMD_Buy: Buy(); break;
1355  case C4CMD_Sell: Sell(); break;
1356  case C4CMD_Acquire: Acquire(); break;
1357  case C4CMD_Retry: Retry(); break;
1358  case C4CMD_Home: Home(); break;
1359  case C4CMD_Call: Call(); break;
1360  case C4CMD_Take: Take(); break; // carlo
1361  case C4CMD_Take2: Take2(); break; // carlo
1362  default: Finish(); break;
1363  }
1364 
1365  /* // Remember this command might have already been deleted through calls
1366  // made during execution. You must not do anything here... */
1367 
1368  // check: command must be deleted?
1369  if (iExec > 1)
1370  delete this;
1371  else
1372  iExec = 0;
1373 
1374 }
1375 
1376 void C4Command::Finish(bool fSuccess, const char *szFailMessage)
1377 {
1378  // Mark finished
1379  Finished=true;
1380  // Failed
1381  if (!fSuccess)
1382  Fail(szFailMessage);
1383  else
1384  {
1385  // successful commands might gain EXP
1386  int32_t iExpGain = GetExpGain();
1387  if (iExpGain && cObj) if (cObj->Info)
1388  for (int32_t i=iExpGain; i; --i)
1389  if (!(++cObj->Info->ControlCount%5))
1390  cObj->DoExperience(1);
1391  }
1392 }
1393 
1395 {
1396  // Already evaluated
1397  if (Evaluated) return false;
1398  // Set evaluation flag
1399  Evaluated=true;
1400  // Evaluate
1401  switch (Command)
1402  {
1403  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1404  case C4CMD_MoveTo:
1405  {
1406  // Target coordinates by Target
1407  if (Target) { Tx+=Target->GetX(); Ty+=Target->GetY(); Target=nullptr; }
1408  // Adjust coordinates
1409  int32_t iTx = Tx._getInt();
1411  Tx.SetInt(iTx);
1412  return true;
1413  }
1414  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1415  case C4CMD_PushTo:
1416  {
1417  // Adjust coordinates
1418  int32_t iTx = Tx._getInt();
1420  Tx.SetInt(iTx);
1421  return true;
1422  }
1423  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1424  case C4CMD_Exit:
1425  // Cancel attach
1427  return true;
1428  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1429  case C4CMD_Jump:
1430  {
1431  if (Tx._getInt())
1432  {
1433  if (Tx._getInt()<cObj->GetX()) cObj->SetDir(DIR_Left);
1434  if (Tx._getInt()>cObj->GetX()) cObj->SetDir(DIR_Right);
1435  }
1437  return true;
1438  }
1439  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1440  case C4CMD_Wait:
1441  // Update interval by Data
1442  if (!!Data) UpdateInterval=Data.getInt();
1443  // Else update interval by Tx
1444  else if (Tx._getInt()) UpdateInterval=Tx._getInt();
1445  return true;
1446  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1447  case C4CMD_Acquire:
1448  // update default search range
1449  if (!Tx._getInt()) Tx.SetInt(500);
1450  if (!Ty) Ty=250;
1451  return true;
1452  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1453  }
1454  // Need not be evaluated
1455  return false;
1456 }
1457 
1459 {
1461  cObj=nullptr;
1462  Evaluated=false;
1463  PathChecked=false;
1464  Tx=C4VNull;
1465  Ty=0;
1466  Target=Target2=nullptr;
1467  UpdateInterval=0;
1468  if (Text) Text->DecRef(); Text=nullptr;
1470 }
1471 
1472 bool C4Command::FlightControl() // Called by DFA_WALK, DFA_FLIGHT
1473 {
1474  // Crew members or pathfinder objects only
1475  if (!((cObj->OCF & OCF_CrewMember) || cObj->Def->Pathfinder)) return false;
1476 
1477  // Not while in a disabled action
1478  C4PropList* pActionDef = cObj->GetAction();
1479  if (pActionDef)
1480  {
1481  if (pActionDef->GetPropertyInt(P_ObjectDisabled)) return false;
1482  }
1483 
1484  // Target angle
1485  int32_t cx=cObj->GetX(),cy=cObj->GetY();
1486  int32_t iAngle = Angle(cx,cy,Tx._getInt(),Ty); while (iAngle>180) iAngle-=360;
1487 
1488  // Target in flight angle (sector +/- from straight up), beyond minimum distance, and top free
1489  if (Inside(iAngle, -FlightAngleRange, +FlightAngleRange)
1490  || Inside(iAngle, -FlightAngleRange, +FlightAngleRange))
1491  if (Distance(cx,cy,Tx._getInt(),Ty) > 30)
1492  {
1493  int32_t iTopFree;
1494  for (iTopFree=0; (iTopFree<50) && !GBackSolid(cx,cy+cObj->Shape.GetY()-iTopFree); ++iTopFree) {}
1495  if (iTopFree>=15)
1496  {
1497  // Take off
1498  return cObj->SetActionByName("Fly"); // This is a little primitive... we should have a ObjectActionFly or maybe a command for this...
1499  }
1500  }
1501 
1502  // No flight control
1503  return false;
1504 }
1505 
1506 bool C4Command::JumpControl() // Called by DFA_WALK
1507 {
1508 
1509  // Crew members or pathfinder objects only
1510  if (! ((cObj->OCF & OCF_CrewMember) || cObj->Def->Pathfinder) ) return false;
1511 
1512  // Target angle
1513  int32_t cx=cObj->GetX(),cy=cObj->GetY();
1514  int32_t iAngle = Angle(cx,cy,Tx._getInt(),Ty); while (iAngle>180) iAngle-=360;
1515 
1516  // Diagonal free jump (if in angle range, minimum distance, and top free)
1519  if (PathFree(cx,cy,Tx._getInt(),Ty))
1520  if (Distance(cx,cy,Tx._getInt(),Ty)>30)
1521  {
1522  int32_t iTopFree;
1523  for (iTopFree=0; (iTopFree<50) && !GBackSolid(cx,cy+cObj->Shape.GetY()-iTopFree); ++iTopFree) {}
1524  if (iTopFree>=15)
1525  {
1526  cObj->AddCommand(C4CMD_Jump,nullptr,Tx,Ty); return true;
1527  }
1528  }
1529 
1530  // High angle side move - jump (2x range)
1531  if (Inside<int32_t>(iAngle-JumpHighAngle,-3*JumpAngleRange,+3*JumpAngleRange))
1532  // Vertical range
1533  if (Inside<int32_t>(cy-Ty,10,40))
1534  {
1535  int32_t iSide=SolidOnWhichSide(Tx._getInt(),Ty); // take jump height of side move position into consideration...!
1536  int32_t iDist=5*Abs(cy-Ty)/6;
1537  int32_t iSideX=cx-iDist*iSide,iSideY=cy; AdjustMoveToTarget(iSideX,iSideY,false,0);
1538  // Side move target in range
1539  if (Inside<int32_t>(iSideY-cy,-20,+20))
1540  {
1541  // Path free from side move target to jump target
1542  if (PathFree(iSideX,iSideY,Tx._getInt(),Ty))
1543  {
1544  cObj->AddCommand(C4CMD_Jump,nullptr,Tx,Ty);
1545  cObj->AddCommand(C4CMD_MoveTo,nullptr,iSideX,iSideY,50);
1546  return true;
1547  }
1548  }
1549  }
1550 
1551  // Low side contact jump
1552  // Only jump before almost running off a cliff
1553  int32_t iLowSideRange=5;
1554  if (!(GBackDensity(cx,cy+cObj->Shape.Hgt/2) >= cObj->Shape.ContactDensity))
1555  {
1556  if (cObj->t_contact & CNAT_Right)
1557  if (Inside(iAngle-JumpLowAngle,-iLowSideRange*JumpAngleRange,+iLowSideRange*JumpAngleRange))
1558  {
1559  cObj->AddCommand(C4CMD_Jump,nullptr,Tx,Ty); return true;
1560  }
1561  if (cObj->t_contact & CNAT_Left)
1562  if (Inside(iAngle+JumpLowAngle,-iLowSideRange*JumpAngleRange,+iLowSideRange*JumpAngleRange))
1563  {
1564  cObj->AddCommand(C4CMD_Jump,nullptr,Tx,Ty); return true;
1565  }
1566  }
1567 
1568  // No jump control
1569  return false;
1570 }
1571 
1573 {
1574 
1575  // No target: failure
1576  if (!Target) { Finish(); return; }
1577 
1578  // Find transfer zone
1579  C4TransferZone *pZone;
1580  int32_t iEntryX,iEntryY;
1581  if (!(pZone=Game.TransferZones.Find(Target))) { Finish(); return; }
1582 
1583  // Not at or in transfer zone: move to entry point
1584  if (!Inside<int32_t>(cObj->GetX()-pZone->X,-5,pZone->Wdt-1+5))
1585  {
1586  if (!pZone->GetEntryPoint(iEntryX,iEntryY,cObj->GetX(),cObj->GetY())) { Finish(); return; }
1587  cObj->AddCommand(C4CMD_MoveTo,nullptr,iEntryX,iEntryY,25);
1588  return;
1589  }
1590 
1591  // Call target transfer script
1592  if (!::Game.iTick5)
1593  {
1595  // Transfer not handled by target: done
1596  { Finish(true); return; }
1597  }
1598 
1599 }
1600 
1602 {
1603 
1604  // No target: failure
1605  if (!Target) { Finish(); return; }
1606 
1607  // Target is crew member
1608  if (Target->OCF & OCF_CrewMember)
1609  {
1610 
1611  // Throw projectile at target
1612  for (C4Object *pProjectile : cObj->Contents)
1613  if (pProjectile->Def->Projectile)
1614  {
1615  // Add throw command
1616  cObj->AddCommand(C4CMD_Throw,pProjectile,Target->GetX(),Target->GetY(),2);
1617  return;
1618  }
1619 
1620  // Follow containment
1621  if (cObj->Contained!=Target->Contained)
1622  {
1623  // Exit
1624  if (cObj->Contained) cObj->AddCommand(C4CMD_Exit,nullptr,0,0,10);
1625  // Enter
1626  else cObj->AddCommand(C4CMD_Enter,Target->Contained,0,0,10);
1627  return;
1628  }
1629 
1630  // Move to target
1631  cObj->AddCommand(C4CMD_MoveTo,nullptr,Target->GetX(),Target->GetY(),10);
1632  return;
1633 
1634  }
1635 
1636  // For now, attack crew members only
1637  else
1638  {
1639  // Success, target might be no crew member due to that is has been killed
1640  Finish(true);
1641  return;
1642  }
1643 
1644 }
1645 
1647 {
1648  Finish();
1649 }
1650 
1652 {
1653  Finish();
1654 }
1655 
1657 {
1658 
1659  // No type to acquire specified: fail
1660  if (!Data) { Finish(); return; }
1661 
1662  // Target material in inventory: done
1663  if (cObj->Contents.Find(Data.getDef()))
1664  { Finish(true); return; }
1665 
1666  // script overload
1667  int32_t scriptresult = cObj->Call(PSF_ControlCommandAcquire, &C4AulParSet(Target, Tx, Ty, Target2, Data)).getInt ();
1668 
1669  // script call might have deleted object
1670  if (!cObj->Status) return;
1671  if (1 == scriptresult) return;
1672  if (2 == scriptresult)
1673  { Finish(true); return; }
1674  if (3 == scriptresult)
1675  { Finish(); return; }
1676 
1677  // Find available material
1678  C4Object *pMaterial=nullptr;
1679  // Next closest
1680  while ((pMaterial = Game.FindObject(Data.getDef(),cObj->GetX(),cObj->GetY(),-1,-1,OCF_Available,pMaterial)))
1681  // Object is not in container to be ignored
1682  if (!Target2 || pMaterial->Contained!=Target2)
1683  // Object is near enough
1684  if (Inside(cObj->GetX()-pMaterial->GetX(),-Tx._getInt(),+Tx._getInt()))
1685  if (Inside(cObj->GetY()-pMaterial->GetY(),-Ty,+Ty))
1686  // Must be complete
1687  if (pMaterial->OCF & OCF_FullCon)
1688  // Doesn't burn
1689  if (!pMaterial->GetOnFire())
1690  // We found one
1691  break;
1692 
1693  // Available material found: get material
1694  if (pMaterial)
1695  { cObj->AddCommand(C4CMD_Get,pMaterial,0,0,40); return; }
1696 
1697  // No available material found: buy material
1698  // This command will fail immediately if buying at bases is not possible
1699  // - but the command should be created anyway because it might be overloaded
1700  cObj->AddCommand(C4CMD_Buy,nullptr,0,0,100,nullptr,true,Data,false,0,0,C4CMD_Mode_Sub);
1701 
1702 }
1703 
1704 void C4Command::Fail(const char *szFailMessage)
1705 {
1706  // Check for base command (next unfinished)
1707  C4Command *pBase;
1708  for (pBase=Next; pBase; pBase=pBase->Next) if (!pBase->Finished) break;
1709 
1710  bool ExecFail = false;
1711  switch (BaseMode)
1712  {
1713  // silent subcommand
1714  case C4CMD_Mode_SilentSub:
1715  {
1716  // Just count failures in base command
1717  if (pBase) { pBase->Failures++; return; }
1718  else ExecFail = true;
1719  break;
1720  }
1721  // verbose subcommand
1722  case C4CMD_Mode_Sub:
1723  {
1724  // Count failures in base command
1725  if (pBase) { pBase->Failures++; }
1726  // Execute fail message, if base will fail
1727  if (!pBase || !pBase->Retries) ExecFail = true;
1728  break;
1729  }
1730  // base command
1731  case C4CMD_Mode_Base:
1732  {
1733  // Just execute fail notice
1734  ExecFail = true;
1735  break;
1736  }
1737  // silent base command: do nothing
1738  }
1739 
1740  char szCommandName[24 + 1];
1741  char szObjectName[C4MaxName + 1];
1742  StdStrBuf str;
1743 
1744  if (ExecFail && cObj && (cObj->OCF & OCF_CrewMember))
1745  {
1746  // Fail message
1747  if (szFailMessage)
1748  str = szFailMessage;
1749  C4Object * l_Obj = cObj;
1750  switch (Command)
1751  {
1752  case C4CMD_Call:
1753  {
1754  // Call fail-function in target object (no message if non-zero)
1755  int32_t l_Command = Command;
1756  if (CallFailed()) return;
1757  // Fail-function not available or returned zero: standard message
1758  SCopy(LoadResStr(CommandNameID(l_Command)),szCommandName);
1759  str.Format(LoadResStr("IDS_CON_FAILURE"),szCommandName);
1760  break;
1761  }
1762  case C4CMD_Exit:
1763  // No message
1764  break;
1765  case C4CMD_Dig:
1766  // No message
1767  break;
1768  case C4CMD_Acquire:
1769  // Already has a fail message
1770  if (szFailMessage) break;
1771  // Fail message with name of target type
1772  SCopy(LoadResStr(CommandNameID(Command)), szCommandName);
1773  C4Def *pDef; pDef = Data.getDef();
1774  SCopy(pDef ? pDef->GetName() : LoadResStr("IDS_OBJ_UNKNOWN"), szObjectName);
1775  str.Format(LoadResStr("IDS_CON_FAILUREOF"), szCommandName, szObjectName);
1776  break;
1777  default:
1778  // Already has a fail message
1779  if (szFailMessage) break;
1780  // Standard no-can-do message
1781  SCopy(LoadResStr(CommandNameID(Command)), szCommandName);
1782  str.Format(LoadResStr("IDS_CON_FAILURE"), szCommandName);
1783  break;
1784  }
1785  if (l_Obj) if (l_Obj->Status && !l_Obj->Def->SilentCommands)
1786  {
1787  // Message (if not empty)
1788  if (!!str)
1789  {
1790  ::Messages.Append(C4GM_Target, str.getData(), l_Obj, NO_OWNER, 0, 0, C4RGB(0xff, 0xff, 0xff), true);
1791  }
1792  // Stop Clonk
1793  l_Obj->Action.ComDir = COMD_Stop;
1794  // Clonk-specific fail action/sound
1796  l_Obj->Call(PSF_CommandFailure, &pars);
1797  }
1798  }
1799 }
1800 
1802 {
1803 
1804 }
1805 
1807 {
1808  Finish();
1809 }
1810 
1811 void C4Command::Set(int32_t iCommand, C4Object *pObj, C4Object *pTarget, C4Value nTx, int32_t iTy,
1812  C4Object *pTarget2, C4Value iData, int32_t iUpdateInterval,
1813  bool fEvaluated, int32_t iRetries, C4String * szText, int32_t iBaseMode)
1814 {
1815  // Reset
1816  Clear(); Default();
1817  // Set
1818  Command=iCommand;
1819  cObj=pObj;
1820  Target=pTarget;
1821  Tx=nTx; Ty=iTy;
1823  Tx.SetInt(0);
1824  Target2=pTarget2;
1825  Data=iData;
1826  UpdateInterval=iUpdateInterval;
1827  Evaluated=fEvaluated;
1828  Retries=iRetries;
1829  Text = szText;
1830  if (Text) Text->IncRef();
1831  BaseMode=iBaseMode;
1832 }
1833 
1835 {
1836  // No function name: fail
1837  if (!Text || !Text->GetCStr() || !Text->GetCStr()[0]) { Finish(); return; }
1838  // No target object: fail
1839  if (!Target) { Finish(); return; }
1840  // Done: success
1841  Finish(true);
1842  // Object call FIXME:use c4string-api
1844  // Extreme caution notice: the script call might do just about anything
1845  // including clearing all commands (including this) i.e. through a call
1846  // to SetCommand. Thus, we must not do anything in this command anymore
1847  // after the script call (even the Finish has to be called before).
1848  // The Finish call being misled to the freshly created Build command (by
1849  // chance, the this-pointer was simply crap at the time) was reason for
1850  // the latest sync losses in 4.62.
1851 }
1852 
1854 {
1855  // Version
1856  int32_t iVersion = 0;
1857  if (pComp->Separator(StdCompiler::SEP_DOLLAR))
1858  {
1859  iVersion = 1;
1860  pComp->Value(mkIntPackAdapt(iVersion));
1862  }
1863  else
1864  pComp->NoSeparator();
1865  // Command name
1866  pComp->Value(mkEnumAdaptT<uint8_t>(Command, EnumAdaptCommandEntries));
1868  // Target X/Y
1869  pComp->Value(mkParAdapt(Tx, numbers)); pComp->Separator(StdCompiler::SEP_SEP);
1871  // Target
1872  pComp->Value(Target); pComp->Separator(StdCompiler::SEP_SEP);
1873  pComp->Value(Target2); pComp->Separator(StdCompiler::SEP_SEP);
1874  // Data
1875  pComp->Value(mkParAdapt(Data, numbers)); pComp->Separator(StdCompiler::SEP_SEP);
1876  // Update interval
1878  // Flags
1882  // Retries
1886  // Base mode
1887  if (iVersion > 0)
1888  {
1890  }
1891  // Text
1892  StdStrBuf TextBuf;
1893  if (pComp->isSerializer())
1894  {
1895  if (Text)
1896  TextBuf.Ref(Text->GetData());
1897  else
1898  TextBuf.Ref("0");
1899  }
1900  pComp->Value(mkParAdapt(TextBuf, StdCompiler::RCT_All));
1901  if (pComp->isDeserializer())
1902  {
1903  if (Text)
1904  Text->DecRef();
1905  if (TextBuf == "0")
1906  { Text = nullptr; }
1907  else
1908  { Text = Strings.RegString(TextBuf); Text->IncRef(); }
1909  }
1910 }
1911 
1913 {
1916  Tx.Denumerate(numbers);
1917 }
1918 
1920 {
1921  // No function name or no target object: cannot call fail-function
1922  if (!Text || !Text->GetCStr() || !Text->GetCStr()[0] || !Target) return 0;
1923  // Compose fail-function name
1924  char szFunctionFailed[1024+1]; sprintf(szFunctionFailed,"~%sFailed",Text->GetCStr());
1925  // Call failed-function
1926  return Target->Call(szFunctionFailed,&C4AulParSet(cObj, Tx, Ty, Target2))._getInt();
1927  // Extreme caution notice: the script call might do just about anything
1928  // including clearing all commands (including this) i.e. through a call
1929  // to SetCommand. Thus, we must not do anything in this command anymore
1930  // after the script call.
1931 }
1932 
1934 {
1935  // return exp gained by this command
1936  switch (Command)
1937  {
1938  // internal
1939  case C4CMD_Wait:
1940  case C4CMD_Transfer:
1941  case C4CMD_Retry:
1942  case C4CMD_Call:
1943  return 0;
1944 
1945  // regular move commands
1946  case C4CMD_Follow:
1947  case C4CMD_MoveTo:
1948  case C4CMD_Enter:
1949  case C4CMD_Exit:
1950  return 1;
1951 
1952  // simple activities
1953  case C4CMD_Grab:
1954  case C4CMD_UnGrab:
1955  case C4CMD_Throw:
1956  case C4CMD_Jump:
1957  case C4CMD_Get:
1958  case C4CMD_Put:
1959  case C4CMD_Drop:
1960  case C4CMD_Activate:
1961  case C4CMD_PushTo:
1962  case C4CMD_Dig:
1963  case C4CMD_Buy:
1964  case C4CMD_Sell:
1965  case C4CMD_Take:
1966  case C4CMD_Take2:
1967  return 1;
1968 
1969  // not that simple
1970  case C4CMD_Acquire:
1971  case C4CMD_Home:
1972  return 2;
1973 
1974  // victory!
1975  case C4CMD_Attack:
1976  return 15;
1977  }
1978  // unknown command
1979  return 0;
1980 }
const char * getData() const
Definition: StdBuf.h:450
int32_t GetY() const
Definition: C4Object.h:287
const uint32_t OCF_HitSpeed1
Definition: C4Constants.h:84
int32_t Pathfinder
Definition: C4Def.h:137
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:129
int32_t CommandByName(const char *szCommand)
Definition: C4Command.cpp:128
void Sell()
Definition: C4Command.cpp:1651
StdStrBuf GetData() const
Definition: C4StringTable.h:50
void Drop()
Definition: C4Command.cpp:843
C4Object * cObj
Definition: C4Command.h:80
bool ObjectComGrab(C4Object *cObj, C4Object *pTarget)
bool ObjectComUnGrab(C4Object *cObj)
#define COMD_UpRight
Definition: C4Object.h:52
const int32_t DigOutDirectRange
Definition: C4Command.cpp:43
const char * CommandName(int32_t iCommand)
Definition: C4Command.cpp:48
bool Enter(C4Object *pTarget, bool fCalls=true, bool fCopyMotion=true, bool *pfRejectCollect=nullptr)
Definition: C4Object.cpp:1267
virtual void NoSeparator()
Definition: StdCompiler.h:130
bool InitEvaluation()
Definition: C4Command.cpp:1394
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:129
const uint32_t OCF_Entrance
Definition: C4Constants.h:90
const uint32_t OCF_Collection
Definition: C4Constants.h:93
void Take()
Definition: C4Command.cpp:831
virtual const char * GetName() const
Definition: C4PropList.cpp:267
int32_t NoTransferZones
Definition: C4Def.h:149
uint32_t Random()
Definition: C4Random.cpp:43
void Wait()
Definition: C4Command.cpp:922
int32_t Evaluated
Definition: C4Command.h:87
int32_t Time
Definition: C4Object.h:83
int32_t iTick5
Definition: C4Game.h:131
#define COMD_Down
Definition: C4Object.h:55
Definition: StdAdaptors.h:763
BYTE GetEntranceArea(int32_t &aX, int32_t &aY, int32_t &aWdt, int32_t &aHgt) const
Definition: C4Object.cpp:1595
const int32_t LetGoHangleAngle
Definition: C4Command.cpp:44
const int32_t C4CMD_Mode_Base
Definition: C4Command.h:60
void Activate()
Definition: C4Command.cpp:1107
C4Game Game
Definition: C4Globals.cpp:52
bool ObjectComCancelAttach(C4Object *cObj)
int32_t GetY() const
Definition: C4Shape.h:64
void IncRef()
Definition: C4StringTable.h:27
C4Value Data
Definition: C4Command.h:85
int32_t iTick35
Definition: C4Game.h:131
#define COMD_DownRight
Definition: C4Object.h:54
C4Command * Next
Definition: C4Command.h:90
void SetDir(int32_t tdir)
Definition: C4Object.cpp:2847
int32_t Projectile
Definition: C4Def.h:134
void Attack()
Definition: C4Command.cpp:1601
#define sprintf
Definition: Standard.h:171
int32_t Permit
Definition: C4Command.h:88
void Grab()
Definition: C4Command.cpp:671
bool GetTryEnter()
Definition: C4Command.cpp:928
const int32_t JumpAngleRange
Definition: C4Command.cpp:41
void Finish(bool fSuccess=false, const char *szFailMessage=0)
Definition: C4Command.cpp:1376
void Take2()
Definition: C4Command.cpp:837
int32_t ControlCount
Definition: C4ObjectInfo.h:38
C4PropList * GetAction() const
Definition: C4Object.cpp:2681
void Transfer()
Definition: C4Command.cpp:1572
#define DIR_Right
Definition: C4Object.h:42
C4Command * Command
Definition: C4Object.h:166
const char * GetCStr() const
Definition: C4StringTable.h:49
int32_t Retries
Definition: C4Command.h:88
C4String * RegString(StdStrBuf String)
void Execute()
Definition: C4Command.cpp:1297
int32_t ContactDensity
Definition: C4Shape.h:48
C4Value C4VInt(int32_t i)
Definition: C4Value.h:242
int32_t BaseMode
Definition: C4Command.h:92
bool SetActionByName(C4String *ActName, C4Object *pTarget=nullptr, C4Object *pTarget2=nullptr, int32_t iCalls=SAC_StartCall|SAC_AbortCall, bool fForce=false)
Definition: C4Object.cpp:2821
void Dig()
Definition: C4Command.cpp:456
int32_t Ty
Definition: C4Command.h:83
bool AddCommand(int32_t iCommand, C4Object *pTarget, C4Value iTx, int32_t iTy=0, int32_t iUpdateInterval=0, C4Object *pTarget2=nullptr, bool fInitEvaluation=true, C4Value iData=C4VNull, bool fAppend=false, int32_t iRetries=0, C4String *szText=nullptr, int32_t iBaseMode=0)
Definition: C4Object.cpp:2569
const uint32_t OCF_InSolid
Definition: C4Constants.h:100
bool ObjectComPutTake(C4Object *cObj, C4Object *pTarget, C4Object *pThing)
StdEnumAdapt< int32_t >::Entry EnumAdaptCommandEntries[C4CMD_Last-C4CMD_First+2]
Definition: C4Command.cpp:46
bool Find(int32_t iFromX, int32_t iFromY, int32_t iToX, int32_t iToY, SetWaypointFn fnSetWaypoint)
const uint32_t OCF_CrewMember
Definition: C4Constants.h:98
const uint32_t OCF_Normal
Definition: C4Constants.h:79
const int32_t PathRange
Definition: C4Command.cpp:40
C4Real C4REAL100(int x)
Definition: C4Real.h:267
void Set0()
Definition: C4Value.h:336
void MoveTo()
Definition: C4Command.cpp:259
const int32_t LetGoRange1
Definition: C4Command.cpp:38
int32_t Finished
Definition: C4Command.h:87
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:181
bool getBool() const
Definition: C4Value.h:113
void ClearPointers(C4Object *pObj)
Definition: C4Command.cpp:1290
C4TransferZone * Find(C4Object *pObj)
C4Value Tx
Definition: C4Command.h:82
const int32_t JumpHighAngle
Definition: C4Command.cpp:41
void SetLevel(int iLevel)
bool AdjustSolidOffset(int32_t &rX, int32_t &rY, int32_t iXOff, int32_t iYOff)
Definition: C4Command.cpp:167
const int32_t LetGoRange2
Definition: C4Command.cpp:38
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:97
C4Value C4VObj(C4Object *pObj)
Definition: C4Value.cpp:90
int32_t SilentCommands
Definition: C4Def.h:142
void DenumeratePointers()
Definition: C4ObjectPtr.cpp:46
const int32_t C4D_Grab_Get
Definition: C4Def.h:65
#define PSF_ControlCommandAcquire
Definition: C4GameScript.h:163
const uint32_t OCF_FullCon
Definition: C4Constants.h:85
C4ObjectInfo * Info
Definition: C4Object.h:145
const int32_t C4CMD_Mode_SilentSub
Definition: C4Command.h:59
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
Definition: C4Real.h:58
ALWAYS_INLINE bool CheckConversion(C4V_Type vtToType) const
Definition: C4Value.h:189
int32_t GetExpGain()
Definition: C4Command.cpp:1933
const bool InitEnumAdaptCommandEntriesDummy
Definition: C4Command.cpp:126
int32_t Distance(int32_t iX1, int32_t iY1, int32_t iX2, int32_t iY2)
Definition: Standard.cpp:24
bool ObjectComStop(C4Object *cObj)
const int32_t FollowRange
Definition: C4Command.cpp:39
const C4ObjectLink * GetLink(const C4Object *pObj) const
bool ObjectComPut(C4Object *cObj, C4Object *pTarget, C4Object *pThing)
int32_t Wdt
Definition: C4Rect.h:32
int32_t NoPushEnter
Definition: C4Def.h:135
bool operator()(int32_t iX, int32_t iY, C4Object *TransferTarget)
Definition: C4Command.cpp:233
bool isSerializer()
Definition: StdCompiler.h:64
void Enter()
Definition: C4Command.cpp:566
int32_t UpdateInterval
Definition: C4Command.h:86
#define PSF_CommandFailure
Definition: C4GameScript.h:102
bool InitEnumAdaptCommandEntries()
Definition: C4Command.cpp:116
bool At(int32_t ctx, int32_t cty) const
Definition: C4Object.cpp:957
const int32_t C4D_Grab_Put
Definition: C4Def.h:64
void Home()
Definition: C4Command.cpp:1806
void Denumerate(C4ValueNumbers *)
Definition: C4Value.cpp:253
C4NotifyingObjectList Contents
Definition: C4Object.h:152
C4Object * FindObject(C4Def *pDef, int32_t iX=0, int32_t iY=0, int32_t iWdt=0, int32_t iHgt=0, DWORD ocf=OCF_All, C4Object *pFindNext=nullptr)
Definition: C4Game.cpp:1162
C4Def * Def
Definition: C4Object.h:143
bool FindClosestFree(int32_t &rX, int32_t &rY, int32_t iAngle1, int32_t iAngle2, int32_t iExcludeAngle1, int32_t iExcludeAngle2)
C4String * Text
Definition: C4Command.h:89
void Fail(const char *szFailMessage=0)
Definition: C4Command.cpp:1704
const int32_t FlightAngleRange
Definition: C4Command.cpp:42
bool Append(int32_t iType, const char *szText, C4Object *pTarget, int32_t iPlayer, int32_t iX, int32_t iY, uint32_t bCol, bool fNoDuplicates=false)
#define DIR_Left
Definition: C4Object.h:41
int32_t y
Definition: C4Rect.h:32
uint32_t t_contact
Definition: C4Object.h:133
void Buy()
Definition: C4Command.cpp:1646
bool ObjectComDrop(C4Object *cObj, C4Object *pThing)
C4StringTable Strings
Definition: C4Globals.cpp:42
bool GetOnFire() const
Definition: C4Object.h:303
const int32_t C4CMD_MoveTo_NoPosAdjust
Definition: C4Command.h:65
const int32_t C4CMD_First
Definition: C4Command.h:56
#define COMD_DownLeft
Definition: C4Object.h:56
C4Landscape Landscape
C4Rect Collection
Definition: C4Def.h:108
const int32_t DigRange
Definition: C4Command.cpp:38
int32_t Failures
Definition: C4Command.h:88
int32_t Command
Definition: C4Command.h:81
bool ObjectComJump(C4Object *cObj)
bool GetEntryPoint(int32_t &rX, int32_t &rY, int32_t iToX, int32_t iToY)
const int32_t DigOutPositionRange
Definition: C4Command.cpp:39
bool PutAwayUnusedObject(C4Object *pToMakeRoomForObject)
Definition: C4Object.cpp:4412
int32_t _getInt() const
Definition: C4Value.h:122
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:1231
void Default()
Definition: C4Command.cpp:209
const int32_t C4CMD_MoveTo_PushTarget
Definition: C4Command.h:66
int32_t GetX() const
Definition: C4Object.h:286
bool EntranceStatus
Definition: C4Object.h:132
Definition: C4Def.h:100
C4TransferZones TransferZones
Definition: C4Game.h:87
const unsigned int C4MaxName
const int NO_OWNER
Definition: C4Constants.h:138
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
const int32_t C4GM_Target
Definition: C4GameMessage.h:31
const int32_t C4CMD_Last
Definition: C4Command.h:57
bool ObjectComThrow(C4Object *cObj, C4Object *pThing)
int Angle(int iX1, int iY1, int iX2, int iY2)
Definition: Standard.cpp:35
C4Object * GetObject(int Index=0) const
#define C4RGB(r, g, b)
Definition: StdColors.h:28
void Denumerate(C4ValueNumbers *)
Definition: C4Command.cpp:1912
int32_t Status
Definition: C4PropList.h:170
void SetCommand(int32_t iCommand, C4Object *pTarget, C4Value iTx, int32_t iTy=0, C4Object *pTarget2=nullptr, bool fControl=false, C4Value iData=C4VNull, int32_t iRetries=0, C4String *szText=nullptr)
Definition: C4Object.cpp:2602
void Set(int32_t iCommand, C4Object *pObj, C4Object *pTarget, C4Value iTx, int32_t iTy, C4Object *pTarget2, C4Value iData, int32_t iUpdateInterval, bool fEvaluated, int32_t iRetries, C4String *szText, int32_t iBaseMode)
Definition: C4Command.cpp:1811
void Value(const T &rStruct)
Definition: StdCompiler.h:171
void SetInt(int32_t i)
Definition: C4Value.h:136
#define COMD_Right
Definition: C4Object.h:53
C4ObjectPtr Target
Definition: C4Command.h:84
#define COMD_Stop
Definition: C4Object.h:50
int32_t CrewMember
Definition: C4Def.h:114
ObjectAddWaypoint(C4Object *obj)
Definition: C4Command.cpp:232
const int32_t JumpLowAngle
Definition: C4Command.cpp:41
bool PathFree(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
const char * Name
Definition: StdAdaptors.h:765
int32_t getInt() const
Definition: C4Value.h:112
#define PSF_ControlTransfer
Definition: C4GameScript.h:78
virtual bool isDeserializer()
Definition: StdCompiler.h:63
int32_t x
Definition: C4Rect.h:32
#define PSF_RejectContents
Definition: C4GameScript.h:134
const int32_t JumpAngle
Definition: C4Command.cpp:41
int32_t GetHeight() const
const int32_t MoveToRange
Definition: C4Command.cpp:38
const char * CommandNameID(int32_t iCommand)
Definition: C4Command.cpp:82
void Ref(const char *pnData)
Definition: StdBuf.h:463
StdIntPackAdapt< T > mkIntPackAdapt(T &rVal)
Definition: StdAdaptors.h:760
int32_t SolidOnWhichSide(int32_t iX, int32_t iY)
Definition: C4Command.cpp:188
void AdjustMoveToTarget(int32_t &rX, int32_t &rY, bool fFreeMove, int32_t iShapeHgt)
Definition: C4Command.cpp:144
void Follow()
Definition: C4Command.cpp:514
const C4Value C4VNull
Definition: C4Value.cpp:32
C4ObjectPtr Target
Definition: C4Object.h:87
#define PSF_Get
Definition: C4GameScript.h:54
int32_t Data
Definition: C4Object.h:84
C4Object * Find(C4Def *def, int iOwner=ANY_OWNER, DWORD dwOCF=OCF_All)
C4ObjectPtr Target2
Definition: C4Command.h:84
C4Real fix_x
Definition: C4Object.h:125
void Call()
Definition: C4Command.cpp:1834
#define COMD_Up
Definition: C4Object.h:51
void Exit()
Definition: C4Command.cpp:632
bool GBackSemiSolid(int32_t x, int32_t y)
Definition: C4Landscape.h:237
void DoExperience(int32_t change)
Definition: C4Object.cpp:1217
#define COMD_Left
Definition: C4Object.h:57
int32_t GBackDensity(int32_t x, int32_t y)
Definition: C4Landscape.h:227
void PushTo()
Definition: C4Command.cpp:703
bool FreeMoveTo(C4Object *cObj)
Definition: C4Command.cpp:136
C4PathFinder PathFinder
Definition: C4Game.h:86
void Get()
Definition: C4Command.cpp:957
const int32_t MaxPathRange
Definition: C4Command.cpp:40
const uint32_t OCF_All
Definition: C4Constants.h:78
const BYTE CNAT_Right
Definition: C4Constants.h:111
int32_t Dir
Definition: C4Object.h:80
bool ObjectComTake(C4Object *cObj)
void Throw()
Definition: C4Command.cpp:757
int32_t iExec
Definition: C4Command.h:91
void Jump()
Definition: C4Command.cpp:900
int32_t GetProcedure() const
Definition: C4Object.cpp:2867
bool ActivateMenu(int32_t iMenu, int32_t iMenuSelect=0, int32_t iMenuData=0, int32_t iMenuPosition=0, C4Object *pTarget=nullptr)
Definition: C4Object.cpp:1483
int32_t MoveToRange
Definition: C4Def.h:138
void UnGrab()
Definition: C4Command.cpp:750
const uint32_t OCF_Carryable
Definition: C4Constants.h:82
C4Def * getDef() const
Definition: C4Value.cpp:80
int32_t GrabPutGet
Definition: C4Def.h:126
C4Value C4VString(C4String *pStr)
Definition: C4Value.h:246
void Clear()
Definition: C4Command.cpp:1458
int32_t NoGet
Definition: C4Def.h:147
const int32_t PushToRange
Definition: C4Command.cpp:39
void Put()
Definition: C4Command.cpp:1175
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val=0) const
Definition: C4PropList.cpp:863
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:459
const int32_t C4CMD_Enter_PushTarget
Definition: C4Command.h:68
C4Real fix_y
Definition: C4Object.h:125
C4ObjectPtr Contained
Definition: C4Object.h:144
bool ObjectComDig(C4Object *cObj)
const uint32_t OCF_Available
Definition: C4Constants.h:102
int32_t Hgt
Definition: C4Rect.h:32
T Abs(T val)
Definition: Standard.h:44
bool FlightControl()
Definition: C4Command.cpp:1472
C4GameMessageList Messages
C4Action Action
Definition: C4Object.h:147
C4Shape Shape
Definition: C4Object.h:148
int32_t Fragile
Definition: C4Def.h:133
void DecRef()
Definition: C4StringTable.h:28
uint32_t OCF
Definition: C4Object.h:134
void Retry()
Definition: C4Command.cpp:1801
bool ObjectComTake2(C4Object *cObj)
C4Value Call(C4PropertyName k, C4AulParSet *pPars=0, bool fPassErrors=false)
Definition: C4PropList.h:112
const int32_t C4CMD_Mode_Sub
Definition: C4Command.h:62
uint32_t DWORD
bool FindThrowingPosition(int32_t iTx, int32_t iTy, C4Real fXDir, C4Real fYDir, int32_t iHeight, int32_t &rX, int32_t &rY)
int32_t PathChecked
Definition: C4Command.h:87
C4Real xdir
Definition: C4Object.h:126
int32_t Controller
Definition: C4Object.h:111
bool ObjectComLetGo(C4Object *cObj, int32_t xdirf)
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *)
Definition: C4Command.cpp:1853
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:45
const BYTE CNAT_Left
Definition: C4Constants.h:110
C4Real ydir
Definition: C4Object.h:126
bool ActivateEntrance(int32_t by_plr, C4Object *by_obj)
Definition: C4Object.cpp:1355
int32_t CallFailed()
Definition: C4Command.cpp:1919
void EnableTransferZones(bool fEnabled)
void Acquire()
Definition: C4Command.cpp:1656
#define COMD_UpLeft
Definition: C4Object.h:58
int32_t ComDir
Definition: C4Object.h:82
bool GBackSolid(int32_t x, int32_t y)
Definition: C4Landscape.h:232
bool JumpControl()
Definition: C4Command.cpp:1506
int32_t iTick2
Definition: C4Game.h:131