OpenClonk
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 LetGoHangleAngle=110;
43 
45 
46 const char *CommandName(int32_t iCommand)
47 {
48  switch (iCommand)
49  {
50  case C4CMD_None: return "None";
51  case C4CMD_Follow: return "Follow";
52  case C4CMD_MoveTo: return "MoveTo";
53  case C4CMD_Enter: return "Enter";
54  case C4CMD_Exit: return "Exit";
55  case C4CMD_Grab: return "Grab";
56  case C4CMD_Throw: return "Throw";
57  case C4CMD_UnGrab: return "UnGrab";
58  case C4CMD_Jump: return "Jump";
59  case C4CMD_Wait: return "Wait";
60  case C4CMD_Get: return "Get";
61  case C4CMD_Put: return "Put";
62  case C4CMD_Drop: return "Drop";
63  case C4CMD_Dig: return "Dig";
64  case C4CMD_Activate: return "Activate";
65  case C4CMD_PushTo: return "PushTo";
66  case C4CMD_Transfer: return "Transfer";
67  case C4CMD_Attack: return "Attack";
68  case C4CMD_Buy: return "Buy";
69  case C4CMD_Sell: return "Sell";
70  case C4CMD_Acquire: return "Acquire";
71  case C4CMD_Retry: return "Retry";
72  case C4CMD_Home: return "Home";
73  case C4CMD_Call: return "Call";
74  case C4CMD_Take: return "Take";
75  case C4CMD_Take2: return "Take2";
76  default: return "None";
77  }
78 }
79 
80 const char* CommandNameID(int32_t iCommand)
81 {
82  switch (iCommand)
83  {
84  case C4CMD_None: return "IDS_COMM_NONE";
85  case C4CMD_Follow: return "IDS_COMM_FOLLOW";
86  case C4CMD_MoveTo: return "IDS_COMM_MOVETO";
87  case C4CMD_Enter: return "IDS_COMM_ENTER";
88  case C4CMD_Exit: return "IDS_COMM_EXIT";
89  case C4CMD_Grab: return "IDS_COMM_GRAB";
90  case C4CMD_Throw: return "IDS_COMM_THROW";
91  case C4CMD_UnGrab: return "IDS_COMM_UNGRAB";
92  case C4CMD_Jump: return "IDS_COMM_JUMP";
93  case C4CMD_Wait: return "IDS_COMM_WAIT";
94  case C4CMD_Get: return "IDS_COMM_GET";
95  case C4CMD_Put: return "IDS_COMM_PUT";
96  case C4CMD_Drop: return "IDS_COMM_DROP";
97  case C4CMD_Dig: return "IDS_COMM_DIG";
98  case C4CMD_Activate: return "IDS_COMM_ACTIVATE";
99  case C4CMD_PushTo: return "IDS_COMM_PUSHTO";
100  case C4CMD_Transfer: return "IDS_COMM_TRANSFER";
101  case C4CMD_Attack: return "IDS_COMM_ATTACK";
102  case C4CMD_Buy: return "IDS_COMM_BUY";
103  case C4CMD_Sell: return "IDS_COMM_SELL";
104  case C4CMD_Acquire: return "IDS_COMM_ACQUIRE";
105  case C4CMD_Retry: return "IDS_COMM_RETRY";
106  case C4CMD_Home: return "IDS_CON_HOME";
107  case C4CMD_Call: return "IDS_COMM_CALL";
108  case C4CMD_Take: return "IDS_COMM_TAKE";
109  case C4CMD_Take2: return "IDS_COMM_TAKE2";
110  default: return "IDS_COMM_NONE";
111  }
112 }
113 
115 {
116  for (int32_t i = C4CMD_First; i <= C4CMD_Last; i++)
117  {
120  }
121  EnumAdaptCommandEntries[C4CMD_Last - C4CMD_First + 1].Name = nullptr;
122  return true;
123 }
125 
126 int32_t CommandByName(const char *szCommand)
127 {
128  for (int32_t cnt=C4CMD_First; cnt<=C4CMD_Last; cnt++)
129  if (SEqual(szCommand,CommandName(cnt)))
130  return cnt;
131  return C4CMD_None;
132 }
133 
134 bool FreeMoveTo(C4Object *cObj)
135 {
136  // Floating: we accept any move-to target
137  if (cObj->GetProcedure()==DFA_FLOAT) return true;
138  // Assume we're walking: move-to targets are adjusted
139  return false;
140 }
141 
142 void AdjustMoveToTarget(int32_t &rX, int32_t &rY, bool fFreeMove, int32_t iShapeHgt)
143 {
144  // Above solid (always)
145  int32_t iY=std::min(rY, ::Landscape.GetHeight());
146  while ((iY>=0) && GBackSolid(rX,iY)) iY--;
147  if (iY>=0) rY=iY;
148  // No-free-move adjustments (i.e. if walking)
149  if (!fFreeMove)
150  {
151  // Drop down to bottom of free space
152  if (!GBackSemiSolid(rX,rY))
153  {
154  for (iY=rY; (iY<::Landscape.GetHeight()) && !GBackSemiSolid(rX,iY+1); iY++) {}
155  if (iY<::Landscape.GetHeight()) rY=iY;
156  }
157  // Vertical shape offset above solid
158  if (GBackSolid(rX,rY+1) || GBackSolid(rX,rY+5))
159  if (!GBackSemiSolid(rX,rY-iShapeHgt/2))
160  rY-=iShapeHgt/2;
161  }
162 
163 }
164 
165 bool AdjustSolidOffset(int32_t &rX, int32_t &rY, int32_t iXOff, int32_t iYOff)
166 {
167  // In solid: fail
168  if (GBackSolid(rX,rY)) return false;
169  // Y Offset
170  int32_t cnt;
171  for (cnt=1; cnt<iYOff; cnt++)
172  {
173  if (GBackSolid(rX,rY+cnt) && !GBackSolid(rX,rY-cnt)) rY--;
174  if (GBackSolid(rX,rY-cnt) && !GBackSolid(rX,rY+cnt)) rY++;
175  }
176  // X Offset
177  for (cnt=1; cnt<iXOff; cnt++)
178  {
179  if (GBackSolid(rX+cnt,rY) && !GBackSolid(rX-cnt,rY)) rX--;
180  if (GBackSolid(rX-cnt,rY) && !GBackSolid(rX+cnt,rY)) rX++;
181  }
182  // Done
183  return true;
184 }
185 
186 int32_t SolidOnWhichSide(int32_t iX, int32_t iY)
187 {
188  for (int32_t cx=1; cx<10; cx++)
189  for (int32_t cy=0; cy<10; cy++)
190  {
191  if (GBackSolid(iX-cx,iY-cy) || GBackSolid(iX-cx,iY+cy)) return -1;
192  if (GBackSolid(iX+cx,iY-cy) || GBackSolid(iX+cx,iY+cy)) return +1;
193  }
194  return 0;
195 }
196 
198 {
199  Default();
200 }
201 
203 {
204  Clear();
205 }
206 
208 {
210  cObj=nullptr;
211  Evaluated=false;
212  PathChecked=false;
213  Finished=false;
214  Tx=C4VNull;
215  Ty=0;
216  Target=Target2=nullptr;
217  Data.Set0();
218  UpdateInterval=0;
219  Failures=0;
220  Retries=0;
221  Permit=0;
222  Text=nullptr;
223  Next=nullptr;
224  iExec=0;
226 }
227 
229 {
230  explicit ObjectAddWaypoint(C4Object *obj) : cObj(obj) {}
231  bool operator()(int32_t iX, int32_t iY, C4Object *TransferTarget)
232  {
233  if (!cObj) return false;
234 
235  // Transfer waypoint
236  if (TransferTarget)
237  return cObj->AddCommand(C4CMD_Transfer,TransferTarget,iX,iY,0,nullptr,false);
238 
239  // Solid offset
240  AdjustSolidOffset(iX,iY,cObj->Shape.Wdt/2,cObj->Shape.Hgt/2);
241 
242  // Standard movement waypoint update interval
243  int32_t iUpdate = 25;
244  // Waypoints before transfer zones are not updated (enforce move to that waypoint)
245  if (cObj->Command && (cObj->Command->Command==C4CMD_Transfer)) iUpdate=0;
246  // Add waypoint
247  assert(cObj->Command);
248  if (!cObj->AddCommand(C4CMD_MoveTo,nullptr,iX,iY,iUpdate,nullptr,false,cObj->Command->Data)) return false;
249 
250  return true;
251  }
252 
253 private:
254  C4Object *cObj;
255 };
256 
258 {
259  // Determine move-to range
260  int32_t iMoveToRange = MoveToRange;
261  if (cObj->Def->MoveToRange > 0) iMoveToRange = cObj->Def->MoveToRange;
262 
263  // Current object position
264  int32_t cx,cy; cx=cObj->GetX(); cy=cObj->GetY();
265  bool fWaypoint=false;
266  if (Next && (Next->Command==C4CMD_MoveTo)) fWaypoint=true;
267 
268  // Contained: exit
269  if (cObj->Contained)
270  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
271 
272  // Check path (crew members or specific only)
273  if ((cObj->OCF & OCF_CrewMember) || cObj->Def->Pathfinder)
274  if (!PathChecked)
275  // Not too far
276  if (Distance(cx,cy,Tx._getInt(),Ty)<MaxPathRange)
277  // Not too close
278  if (!(Inside(cx-Tx._getInt(),-PathRange,+PathRange) && Inside(cy-Ty,-PathRange,+PathRange)))
279  {
280  // Path not free: find path
281  if (!PathFree(cx,cy,Tx._getInt(),Ty))
282  {
285  if (!Game.PathFinder.Find( cObj->GetX(),cObj->GetY(),
286  Tx._getInt(),Ty,
288  { /* Path not found: react? */ PathChecked=true; /* recheck delay */ }
289  return;
290  }
291  // Path free: recheck delay
292  else
293  PathChecked=true;
294  }
295  // Path recheck
296  if (!::Game.iTick35) PathChecked=false;
297 
298  // Pushing grab only or not desired: let go (pulling, too?)
299  if (cObj->GetProcedure()==DFA_PUSH)
300  if (cObj->Action.Target)
302  {
303  // Re-evaluate this command because vehicle control might have blocked evaluation
304  Evaluated=false;
305  cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return;
306  }
307 
308  // Special by procedure
309  switch (cObj->GetProcedure())
310  {
311  // Push/pull
312  case DFA_PUSH: case DFA_PULL:
313  // Use target object's position if on final waypoint
314  if (!fWaypoint)
315  if (cObj->Action.Target)
316  { cx=cObj->Action.Target->GetX(); cy=cObj->Action.Target->GetY(); }
317  break;
318  // dig: stop
319  case DFA_DIG:
321  break;
322  }
323 
324  // Target range
325  int32_t iTargetRange = iMoveToRange;
326  int32_t iRangeFactorTop=1, iRangeFactorBottom=1, iRangeFactorSide=1;
327 
328  // Crew members/pathfinder specific target range
329  if (cObj->OCF & OCF_CrewMember) // || cObj->Def->Pathfinder ? (Sven2)
330  {
331  // Range by size
332  iTargetRange=cObj->Shape.Wdt/2;
333  // Easier range if waypoint
334  if (fWaypoint)
335  if (cObj->GetProcedure()!=DFA_SCALE)
336  { iRangeFactorTop=3; iRangeFactorSide=3; iRangeFactorBottom=2; }
337  }
338 
339  // Target reached (success)
340  if (Inside(cx-Tx._getInt(),-iRangeFactorSide*iTargetRange,+iRangeFactorSide*iTargetRange)
341  && Inside(cy-Ty,-iRangeFactorBottom*iTargetRange,+iRangeFactorTop*iTargetRange))
342  {
344  Finish(true); return;
345  }
346 
347  // Idles can't move to
348  if (!cObj->GetAction())
349  { Finish(); return; }
350 
351  // Action
352  switch (cObj->GetProcedure())
353  {
354  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
355  case DFA_WALK:
356  // Head to target
357  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
358  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
359  // Flight control
360  if (FlightControl()) return;
361  // Jump control
362  if (JumpControl()) return;
363  break;
364  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
365  case DFA_PUSH: case DFA_PULL:
366  // Head to target
367  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
368  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
369  break;
370  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
371  case DFA_SCALE:
372  // Head to target
373  if (cy>Ty+iTargetRange) cObj->Action.ComDir=COMD_Up;
374  if (cy<Ty-iTargetRange) cObj->Action.ComDir=COMD_Down;
375  // Let-Go Control
376  if (cObj->Action.Dir==DIR_Left)
377  {
378  // Target direction
379  if ((Tx._getInt()>cx+LetGoRange1) && (Inside(cy-Ty,-LetGoRange2,+LetGoRange2)))
380  { ObjectComLetGo(cObj,+1); return; }
381  // Contact (not if just started)
382  if (cObj->Action.Time>2)
383  if (cObj->t_contact/* & CNAT_Left*/)
384  { ObjectComLetGo(cObj,+1); return; }
385  }
386  if (cObj->Action.Dir==DIR_Right)
387  {
388  // Target direction
389  if ((Tx._getInt()<cx-LetGoRange1) && (Inside(cy-Ty,-LetGoRange2,+LetGoRange2)))
390  { ObjectComLetGo(cObj,-1); return; }
391  // Contact (not if just started)
392  if (cObj->Action.Time>2)
393  if (cObj->t_contact/* & CNAT_Right*/)
394  { ObjectComLetGo(cObj,-1); return; }
395  }
396  break;
397  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
398  case DFA_SWIM:
399  // Head to target
400  if (::Game.iTick2)
401  {
402  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
403  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
404  }
405  else
406  {
407  if (cy<Ty) cObj->Action.ComDir=COMD_Down;
408  if (cy>Ty) cObj->Action.ComDir=COMD_Up;
409  }
410  break;
411  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
412  case DFA_HANGLE:
413  // Head to target
414  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
415  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
416  // Let-Go Control
417  if (Abs(Angle(cx,cy,Tx._getInt(),Ty))>LetGoHangleAngle)
418  ObjectComLetGo(cObj,0);
419  break;
420  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
421  case DFA_FLOAT:
422  {
423  C4Real dx = itofix(Tx._getInt()) - cObj->fix_x, dy = itofix(Ty) - cObj->fix_y;
424  // normalize
425  C4Real dScale = C4REAL100(cObj->GetAction()->GetPropertyInt(P_Speed)) / std::max(Abs(dx), Abs(dy));
426  dx *= dScale; dy *= dScale;
427  // difference to momentum
428  dx -= cObj->xdir; dy -= cObj->ydir;
429  // steer
430  if (Abs(dx)+Abs(dy) < C4REAL100(20)) cObj->Action.ComDir = COMD_Stop;
431  else if (Abs(dy) * 3 < dx) cObj->Action.ComDir = COMD_Right;
432  else if (Abs(dy) * 3 < -dx) cObj->Action.ComDir = COMD_Left;
433  else if (Abs(dx) * 3 < dy) cObj->Action.ComDir = COMD_Down;
434  else if (Abs(dx) * 3 < -dy) cObj->Action.ComDir = COMD_Up;
435  else if (dx > 0 && dy > 0) cObj->Action.ComDir = COMD_DownRight;
436  else if (dx < 0 && dy > 0) cObj->Action.ComDir = COMD_DownLeft;
437  else if (dx > 0 && dy < 0) cObj->Action.ComDir = COMD_UpRight;
438  else cObj->Action.ComDir = COMD_UpLeft;
439  }
440  break;
441  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
442  case DFA_FLIGHT:
443  // Try to move into right direction
444  if (cx<Tx._getInt()-iTargetRange) cObj->Action.ComDir=COMD_Right;
445  if (cx>Tx._getInt()+iTargetRange) cObj->Action.ComDir=COMD_Left;
446  // Flight control
447  if (FlightControl()) return;
448  break;
449  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
450  }
451 
452 }
453 
455 {
456  // Current object and target coordinates
457  int32_t cx,cy,tx,ty;
458  cx=cObj->GetX(); cy=cObj->GetY();
459  tx=Tx._getInt(); ty=Ty+cObj->Shape.GetY() + 3; // Target coordinates are bottom center
460  bool fDigOutMaterial=Data.getBool();
461 
462  // Grabbing: let go
463  if (cObj->GetProcedure()==DFA_PUSH)
464  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
465 
466  // If contained: exit
467  if (cObj->Contained)
468  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
469 
470  // Scaling or hangling: let go
472  ObjectComLetGo(cObj,(cObj->Action.Dir==DIR_Left) ? +1 : -1);
473 
474  // Determine move-to range
475  int32_t iMoveToRange = MoveToRange;
476  if (cObj->Def->MoveToRange > 0) iMoveToRange = cObj->Def->MoveToRange;
477 
478  // Target reached: success
479  if (Inside(cx - tx, -iMoveToRange, +iMoveToRange)
480  && Inside(cy - ty, -iMoveToRange, +iMoveToRange))
481  {
483  Finish(true); return;
484  }
485 
486  // Can start digging only from walk
487  if (cObj->GetProcedure()!=DFA_DIG)
488  if (cObj->GetProcedure()!=DFA_WALK)
489  // Continue trying (assume currently in flight)
490  return;
491 
492  // Start digging
493  if (cObj->GetProcedure()!=DFA_DIG)
494  if (!ObjectComDig(cObj))
495  { Finish(); return; }
496 
497  // Dig2Object
498  if (fDigOutMaterial) cObj->Action.Data=1;
499 
500  // Head to target
501  if (cx<tx-DigRange) cObj->Action.ComDir=COMD_Right;
502  if (cx>tx+DigRange) cObj->Action.ComDir=COMD_Left;
503  if (cy<ty-DigRange) cObj->Action.ComDir=COMD_Down;
504  if (cx<tx-DigRange) if (cy<ty-DigRange) cObj->Action.ComDir=COMD_DownRight;
505  if (cx>tx-DigRange) if (cy<ty-DigRange) cObj->Action.ComDir=COMD_DownLeft;
506  if (cx<tx-DigRange) if (cy>ty+DigRange) cObj->Action.ComDir=COMD_UpRight;
507  if (cx>tx+DigRange) if (cy>ty+DigRange) cObj->Action.ComDir=COMD_UpLeft;
508 
509 }
510 
511 
513 {
514  // No-one to follow
515  if (!Target) { Finish(); return; }
516 
517  // Follow containment
519  {
520  // Only crew members can follow containment
521  if (!cObj->Def->CrewMember)
522  { Finish(); return; }
523  // Exit/enter
524  if (cObj->Contained) cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50);
525  else cObj->AddCommand(C4CMD_Enter,Target->Contained,0,0,50);
526  return;
527  }
528 
529  // Follow target grabbing
530  if (Target->GetProcedure()==DFA_PUSH)
531  {
532  // Grabbing same: copy ComDir
533  if (cObj->GetProcedure()==DFA_PUSH)
535  {
537  return;
538  }
539  // Else, grab target's grab
541  return;
542  }
543  else if (cObj->GetProcedure()==DFA_PUSH)
544  {
545  // Follow ungrabbing
547  return;
548  }
549 
550  // If in following range
551  if (Inside<int32_t>(cObj->GetX()-Target->GetX(),-FollowRange,+FollowRange)
552  && Inside<int32_t>(cObj->GetY()-Target->GetY(),-FollowRange,+FollowRange))
553  {
554  // Copy target's Action.ComDir
556  }
557  else // Else, move to target
558  {
559  cObj->AddCommand(C4CMD_MoveTo,nullptr,Target->GetX(),Target->GetY(),10);
560  }
561 
562 }
563 
565 {
566  DWORD ocf;
567 
568  // No object to enter or can't enter by def
569  if (!Target || cObj->Def->NoPushEnter) { Finish(); return; }
570 
571  // Already in target object
572  if (cObj->Contained==Target) { Finish(true); return; }
573 
574  // Digging: stop
576 
577  // Pushing grab only or pushing not desired: let go
578  if (cObj->GetProcedure()==DFA_PUSH)
579  if (cObj->Action.Target)
581  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
582 
583  // Pushing target: let go
584  if (cObj->GetProcedure()==DFA_PUSH)
585  if (cObj->Action.Target==Target)
586  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
587 
588  // Grabbing overrides position for target
589  int32_t cx,cy;
590  cx=cObj->GetX(); cy=cObj->GetY();
591  if (cObj->GetProcedure()==DFA_PUSH)
592  if (cObj->Action.Target)
593  { cx=cObj->Action.Target->GetX(); cy=cObj->Action.Target->GetY(); }
594 
595  // If in entrance range
596  ocf=OCF_Entrance;
597  if (!cObj->Contained && Target->At(cx,cy,ocf) && (ocf & OCF_Entrance))
598  {
599  // Stop
601  // Pushing: push target into entrance, then stop
602  if ((cObj->GetProcedure()==DFA_PUSH) && cObj->Action.Target)
603  {
605  Finish(true); return;
606  }
607  // Else, enter self
608  else
609  {
610  // If entrance open, enter object
611  if (Target->EntranceStatus!=0)
612  {
613  cObj->Enter(Target);
614  Finish(true); return;
615  }
616  else // Else, activate entrance
618  }
619 
620  }
621  else // Else, move to object's entrance
622  {
623  int32_t ex,ey,ewdt,ehgt;
624  if (Target->GetEntranceArea(ex,ey,ewdt,ehgt))
625  cObj->AddCommand(C4CMD_MoveTo,nullptr,ex+ewdt/2,ey+ehgt/2,50, nullptr, true, C4VInt((Data.getInt() & C4CMD_Enter_PushTarget) ? C4CMD_MoveTo_PushTarget : 0));
626  }
627 
628 }
629 
631 {
632 
633  // Outside: done
634  if (!cObj->Contained) { Finish(true); return; }
635 
636  // Entrance open, leave object
638  {
639  // Exit to container's container
640  if (cObj->Contained->Contained)
641  { cObj->Enter(cObj->Contained->Contained); Finish(true); return; }
642  // Exit to entrance area
643  int32_t ex,ey,ewdt,ehgt;
644  if (cObj->Contained->OCF & OCF_Entrance)
645  if (cObj->Contained->GetEntranceArea(ex,ey,ewdt,ehgt))
646  { cObj->Exit(ex+ewdt/2,ey+ehgt+cObj->Shape.GetY()-1); Finish(true); return; }
647  // Exit jump out of collection area
650  {
653  Finish(true); return;
654  }
655  // Plain exit
656  cObj->Exit(cObj->GetX(),cObj->GetY());
657  Finish(true); return;
658  }
659 
660  // Entrance closed, activate entrance
661  else
662  {
664  // Entrance activation failed: fail
665  { Finish(); return; }
666  }
667 }
668 
670 {
671  DWORD ocf;
672  // Command fulfilled
673  if (cObj->GetProcedure()==DFA_PUSH)
674  if (cObj->Action.Target==Target)
675  { Finish(true); return; }
676  // Digging: stop
678  // Grabbing: let go
679  if (cObj->GetProcedure()==DFA_PUSH)
680  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
681  // No target
682  if (!Target) { Finish(); return; }
683  // At target object: grab
684  ocf=OCF_All;
685  if (!cObj->Contained && Target->At(cObj->GetX(),cObj->GetY(),ocf))
686  {
687  // Scaling or hangling: let go
689  ObjectComLetGo(cObj,(cObj->Action.Dir==DIR_Left) ? +1 : -1);
690  // Grab
693  }
694  // Else, move to object
695  else
696  {
697  cObj->AddCommand(C4CMD_MoveTo,nullptr,Target->GetX()+Tx._getInt(),Target->GetY()+Ty,50);
698  }
699 }
700 
702 {
703  // Target check
704  if (!Target) { Finish(); return; }
705 
706  // Target is target self: fail
707  if (Target==Target2) { Finish(); return; }
708 
709  // Command fulfilled
710  if (Target2)
711  {
712  // Object in correct target container: success
713  if (Target->Contained==Target2)
714  { Finish(true); return; }
715  }
716  else
717  {
718  // Object at target position: success
721  {
724  cObj->AddCommand(C4CMD_Wait,nullptr,0,0,10);
725  Finish(true); return;
726  }
727  }
728 
729  // Digging: stop
731 
732  // Target contained: activate
733  if (Target->Contained)
734  { cObj->AddCommand(C4CMD_Activate,Target,0,0,40); return; }
735 
736  // Grab target
737  if (!((cObj->GetProcedure()==DFA_PUSH) && (cObj->Action.Target==Target)))
738  { cObj->AddCommand(C4CMD_Grab,Target,0,0,40); return; }
739 
740  // Move to target position / enter target object
741  if (Target2)
742  { cObj->AddCommand(C4CMD_Enter,Target2,0,0,40, nullptr, true, C4Value(C4CMD_Enter_PushTarget)); return; }
743  else
744  { cObj->AddCommand(C4CMD_MoveTo,nullptr,Tx,Ty,40, nullptr, true, C4Value(C4CMD_MoveTo_PushTarget)); return; }
745 
746 }
747 
749 {
752  Finish(true);
753 }
754 
756 {
757 
758  // Digging: stop
760 
761  // Throw specific object not in contents: get object
762  if (Target)
763  if (!cObj->Contents.GetLink(Target))
764  {
765  cObj->AddCommand(C4CMD_Get,Target,0,0,40);
766  return;
767  }
768 
769  // Determine move-to range
770  int32_t iMoveToRange = MoveToRange;
771  if (cObj->Def->MoveToRange > 0) iMoveToRange = cObj->Def->MoveToRange;
772 
773  // Target coordinates are not default 0/0: targeted throw
774  if ((Tx._getInt()!=0) || (Ty!=0))
775  {
776 
777  // Grabbing: let go
778  if (cObj->GetProcedure()==DFA_PUSH)
779  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
780 
781  // Preferred throwing direction
782  int32_t iDir=+1; if (cObj->GetX() > Tx._getInt()) iDir=-1;
783 
784  // Find throwing position
785  int32_t iTx,iTy;
787  int32_t iHeight = cObj->Shape.Hgt;
788  if (!FindThrowingPosition(Tx._getInt(),Ty,pthrow*iDir,-pthrow,iHeight,iTx,iTy))
789  if (!FindThrowingPosition(Tx._getInt(),Ty,pthrow*iDir*-1,-pthrow,iHeight,iTx,iTy))
790  // No throwing position: fail
791  { Finish(); return; }
792 
793  // At throwing position: face target and throw
794  if (Inside<int32_t>(cObj->GetX() - iTx, -iMoveToRange, +iMoveToRange) && Inside<int32_t>(cObj->GetY()-iTy,-15,+15))
795  {
796  if (cObj->GetX() < Tx._getInt()) cObj->SetDir(DIR_Right); else cObj->SetDir(DIR_Left);
799  Finish(true); // Throw successfull: done, else continue
800  return;
801  }
802 
803  // Move to target position
804  cObj->AddCommand(C4CMD_MoveTo,nullptr,iTx,iTy,20);
805 
806  return;
807  }
808 
809  // Contained: put or take
810  if (cObj->Contained)
811  {
813  Finish(true); return;
814  }
815 
816  // Pushing: put or take
817  if (cObj->GetProcedure()==DFA_PUSH)
818  {
819  if (cObj->Action.Target)
821  Finish(true); return;
822  }
823 
824  // Outside: Throw
826  Finish(true);
827 }
828 
830 {
832  Finish(true);
833 }
834 
836 {
838  Finish(true);
839 }
840 
842 {
843 
844  // Digging: stop
846 
847  // Drop specific object not in contents: get object
848  if (Target)
849  if (!cObj->Contents.GetLink(Target))
850  {
851  cObj->AddCommand(C4CMD_Get,Target,0,0,40);
852  return;
853  }
854 
855  // Determine move-to range
856  int32_t iMoveToRange = MoveToRange;
857  if (cObj->Def->MoveToRange > 0) iMoveToRange = cObj->Def->MoveToRange;
858 
859  // Target coordinates are not default 0/0: targeted drop
860  if ((Tx._getInt()!=0) || (Ty!=0))
861  {
862  // Grabbing: let go
863  if (cObj->GetProcedure()==DFA_PUSH)
864  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
865  // At target position: drop
866  if (Inside<int32_t>(cObj->GetX() - Tx._getInt(), -iMoveToRange, +iMoveToRange) && Inside<int32_t>(cObj->GetY()-Ty,-15,+15))
867  {
870  Finish(true);
871  return;
872  }
873  // Move to target position
874  cObj->AddCommand(C4CMD_MoveTo,nullptr,Tx._getInt(),Ty,20);
875  return;
876  }
877 
878  // Contained: put
879  if (cObj->Contained)
880  {
882  Finish(true); return;
883  }
884 
885  // Pushing: put
886  if (cObj->GetProcedure()==DFA_PUSH)
887  {
888  if (cObj->Action.Target)
890  Finish(true); return;
891  }
892 
893  // Outside: Drop
895  Finish(true);
896 }
897 
899 {
900  // Already in air?
901  if (cObj->GetProcedure()==DFA_FLIGHT)
902  {
903  // Check whether target position is given
904  if (Tx._getInt())
905  {
907  else if (cObj->GetX()>Tx._getInt()) cObj->Action.ComDir=COMD_Left;
908  else cObj->Action.ComDir=COMD_Stop;
909  }
910  }
911  else
912  {
914  // Done
915  Finish(true);
916  return;
917  }
918 }
919 
921 {
922  // Digging: stop
924 }
925 
927 {
928  // Target contained and container has RejectContents: fail
929  if (Target->Contained && !!Target->Contained->Call(PSF_RejectContents)) { Finish(); return false; }
930  // FIXME: Drop stuff if full here
931  bool fWasContained = !!Target->Contained;
932  // Grab target object
933  bool fRejectCollect = false;
934  bool fSuccess = !!Target->Enter(cObj, true, true, &fRejectCollect);
935  // target is void?
936  // well...most likely the new container has done something with it
937  // so count it as success
938  if (!Target) { Finish(true); return true; }
939  // collection rejected by target: make room for more contents
940  if (fRejectCollect)
941  {
942  if (cObj->PutAwayUnusedObject(Target)) return false;
943  // Can't get due to RejectCollect: fail
944  Finish();
945  return false;
946  }
947  // if not successfully entered for any other reason, fail
948  if (!fSuccess) { Finish(); return false; }
949  // get-callback for getting out of containers
950  if (fWasContained) cObj->Call(PSF_Get, &C4AulParSet(Target));
951  // entered
952  return true;
953 }
954 
956 {
957 
958  // Data set and target specified: open get menu & done (old style)
959  if (((Data.getInt()==1) || (Data.getInt()==2)) && Target)
960  {
962  Finish(true); return;
963  }
964 
965  // Get target specified by container and type
966  if (!Target && Target2 && Data)
967  if (!(Target = Target2->Contents.Find(Data.getDef())))
968  { Finish(); return; }
969 
970  // No target: failure
971  if (!Target) { Finish(); return; }
972 
973  // Target not carryable: failure
974  if (!(Target->OCF & OCF_Carryable))
975  { Finish(); return; }
976 
977  // Target collected
978  if (Target->Contained == cObj)
979  {
980  // Get-count specified: decrease count and continue with next object
981  if (Tx._getInt() > 1)
982  { Target = nullptr; Tx--; return; }
983  // We're done
984  else
985  { cObj->Action.ComDir=COMD_Stop; Finish(true); return; }
986  }
987 
988  // Grabbing other than target container: let go
989  if (cObj->GetProcedure()==DFA_PUSH)
991  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
992 
993  // Target in solid: dig out
994  if (!Target->Contained && (Target->OCF & OCF_InSolid))
995  {
996  // Check for closest free position
997  int32_t iX=Target->GetX(),iY=Target->GetY();
998  // Find all-closest dig-out position
999  if (!FindClosestFree(iX,iY,-120,+120,-1,-1))
1000  // None found
1001  { Finish(); return; }
1002  // Check good-angle left/right dig-out position
1003  int32_t iX2=Target->GetX(),iY2=Target->GetY();
1004  if (FindClosestFree(iX2,iY2,-140,+140,-40,+40))
1005  // Use good-angle position if it's not way worse
1006  if ( Distance(Target->GetX(),Target->GetY(),iX2,iY2) < 10*Distance(Target->GetX(),Target->GetY(),iX,iY) )
1007  { iX=iX2; iY=iY2; }
1008  // Move to closest free position (if not in dig-direct range)
1011  { cObj->AddCommand(C4CMD_MoveTo,nullptr,iX,iY,50); return; }
1012  // DigTo
1013  cObj->AddCommand(C4CMD_Dig,nullptr,Target->GetX(),Target->GetY()+4,50); return;
1014  }
1015 
1016  // Digging: stop
1018 
1019  // Target contained
1020  if (Target->Contained)
1021  {
1022  // target can't be taken out of containers?
1023  if (Target->Def->NoGet) return;
1024  // In same container: grab target
1025  if (cObj->Contained==Target->Contained)
1026  {
1027  GetTryEnter();
1028  // Done
1029  return;
1030  }
1031 
1032  // Leave own container
1033  if (cObj->Contained)
1034  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
1035 
1036  // Target container has grab get: grab target container
1038  {
1039  // Grabbing target container
1041  {
1042  GetTryEnter();
1043  // Done
1044  return;
1045  }
1046  // Grab target container
1048  return;
1049  }
1050 
1051  // Target container has entrance: enter target container
1052  if (Target->Contained->OCF & OCF_Entrance)
1053  { cObj->AddCommand(C4CMD_Enter,Target->Contained,0,0,50); return; }
1054 
1055  // Can't get to target due to target container: fail
1056  Finish();
1057  return;
1058  }
1059 
1060  // Target outside
1061 
1062  // Leave own container
1063  if (cObj->Contained) { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
1064 
1065  // Outside
1066  if (!cObj->Contained)
1067  {
1068 
1069  // Target in collection range
1071  if (cObj->At(Target->GetX(),Target->GetY(),ocf))
1072  {
1073  // stop here
1075  // try getting the object
1076  if (GetTryEnter()) return;
1077  }
1078 
1079  // Target not in range
1080  else
1081  {
1082  // Target in jumping range above clonk: try side-move jump
1083  if (Inside<int32_t>(cObj->GetX()-Target->GetX(),-10,+10))
1084  if (Inside<int32_t>(cObj->GetY()-Target->GetY(),30,50))
1085  {
1086  int32_t iSideX=1; if (Random(2)) iSideX=-1;
1087  iSideX=cObj->GetX()+iSideX*(cObj->GetY()-Target->GetY());
1088  if (PathFree(iSideX,cObj->GetY(),Target->GetX(),Target->GetY()))
1089  {
1090  // Side-move jump
1091  cObj->AddCommand(C4CMD_Jump,nullptr,Tx._getInt(),Ty);
1092  // FIXME: Drop stuff if full here
1093  cObj->AddCommand(C4CMD_MoveTo,nullptr,iSideX,cObj->GetY(),50);
1094  }
1095  }
1096  // Move to target (random offset for difficult pickups)
1097  // ...avoid offsets into solid which would lead to high above surface locations!
1098  cObj->AddCommand(C4CMD_MoveTo,nullptr,Target->GetX()+Random(15)-7,Target->GetY(),25,nullptr);
1099  }
1100 
1101  }
1102 
1103 }
1104 
1106 {
1107 
1108  // Container specified, but no Target & no type: open activate menu for container
1109  if (Target2 && !Target && !Data)
1110  {
1112  Finish(true);
1113  return;
1114  }
1115 
1116  // Target object specified & outside: success
1117  if (Target)
1118  if (!Target->Contained)
1119  { Finish(true); return; }
1120 
1121  // No container specified: determine container by target object
1122  if (!Target2)
1123  if (Target)
1125 
1126  // No container specified: fail
1127  if (!Target2) { Finish(); return; }
1128 
1129  // Digging: stop
1131 
1132  // In container
1133  if (cObj->Contained==Target2)
1134  {
1135  for (Tx.SetInt(Data ? std::max<int32_t>(Tx._getInt(),1) : 1); Tx._getInt(); --Tx)
1136  {
1137  // If not specified get object from target contents by type
1138  // Find first object requested id that has no command exit yet
1139  if (!Target)
1140  for (C4Object *pObj : Target2->Contents)
1141  if (pObj->Status && (pObj->Def==Data.getDef()))
1142  if (!pObj->Command || (pObj->Command->Command!=C4CMD_Exit))
1143  { Target=pObj; break; }
1144  // No target
1145  if (!Target) { Finish(); return; }
1146 
1147  // Thing in own container (target2)
1148  if (Target->Contained!=Target2) { Finish(); return; }
1149 
1150  // Activate object to exit
1153  Target = nullptr;
1154  }
1155 
1156  Finish(true); return;
1157  }
1158 
1159  // Leave own container
1160  if (cObj->Contained)
1161  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
1162 
1163  // Target container has entrance: enter
1164  if (Target2->OCF & OCF_Entrance)
1165  { cObj->AddCommand(C4CMD_Enter,Target2,0,0,50); return; }
1166 
1167  // Can't get to target due to target container: fail
1168  Finish();
1169 
1170 }
1171 
1172 
1173 void C4Command::Put() // Notice: Put command is currently using Ty as an internal reminder flag for letting go after putting...
1174 {
1175  // No target container: failure
1176  if (!Target) { Finish(); return; }
1177 
1178  // Thing to put specified by type
1179  if (!Target2 && Data)
1180  if (!(Target2 = cObj->Contents.Find(Data.getDef())))
1181  { Finish(); return; }
1182 
1183  // No thing to put specified
1184  if (!Target2)
1185  // Assume first contents object
1186  if (!(Target2 = cObj->Contents.GetObject()))
1187  // No contents object to put - most likely we did have a target but it was deleted,
1188  // e.g. by AutoSellContents in a base. New behaviour: if there is nothing to put, we
1189  // now consider the command succesfully completed.
1190  { Finish(true); return; }
1191 
1192  // Thing is in target
1193  if (Target2->Contained == Target)
1194  {
1195  // Put-count specified: decrease count and continue with next object
1196  if (Tx._getInt() > 1)
1197  { Target2 = nullptr; Tx--; return; }
1198  // We're done
1199  else
1200  { Finish(true); return; }
1201  }
1202 
1203  // Thing to put not in contents: get object
1204  if (!cObj->Contents.GetLink(Target2))
1205  {
1206  // Object is nearby and traveling: wait
1207  if (!Target2->Contained)
1208  if (Distance(cObj->GetX(),cObj->GetY(),Target2->GetX(),Target2->GetY())<80)
1209  if (Target2->OCF & OCF_HitSpeed1)
1210  return;
1211  // Go get it
1212  cObj->AddCommand(C4CMD_Get,Target2,0,0,40); return;
1213  }
1214 
1215  // Target is contained: can't do it
1216  if (Target->Contained)
1217  { Finish(); return; }
1218 
1219  // Digging: stop
1221 
1222  // Grabbing other than target: let go
1223  C4Object *pGrabbing=nullptr;
1224  if (cObj->GetProcedure()==DFA_PUSH)
1225  pGrabbing = cObj->Action.Target;
1226  if (pGrabbing && (pGrabbing!=Target))
1227  { cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0,50); return; }
1228 
1229  // Inside target container
1230  if (cObj->Contained == Target)
1231  {
1232  // Try to put
1234  Finish(); // Putting failed
1235  return;
1236  }
1237 
1238  // Leave own container
1239  if (cObj->Contained)
1240  { cObj->AddCommand(C4CMD_Exit,nullptr,0,0,50); return; }
1241 
1242  // Target has collection: throw in if not fragile, not grabbing target and throwing position found
1243  if (Target->OCF & OCF_Collection)
1244  if (!Target2->Def->Fragile)
1245  if (pGrabbing!=Target)
1246  {
1247  int32_t iTx = Target->GetX() + Target->Def->Collection.x + Target->Def->Collection.Wdt/2;
1248  int32_t iTy = Target->GetY() + Target->Def->Collection.y + Target->Def->Collection.Hgt/2;
1250  int32_t iHeight = cObj->Shape.Hgt;
1251  int32_t iPosX,iPosY;
1252  int32_t iObjDist = Distance(cObj->GetX(),cObj->GetY(),Target->GetX(),Target->GetY());
1253  if ( (FindThrowingPosition(iTx,iTy,pthrow,-pthrow,iHeight,iPosX,iPosY) && (Distance(iPosX,iPosY,cObj->GetX(),cObj->GetY()) < iObjDist))
1254  || (FindThrowingPosition(iTx,iTy,pthrow*-1,-pthrow,iHeight,iPosX,iPosY) && (Distance(iPosX,iPosY,cObj->GetX(),cObj->GetY()) < iObjDist)) )
1255  {
1256  // Throw
1257  cObj->AddCommand(C4CMD_Throw,Target2,iTx,iTy,5);
1258  return;
1259  }
1260  }
1261 
1262  // Target has C4D_Grab_Put: grab target and put
1264  {
1265  // Grabbing target container
1266  if (pGrabbing==Target)
1267  {
1268  // Try to put
1270  // Putting failed
1271  { Finish(); return; }
1272  // Let go (if we grabbed the target because of this command)
1273  if (Ty) cObj->AddCommand(C4CMD_UnGrab,nullptr,0,0);
1274  return;
1275  }
1276  // Grab target and let go after putting
1277  cObj->AddCommand(C4CMD_Grab,Target,0,0,50);
1278  Ty = 1;
1279  return;
1280  }
1281 
1282  // Target can be entered: enter target
1283  if (Target->OCF & OCF_Entrance)
1284  { cObj->AddCommand(C4CMD_Enter,Target,0,0,50); return; }
1285 
1286 }
1287 
1289 {
1290  if (cObj==pObj) cObj=nullptr;
1291  if (Target==pObj) Target=nullptr;
1292  if (Target2==pObj) Target2=nullptr;
1293 }
1294 
1296 {
1297 
1298  // Finished?!
1299  if (Finished) return;
1300 
1301  // Parent object safety
1302  if (!cObj) { Finish(); return; }
1303 
1304  // Delegated command failed
1305  if (Failures)
1306  {
1307  // Retry
1308  if (Retries>0)
1309  { Failures=0; Retries--; cObj->AddCommand(C4CMD_Retry,nullptr,0,0,10); return; }
1310  // Too many failures
1311  else
1312  { Finish(); return; }
1313  }
1314 
1315  // Command update
1316  if (UpdateInterval>0)
1317  {
1318  UpdateInterval--;
1319  if (UpdateInterval==0)
1320  {
1321  Finish(true); return;
1322  }
1323  }
1324 
1325  // Initial command evaluation
1326  if (InitEvaluation()) return;
1327 
1328  // from now on, we are executing this command... and nobody
1329  // should dare deleting us
1330  iExec = 1;
1331 
1332  // Execute
1333  switch (Command)
1334  {
1335  case C4CMD_Follow: Follow(); break;
1336  case C4CMD_MoveTo: MoveTo(); break;
1337  case C4CMD_Enter: Enter(); break;
1338  case C4CMD_Exit: Exit(); break;
1339  case C4CMD_Grab: Grab(); break;
1340  case C4CMD_UnGrab: UnGrab(); break;
1341  case C4CMD_Throw: Throw(); break;
1342  case C4CMD_Jump: Jump(); break;
1343  case C4CMD_Wait: Wait(); break;
1344  case C4CMD_Get: Get(); break;
1345  case C4CMD_Put: Put(); break;
1346  case C4CMD_Drop: Drop(); break;
1347  case C4CMD_Dig: Dig(); break;
1348  case C4CMD_Activate: Activate(); break;
1349  case C4CMD_PushTo: PushTo(); break;
1350  case C4CMD_Transfer: Transfer(); break;
1351  case C4CMD_Attack: Attack(); break;
1352  case C4CMD_Buy: Buy(); break;
1353  case C4CMD_Sell: Sell(); break;
1354  case C4CMD_Acquire: Acquire(); break;
1355  case C4CMD_Retry: Retry(); break;
1356  case C4CMD_Home: Home(); break;
1357  case C4CMD_Call: Call(); break;
1358  case C4CMD_Take: Take(); break; // carlo
1359  case C4CMD_Take2: Take2(); break; // carlo
1360  default: Finish(); break;
1361  }
1362 
1363  /* // Remember this command might have already been deleted through calls
1364  // made during execution. You must not do anything here... */
1365 
1366  // check: command must be deleted?
1367  if (iExec > 1)
1368  delete this;
1369  else
1370  iExec = 0;
1371 
1372 }
1373 
1374 void C4Command::Finish(bool fSuccess, const char *szFailMessage)
1375 {
1376  // Mark finished
1377  Finished=true;
1378  // Failed
1379  if (!fSuccess)
1380  Fail(szFailMessage);
1381  else
1382  {
1383  // successful commands might gain EXP
1384  int32_t iExpGain = GetExpGain();
1385  if (iExpGain && cObj) if (cObj->Info)
1386  for (int32_t i=iExpGain; i; --i)
1387  if (!(++cObj->Info->ControlCount%5))
1388  cObj->DoExperience(1);
1389  }
1390 }
1391 
1393 {
1394  // Already evaluated
1395  if (Evaluated) return false;
1396  // Set evaluation flag
1397  Evaluated=true;
1398  // Evaluate
1399  switch (Command)
1400  {
1401  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1402  case C4CMD_MoveTo:
1403  {
1404  // Target coordinates by Target
1405  if (Target) { Tx+=Target->GetX(); Ty+=Target->GetY(); Target=nullptr; }
1406  // Adjust coordinates
1407  int32_t iTx = Tx._getInt();
1409  Tx.SetInt(iTx);
1410  return true;
1411  }
1412  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1413  case C4CMD_PushTo:
1414  {
1415  // Adjust coordinates
1416  int32_t iTx = Tx._getInt();
1418  Tx.SetInt(iTx);
1419  return true;
1420  }
1421  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1422  case C4CMD_Exit:
1423  // Cancel attach
1425  return true;
1426  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1427  case C4CMD_Jump:
1428  {
1429  if (Tx._getInt())
1430  {
1431  if (Tx._getInt()<cObj->GetX()) cObj->SetDir(DIR_Left);
1432  if (Tx._getInt()>cObj->GetX()) cObj->SetDir(DIR_Right);
1433  }
1435  return true;
1436  }
1437  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1438  case C4CMD_Wait:
1439  // Update interval by Data
1440  if (!!Data) UpdateInterval=Data.getInt();
1441  // Else update interval by Tx
1442  else if (Tx._getInt()) UpdateInterval=Tx._getInt();
1443  return true;
1444  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1445  case C4CMD_Acquire:
1446  // update default search range
1447  if (!Tx._getInt()) Tx.SetInt(500);
1448  if (!Ty) Ty=250;
1449  return true;
1450  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1451  }
1452  // Need not be evaluated
1453  return false;
1454 }
1455 
1457 {
1459  cObj=nullptr;
1460  Evaluated=false;
1461  PathChecked=false;
1462  Tx=C4VNull;
1463  Ty=0;
1464  Target=Target2=nullptr;
1465  UpdateInterval=0;
1466  if (Text) Text->DecRef();
1467  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  {
1593  if (!Target->Call(PSF_ControlTransfer, &C4AulParSet(cObj, Tx, Ty)).getBool())
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 int32_t PushToRange
Definition: C4Command.cpp:38
bool AdjustSolidOffset(int32_t &rX, int32_t &rY, int32_t iXOff, int32_t iYOff)
Definition: C4Command.cpp:165
const int32_t PathRange
Definition: C4Command.cpp:39
const int32_t LetGoRange1
Definition: C4Command.cpp:37
const int32_t FollowRange
Definition: C4Command.cpp:38
StdEnumAdapt< int32_t >::Entry EnumAdaptCommandEntries[C4CMD_Last - C4CMD_First+2]
Definition: C4Command.cpp:44
int32_t CommandByName(const char *szCommand)
Definition: C4Command.cpp:126
bool InitEnumAdaptCommandEntries()
Definition: C4Command.cpp:114
bool FreeMoveTo(C4Object *cObj)
Definition: C4Command.cpp:134
const char * CommandName(int32_t iCommand)
Definition: C4Command.cpp:46
const int32_t JumpLowAngle
Definition: C4Command.cpp:40
const int32_t MoveToRange
Definition: C4Command.cpp:37
const char * CommandNameID(int32_t iCommand)
Definition: C4Command.cpp:80
const bool InitEnumAdaptCommandEntriesDummy
Definition: C4Command.cpp:124
void AdjustMoveToTarget(int32_t &rX, int32_t &rY, bool fFreeMove, int32_t iShapeHgt)
Definition: C4Command.cpp:142
const int32_t JumpAngleRange
Definition: C4Command.cpp:40
const int32_t JumpHighAngle
Definition: C4Command.cpp:40
const int32_t MaxPathRange
Definition: C4Command.cpp:39
const int32_t DigOutPositionRange
Definition: C4Command.cpp:38
const int32_t FlightAngleRange
Definition: C4Command.cpp:41
const int32_t JumpAngle
Definition: C4Command.cpp:40
int32_t SolidOnWhichSide(int32_t iX, int32_t iY)
Definition: C4Command.cpp:186
const int32_t LetGoRange2
Definition: C4Command.cpp:37
const int32_t LetGoHangleAngle
Definition: C4Command.cpp:42
const int32_t DigRange
Definition: C4Command.cpp:37
const int32_t C4CMD_MoveTo_NoPosAdjust
Definition: C4Command.h:65
@ C4CMD_Acquire
Definition: C4Command.h:48
@ C4CMD_Call
Definition: C4Command.h:51
@ C4CMD_Home
Definition: C4Command.h:50
@ C4CMD_Sell
Definition: C4Command.h:47
@ C4CMD_Drop
Definition: C4Command.h:40
@ C4CMD_Transfer
Definition: C4Command.h:44
@ C4CMD_Follow
Definition: C4Command.h:29
@ C4CMD_Activate
Definition: C4Command.h:42
@ C4CMD_Take
Definition: C4Command.h:52
@ C4CMD_Wait
Definition: C4Command.h:37
@ C4CMD_Attack
Definition: C4Command.h:45
@ C4CMD_Retry
Definition: C4Command.h:49
@ C4CMD_Get
Definition: C4Command.h:38
@ C4CMD_None
Definition: C4Command.h:28
@ C4CMD_MoveTo
Definition: C4Command.h:30
@ C4CMD_Take2
Definition: C4Command.h:53
@ C4CMD_Jump
Definition: C4Command.h:36
@ C4CMD_Put
Definition: C4Command.h:39
@ C4CMD_Enter
Definition: C4Command.h:31
@ C4CMD_PushTo
Definition: C4Command.h:43
@ C4CMD_Exit
Definition: C4Command.h:32
@ C4CMD_UnGrab
Definition: C4Command.h:35
@ C4CMD_Buy
Definition: C4Command.h:46
@ C4CMD_Throw
Definition: C4Command.h:34
@ C4CMD_Dig
Definition: C4Command.h:41
@ C4CMD_Grab
Definition: C4Command.h:33
const int32_t C4CMD_MoveTo_PushTarget
Definition: C4Command.h:66
const int32_t C4CMD_Mode_Base
Definition: C4Command.h:60
const int32_t C4CMD_Enter_PushTarget
Definition: C4Command.h:68
const int32_t C4CMD_Last
Definition: C4Command.h:57
const int32_t C4CMD_First
Definition: C4Command.h:56
const int32_t C4CMD_Mode_Sub
Definition: C4Command.h:62
const int32_t C4CMD_Mode_SilentSub
Definition: C4Command.h:59
const uint32_t OCF_Carryable
Definition: C4Constants.h:82
const uint32_t OCF_HitSpeed1
Definition: C4Constants.h:84
const uint32_t OCF_Collection
Definition: C4Constants.h:93
const uint32_t OCF_Normal
Definition: C4Constants.h:79
const uint32_t OCF_Entrance
Definition: C4Constants.h:90
const uint32_t OCF_All
Definition: C4Constants.h:78
const uint32_t OCF_Available
Definition: C4Constants.h:101
const BYTE CNAT_Right
Definition: C4Constants.h:110
const uint32_t OCF_InSolid
Definition: C4Constants.h:99
const uint32_t OCF_FullCon
Definition: C4Constants.h:85
const uint32_t OCF_CrewMember
Definition: C4Constants.h:97
const int NO_OWNER
Definition: C4Constants.h:137
const BYTE CNAT_Left
Definition: C4Constants.h:109
const int32_t C4D_Grab_Put
Definition: C4Def.h:62
const int32_t C4D_Grab_Get
Definition: C4Def.h:63
C4GameMessageList Messages
const int32_t C4GM_Target
Definition: C4GameMessage.h:31
#define PSF_RejectContents
Definition: C4GameScript.h:134
#define PSF_ControlCommandAcquire
Definition: C4GameScript.h:163
#define PSF_Get
Definition: C4GameScript.h:54
#define PSF_ControlTransfer
Definition: C4GameScript.h:78
#define PSF_CommandFailure
Definition: C4GameScript.h:102
C4Game Game
Definition: C4Globals.cpp:52
C4StringTable Strings
Definition: C4Globals.cpp:42
const unsigned int C4MaxName
bool PathFree(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
C4Landscape Landscape
bool FindThrowingPosition(int32_t iTx, int32_t iTy, C4Real fXDir, C4Real fYDir, int32_t iHeight, int32_t &rX, int32_t &rY)
bool FindClosestFree(int32_t &rX, int32_t &rY, int32_t iAngle1, int32_t iAngle2, int32_t iExcludeAngle1, int32_t iExcludeAngle2)
bool GBackSemiSolid(int32_t x, int32_t y)
Definition: C4Landscape.h:234
int32_t GBackDensity(int32_t x, int32_t y)
Definition: C4Landscape.h:224
bool GBackSolid(int32_t x, int32_t y)
Definition: C4Landscape.h:229
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
#define COMD_UpLeft
Definition: C4Object.h:58
#define COMD_DownRight
Definition: C4Object.h:54
#define COMD_Down
Definition: C4Object.h:55
#define DIR_Right
Definition: C4Object.h:42
#define COMD_DownLeft
Definition: C4Object.h:56
#define DIR_Left
Definition: C4Object.h:41
#define COMD_UpRight
Definition: C4Object.h:52
#define COMD_Right
Definition: C4Object.h:53
#define COMD_Left
Definition: C4Object.h:57
#define COMD_Stop
Definition: C4Object.h:50
#define COMD_Up
Definition: C4Object.h:51
bool ObjectComThrow(C4Object *cObj, C4Object *pThing)
bool ObjectComPutTake(C4Object *cObj, C4Object *pTarget, C4Object *pThing)
bool ObjectComCancelAttach(C4Object *cObj)
bool ObjectComLetGo(C4Object *cObj, int32_t xdirf)
bool ObjectComTake(C4Object *cObj)
bool ObjectComUnGrab(C4Object *cObj)
bool ObjectComTake2(C4Object *cObj)
bool ObjectComGrab(C4Object *cObj, C4Object *pTarget)
bool ObjectComJump(C4Object *cObj)
bool ObjectComStop(C4Object *cObj)
bool ObjectComPut(C4Object *cObj, C4Object *pTarget, C4Object *pThing)
bool ObjectComDig(C4Object *cObj)
bool ObjectComDrop(C4Object *cObj, C4Object *pThing)
@ C4MN_Activate
Definition: C4ObjectMenu.h:33
@ C4MN_Get
Definition: C4ObjectMenu.h:39
@ C4MN_Contents
Definition: C4ObjectMenu.h:44
uint32_t Random()
Definition: C4Random.cpp:43
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
C4Real C4REAL100(int x)
Definition: C4Real.h:267
@ DFA_SWIM
@ DFA_FLOAT
@ DFA_HANGLE
@ DFA_WALK
@ DFA_DIG
@ P_Speed
@ DFA_PULL
@ P_Collectible
@ DFA_FLIGHT
@ P_Touchable
@ DFA_PUSH
@ DFA_SCALE
@ P_ObjectDisabled
@ P_ThrowSpeed
C4Value C4VObj(C4Object *pObj)
Definition: C4Value.cpp:88
const C4Value C4VNull
Definition: C4Value.cpp:30
@ C4V_Int
Definition: C4Value.h:26
C4Value C4VInt(int32_t i)
Definition: C4Value.h:239
C4Value C4VString(C4String *pStr)
Definition: C4Value.h:243
uint32_t DWORD
int32_t Angle(int32_t iX1, int32_t iY1, int32_t iX2, int32_t iY2, int32_t iPrec)
Definition: Standard.cpp:37
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
int32_t Distance(int32_t iX1, int32_t iY1, int32_t iX2, int32_t iY2)
Definition: Standard.cpp:25
#define sprintf
Definition: Standard.h:162
T Abs(T val)
Definition: Standard.h:42
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
StdIntPackAdapt< T > mkIntPackAdapt(T &rVal)
Definition: StdAdaptors.h:791
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:490
Definition: StdAdaptors.h:795
#define C4RGB(r, g, b)
Definition: StdColors.h:26
int32_t Data
Definition: C4Object.h:84
int32_t Time
Definition: C4Object.h:83
int32_t ComDir
Definition: C4Object.h:82
int32_t Dir
Definition: C4Object.h:80
C4ObjectPtr Target
Definition: C4Object.h:87
int32_t Failures
Definition: C4Command.h:88
bool JumpControl()
Definition: C4Command.cpp:1505
int32_t Evaluated
Definition: C4Command.h:87
C4Value Data
Definition: C4Command.h:85
void Drop()
Definition: C4Command.cpp:841
void Acquire()
Definition: C4Command.cpp:1655
void Dig()
Definition: C4Command.cpp:454
void Put()
Definition: C4Command.cpp:1173
int32_t Finished
Definition: C4Command.h:87
void Buy()
Definition: C4Command.cpp:1645
void ClearPointers(C4Object *pObj)
Definition: C4Command.cpp:1288
void Finish(bool fSuccess=false, const char *szFailMessage=nullptr)
Definition: C4Command.cpp:1374
void Denumerate(C4ValueNumbers *)
Definition: C4Command.cpp:1911
void Enter()
Definition: C4Command.cpp:564
void Retry()
Definition: C4Command.cpp:1800
C4Value Tx
Definition: C4Command.h:82
int32_t Retries
Definition: C4Command.h:88
int32_t GetExpGain()
Definition: C4Command.cpp:1932
void Take2()
Definition: C4Command.cpp:835
bool GetTryEnter()
Definition: C4Command.cpp:926
int32_t UpdateInterval
Definition: C4Command.h:86
void Call()
Definition: C4Command.cpp:1833
C4ObjectPtr Target
Definition: C4Command.h:84
int32_t iExec
Definition: C4Command.h:91
void Sell()
Definition: C4Command.cpp:1650
void Transfer()
Definition: C4Command.cpp:1571
bool FlightControl()
Definition: C4Command.cpp:1471
void Grab()
Definition: C4Command.cpp:669
int32_t CallFailed()
Definition: C4Command.cpp:1918
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
C4ObjectPtr Target2
Definition: C4Command.h:84
void Get()
Definition: C4Command.cpp:955
C4Object * cObj
Definition: C4Command.h:80
int32_t Permit
Definition: C4Command.h:88
bool InitEvaluation()
Definition: C4Command.cpp:1392
void Execute()
Definition: C4Command.cpp:1295
void Default()
Definition: C4Command.cpp:207
void Throw()
Definition: C4Command.cpp:755
void MoveTo()
Definition: C4Command.cpp:257
void PushTo()
Definition: C4Command.cpp:701
void Attack()
Definition: C4Command.cpp:1600
void Take()
Definition: C4Command.cpp:829
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *)
Definition: C4Command.cpp:1852
void Home()
Definition: C4Command.cpp:1805
void UnGrab()
Definition: C4Command.cpp:748
void Wait()
Definition: C4Command.cpp:920
void Jump()
Definition: C4Command.cpp:898
void Fail(const char *szFailMessage=nullptr)
Definition: C4Command.cpp:1703
int32_t Ty
Definition: C4Command.h:83
void Exit()
Definition: C4Command.cpp:630
int32_t PathChecked
Definition: C4Command.h:87
int32_t Command
Definition: C4Command.h:81
int32_t BaseMode
Definition: C4Command.h:92
void Clear()
Definition: C4Command.cpp:1456
C4String * Text
Definition: C4Command.h:89
C4Command * Next
Definition: C4Command.h:90
void Follow()
Definition: C4Command.cpp:512
void Activate()
Definition: C4Command.cpp:1105
Definition: C4Def.h:99
int32_t CrewMember
Definition: C4Def.h:112
int32_t NoPushEnter
Definition: C4Def.h:132
int32_t MoveToRange
Definition: C4Def.h:135
int32_t Projectile
Definition: C4Def.h:131
int32_t SilentCommands
Definition: C4Def.h:139
C4Rect Collection
Definition: C4Def.h:106
int32_t NoTransferZones
Definition: C4Def.h:146
int32_t NoGet
Definition: C4Def.h:144
int32_t Pathfinder
Definition: C4Def.h:134
int32_t Fragile
Definition: C4Def.h:130
int32_t GrabPutGet
Definition: C4Def.h:124
Definition: C4Real.h:59
C4TransferZones TransferZones
Definition: C4Game.h:85
C4PathFinder PathFinder
Definition: C4Game.h:84
C4Object * FindObject(C4Def *def, int32_t x=0, int32_t y=0, int32_t wdt=0, int32_t hgt=0, DWORD ocf=OCF_All, C4Object *find_next=nullptr)
Definition: C4Game.cpp:1456
int32_t iTick2
Definition: C4Game.h:130
int32_t iTick35
Definition: C4Game.h:130
int32_t iTick5
Definition: C4Game.h:130
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)
int32_t GetHeight() const
bool Enter(C4Object *pTarget, bool fCalls=true, bool fCopyMotion=true, bool *pfRejectCollect=nullptr)
bool EntranceStatus
Definition: C4Object.h:130
C4ObjectInfo * Info
Definition: C4Object.h:143
bool At(int32_t ctx, int32_t cty) const
C4Real ydir
Definition: C4Object.h:124
bool PutAwayUnusedObject(C4Object *pToMakeRoomForObject)
C4Real fix_y
Definition: C4Object.h:123
C4PropList * GetAction() const
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)
C4Real xdir
Definition: C4Object.h:124
void DoExperience(int32_t change)
bool ActivateEntrance(int32_t by_plr, C4Object *by_obj)
Definition: C4Object.cpp:689
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)
C4Real fix_x
Definition: C4Object.h:123
uint32_t t_contact
Definition: C4Object.h:131
bool SetActionByName(C4String *ActName, C4Object *pTarget=nullptr, C4Object *pTarget2=nullptr, int32_t iCalls=SAC_StartCall|SAC_AbortCall, bool fForce=false)
int32_t GetProcedure() const
C4Command * Command
Definition: C4Object.h:165
int32_t GetX() const
Definition: C4Object.h:285
bool ActivateMenu(int32_t iMenu, int32_t iMenuSelect=0, int32_t iMenuData=0, int32_t iMenuPosition=0, C4Object *pTarget=nullptr)
int32_t Controller
Definition: C4Object.h:109
void SetDir(int32_t tdir)
uint32_t OCF
Definition: C4Object.h:132
bool GetOnFire() const
Definition: C4Object.h:302
int32_t GetY() const
Definition: C4Object.h:286
C4NotifyingObjectList Contents
Definition: C4Object.h:151
C4ObjectPtr Contained
Definition: C4Object.h:142
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)
C4Action Action
Definition: C4Object.h:145
BYTE GetEntranceArea(int32_t &aX, int32_t &aY, int32_t &aWdt, int32_t &aHgt) const
Definition: C4Object.cpp:708
C4Def * Def
Definition: C4Object.h:141
C4Shape Shape
Definition: C4Object.h:146
int32_t ControlCount
Definition: C4ObjectInfo.h:38
const C4ObjectLink * GetLink(const C4Object *obj) const
C4Object * Find(C4Def *def, int owner=ANY_OWNER, DWORD dwOCF=OCF_All)
C4Object * GetObject(int index=0) const
void DenumeratePointers()
Definition: C4ObjectPtr.cpp:49
void EnableTransferZones(bool fEnabled)
void SetLevel(int iLevel)
bool Find(int32_t iFromX, int32_t iFromY, int32_t iToX, int32_t iToY, SetWaypointFn fnSetWaypoint)
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val=0) const
Definition: C4PropList.cpp:855
int32_t Status
Definition: C4PropList.h:173
C4Value Call(C4PropertyName k, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4PropList.h:114
const char * GetName() const override
Definition: C4PropList.cpp:243
int32_t y
Definition: C4Rect.h:30
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
int32_t x
Definition: C4Rect.h:30
void DecRef()
Definition: C4StringTable.h:28
void IncRef()
Definition: C4StringTable.h:27
int32_t ContactDensity
Definition: C4Shape.h:47
int32_t GetY() const
Definition: C4Shape.h:63
StdStrBuf GetData() const
Definition: C4StringTable.h:50
const char * GetCStr() const
Definition: C4StringTable.h:49
C4String * RegString(StdStrBuf String)
bool GetEntryPoint(int32_t &rX, int32_t &rY, int32_t iToX, int32_t iToY)
C4TransferZone * Find(C4Object *pObj)
ALWAYS_INLINE bool CheckConversion(C4V_Type vtToType) const
Definition: C4Value.h:189
int32_t getInt() const
Definition: C4Value.h:112
void Set0()
Definition: C4Value.h:332
int32_t _getInt() const
Definition: C4Value.h:122
void SetInt(int32_t i)
Definition: C4Value.h:136
bool getBool() const
Definition: C4Value.h:113
C4Def * getDef() const
Definition: C4Value.cpp:78
void Denumerate(C4ValueNumbers *)
Definition: C4Value.cpp:251
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:119
virtual void NoSeparator()
Definition: StdCompiler.h:120
void Value(const T &rStruct)
Definition: StdCompiler.h:161
bool isSerializer()
Definition: StdCompiler.h:54
virtual bool isDeserializer()
Definition: StdCompiler.h:53
void Ref(const char *pnData)
Definition: StdBuf.h:455
const char * getData() const
Definition: StdBuf.h:442
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174
ObjectAddWaypoint(C4Object *obj)
Definition: C4Command.cpp:230
bool operator()(int32_t iX, int32_t iY, C4Object *TransferTarget)
Definition: C4Command.cpp:231