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