OpenClonk
C4ObjectPhysics.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 /* Logic for C4Object: Physics and landscape interaction */
19 
20 #include "C4Include.h"
22 #include "object/C4Object.h"
23 
24 #include "game/C4Physics.h"
25 #include "gui/C4GameMessage.h"
27 #include "landscape/C4PXS.h"
28 #include "landscape/C4SolidMask.h"
29 #include "lib/C4Random.h"
30 #include "lib/C4Real.h"
31 #include "object/C4Def.h"
32 #include "object/C4GameObjects.h"
33 #include "object/C4ObjectCom.h"
34 #include "platform/C4SoundSystem.h"
35 
36 
38 {
39  // Get new area covered:
40  // Do *NOT* do this while initializing, because object cannot be sorted by main list
41  if (!Initializing && Status == C4OS_NORMAL)
42  {
43  ::Objects.UpdatePos(this);
44  }
45 }
46 
48 {
49  Mass = std::max<int32_t>((Def->Mass + OwnMass) * Con / FullCon, 1);
50  if (!Def->NoMassFromContents)
51  {
52  Mass += Contents.Mass;
53  }
54  if (Contained)
55  {
58  }
59 }
60 
61 void C4Object::UpdateInMat()
62 {
63  // Get the current material
64  int32_t newmat;
65  if (Contained)
66  {
68  }
69  else
70  {
71  newmat = GBackMat(GetX(), GetY());
72  }
73 
74  // Has the material changed?
75  if (newmat != InMat)
76  {
78  InMat = newmat;
79  }
80 }
81 
82 bool C4Object::At(int32_t ctx, int32_t cty) const
83 {
84  return Status
85  && !Contained
86  && Def
87  // TODO: Do a separate check in C4Shape
88  && Inside<int32_t>(cty - (GetY() + Shape.GetY() - addtop()), 0, Shape.Hgt - 1 + addtop())
89  && Inside<int32_t>(ctx - (GetX() + Shape.GetX()), 0, Shape.Wdt - 1);
90 }
91 
92 bool C4Object::At(int32_t ctx, int32_t cty, DWORD &ocf) const
93 {
94  if (Status
95  && !Contained
96  && Def
97  && (OCF & ocf)
98  // TODO: Do a separate check in C4Shape
99  && Inside<int32_t>(cty - (GetY() + Shape.GetY() - addtop()), 0, Shape.Hgt - 1 + addtop())
100  && Inside<int32_t>(ctx - (GetX() + Shape.GetX()), 0, Shape.Wdt - 1))
101  {
102  // Set ocf return value
103  GetOCFForPos(ctx, cty, ocf);
104  return true;
105  }
106  return false;
107 }
108 
109 void C4Object::Fling(C4Real fling_xdir, C4Real fling_ydir, bool add_speed)
110 {
111  if (add_speed)
112  {
113  fling_xdir += xdir / 2;
114  fling_ydir += ydir / 2;
115  }
116  if (!ObjectActionTumble(this, (fling_xdir < 0), fling_xdir, fling_ydir)
117  && !ObjectActionJump(this, fling_xdir, fling_ydir, false))
118  {
119  xdir = fling_xdir;
120  ydir = fling_ydir;
121  Mobile = true;
123  }
124 }
125 
126 bool C4Object::Push(C4Real txdir, C4Real dforce, bool fStraighten)
127 {
128  // Valid check
129  if (!Status || !Def || Contained || !(OCF & OCF_Grab))
130  {
131  return false;
132  }
133  // Grabbing okay, no pushing
134  if (GetPropertyInt(P_Touchable) == 2)
135  {
136  return true;
137  }
138  // Mobilization check (pre-mobilization zero)
139  if (!Mobile)
140  {
141  xdir = ydir = Fix0;
142  }
143  // General pushing force vs. object mass
144  dforce = dforce * 100 / Mass;
145  // Set dir
146  if (xdir < 0) SetDir(DIR_Left);
147  if (xdir > 0) SetDir(DIR_Right);
148  // Work towards txdir
149  if (Abs(xdir - txdir) <= dforce) // Close-enough-set
150  {
151  xdir = txdir;
152  }
153  else // Work towards
154  {
155  if (xdir < txdir) xdir += dforce;
156  if (xdir > txdir) xdir -= dforce;
157  }
158  // Straighten
159  if (fStraighten)
160  {
161  if (Inside<int32_t>(GetR(), -StableRange, +StableRange))
162  {
163  rdir = 0; // Cheap way out
164  }
165  else
166  {
167  if (fix_r > Fix0)
168  {
169  if (rdir > -RotateAccel)
170  {
171  rdir -= dforce;
172  }
173  }
174  else
175  {
176  if (rdir < +RotateAccel)
177  {
178  rdir += dforce;
179  }
180  }
181  }
182  }
183 
184  // Mobilization check
185  if (!!xdir || !!ydir || !!rdir)
186  {
187  Mobile = true;
188  }
189 
190  // Stuck check
191  if (!::Game.iTick35
192  && txdir
193  && !Def->NoHorizontalMove
194  && ContactCheck(GetX(), GetY())) // Resets t_contact
195  {
196  GameMsgObjectError(FormatString(LoadResStr("IDS_OBJ_STUCK"), GetName()).getData(), this);
197  Call(PSF_Stuck);
198  }
199 
200  return true;
201 }
202 
203 bool C4Object::Lift(C4Real tydir, C4Real dforce)
204 {
205  // Valid check
206  if (!Status || !Def || Contained)
207  {
208  return false;
209  }
210  // Mobilization check
211  if (!Mobile)
212  {
213  xdir = ydir = Fix0;
214  Mobile = true;
215  }
216  // General pushing force vs. object mass
217  dforce = dforce * 100 / Mass;
218  // If close enough, set tydir
219  if (Abs(tydir - ydir) <= Abs(dforce))
220  {
221  ydir = tydir;
222  }
223  else // Work towards tydir
224  {
225  if (ydir<tydir) ydir+=dforce;
226  if (ydir>tydir) ydir-=dforce;
227  }
228  // Stuck check
229  if (tydir != -GravAccel
230  && ContactCheck(GetX(), GetY())) // Resets t_contact
231  {
232  GameMsgObjectError(FormatString(LoadResStr("IDS_OBJ_STUCK"), GetName()).getData(), this);
233  Call(PSF_Stuck);
234  }
235  return true;
236 }
237 
239 {
240  rxdir = rydir = 0;
241  if (!Status || !Def)
242  {
243  return 0;
244  }
245  rxdir = xdir;
246  rydir = ydir;
247  return 1;
248 }
249 
251 {
252  // TODO: This is actually not the real speed of the object,
253  // it is actually a "Manhattan" speed :)
254  // Note: Relevant for OCF calculation only...
255  C4Real speed = Fix0;
256  if (xdir < 0) speed -= xdir; else speed += xdir;
257  if (ydir < 0) speed -= ydir; else speed += ydir;
258  return speed;
259 }
260 
261 void C4Object::SetSolidMask(int32_t x, int32_t y, int32_t wdt, int32_t hgt, int32_t tx, int32_t ty)
262 {
263  // Remove old
264  if (pSolidMaskData)
265  {
266  delete pSolidMaskData;
267  pSolidMaskData = nullptr;
268  }
269  // Set new data
270  SolidMask.Set(x, y, wdt, hgt, tx, ty);
271  // Re-put if valid
272  if (CheckSolidMaskRect())
273  {
274  UpdateSolidMask(false);
275  }
276 }
277 
279 {
280  if (pSolidMaskData)
281  {
282  HalfVehicleSolidMask = set;
284  }
285 }
286 
288 {
289  // Ensure SolidMask rect lies within bounds of SolidMask bitmap in definition
290  CSurface8 *mask = Def->pSolidMask;
291  if (!mask)
292  {
293  // No graphics to set solid in
294  SolidMask.Set(0, 0, 0, 0, 0, 0);
295  return false;
296  }
297  SolidMask.Set(std::max<int32_t>(SolidMask.x,0), std::max<int32_t>(SolidMask.y, 0),
298  std::min<int32_t>(SolidMask.Wdt, mask->Wdt - SolidMask.x), std::min<int32_t>(SolidMask.Hgt, mask->Hgt-SolidMask.y),
300  if (SolidMask.Hgt <= 0)
301  {
302  SolidMask.Wdt = 0;
303  }
304  return SolidMask.Wdt > 0;
305 }
306 
308 {
309  return GBackLiquid(GetX(), GetY() + Def->Float * Con / FullCon - 1);
310 }
311 
312 void C4Object::SetRotation(int32_t new_rotation)
313 {
314  while (new_rotation < 0)
315  {
316  new_rotation += 360;
317  }
318  new_rotation %= 360;
319  // Remove solid mask
320  RemoveSolidMask(false);
321  // Set rotation
322  fix_r = itofix(new_rotation);
323  // Update face
324  UpdateFace(true);
325 }
326 
328 {
329  if (pSolidMaskData)
330  {
331  pSolidMaskData->Draw(cgo);
332  }
333 }
334 
335 void C4Object::RemoveSolidMask(bool fBackupAttachment)
336 {
337  if (pSolidMaskData)
338  {
339  pSolidMaskData->Remove(fBackupAttachment);
340  }
341 }
342 
343 void C4Object::UpdateSolidMask(bool fRestoreAttachedObjects)
344 {
345  // Solidmask doesn't make sense with non-existant objects
346  // (the solidmask has already been destroyed in AssignRemoval -
347  // do not reset it!)
348  if (!Status)
349  {
350  return;
351  }
352  // Determine necessity, update cSolidMask, put or remove mask
353  // Mask if enabled, fullcon, not contained
354  if (SolidMask.Wdt > 0 && Con >= FullCon && !Contained)
355  {
356  // Recheck and put mask
357  if (!pSolidMaskData)
358  {
359  pSolidMaskData = new C4SolidMask(this);
360  }
361  else
362  {
363  pSolidMaskData->Remove(false);
364  }
365  pSolidMaskData->Put(true, nullptr, fRestoreAttachedObjects);
367  }
368  // Otherwise, remove and destroy mask
369  else if (pSolidMaskData)
370  {
371  delete pSolidMaskData;
372  pSolidMaskData = nullptr;
373  }
374 }
375 
376 bool C4Object::AdjustWalkRotation(int32_t range_x, int32_t range_y, int32_t speed)
377 {
378  int32_t dest_angle;
379  // Attachment at middle (bottom) vertex?
380  if (Shape.iAttachVtx < 0 || !Def->Shape.VtxX[Shape.iAttachVtx])
381  {
382  // Evaluate floor around attachment pos
383  int32_t y_solid_left = 0;
384  int32_t y_solid_right = 0;
385  // Left
386  int32_t check_x = Shape.iAttachX - range_x;
387  if (GBackSolid(check_x, Shape.iAttachY))
388  {
389  // Up
390  while (--y_solid_left > -range_y)
391  {
392  if (GBackSolid(check_x, Shape.iAttachY + y_solid_left))
393  {
394  ++y_solid_left;
395  break;
396  }
397  }
398  }
399  else
400  {
401  // Down
402  while (++y_solid_left < range_y)
403  {
404  if (GBackSolid(check_x, Shape.iAttachY + y_solid_left))
405  {
406  --y_solid_left;
407  break;
408  }
409  }
410  }
411  // Right
412  check_x += 2 * range_x;
413  if (GBackSolid(check_x, Shape.iAttachY))
414  {
415  // Up
416  while (--y_solid_right > -range_y)
417  {
418  if (GBackSolid(check_x, Shape.iAttachY + y_solid_right))
419  {
420  ++y_solid_right;
421  break;
422  }
423  }
424  }
425  else
426  {
427  // Down
428  while (++y_solid_right < range_y)
429  {
430  if (GBackSolid(check_x, Shape.iAttachY + y_solid_right))
431  {
432  --y_solid_right;
433  break;
434  }
435  }
436  }
437  // Calculate destination angle
438  // 100% accurate for large values of Pi ;)
439  dest_angle = (y_solid_right - y_solid_left) * (35 / std::max<int32_t>(range_x, 1));
440  }
441  else
442  {
443  // Attachment at other than horizontal middle vertex: get your feet to the ground!
444  // Rotate target to large angle is OK, because rotation will stop once the real
445  // bottom vertex hits solid ground
446  if (Shape.VtxX[Shape.iAttachVtx] > 0)
447  {
448  dest_angle = -50;
449  }
450  else
451  {
452  dest_angle = 50;
453  }
454  }
455  // Move to destination angle
456  if (Abs(dest_angle - GetR()) > 2)
457  {
458  rdir = itofix(Clamp<int32_t>(dest_angle-GetR(), -15, +15));
459  rdir /= (10000 / speed);
460  }
461  else
462  {
463  rdir = 0;
464  }
465  // Done, success
466  return true;
467 }
468 
469 static void BubbleOut(int32_t tx, int32_t ty)
470 {
471  // No bubbles from nowhere
472  if (!GBackSemiSolid(tx, ty))
473  {
474  return;
475  }
476  // Enough bubbles out there already
477  if (::Objects.ObjectCount(C4ID::Bubble) >= 150)
478  {
479  return;
480  }
481  // Create bubble
482  Game.CreateObject(C4ID::Bubble, nullptr, NO_OWNER, tx, ty);
483 }
484 
485 void C4Object::Splash()
486 {
487  int32_t tx = GetX();
488  int32_t ty = GetY() + 1;
489  int32_t amt = std::min(Shape.Wdt * Shape.Hgt / 10, 20);
490  // Splash only if there is free space above
491  if (GBackSemiSolid(tx, ty - 15))
492  {
493  return;
494  }
495  // Get back material
496  int32_t iMat = GBackMat(tx, ty);
497  // Check liquid
498  if (MatValid(iMat)
500  && ::MaterialMap.Map[iMat].Instable)
501  {
502  int32_t sy = ty;
503  while (GBackLiquid(tx, sy) && sy > ty - 20 && sy >= 0)
504  {
505  sy--;
506  }
507  // Splash bubbles and liquid
508  for (int32_t cnt = 0; cnt < amt; cnt++)
509  {
510  int32_t bubble_x = tx + Random(16) - 8;
511  int32_t bubble_y = ty + Random(16) - 6;
512  BubbleOut(bubble_x, bubble_y);
513  if (GBackLiquid(tx, ty) && !GBackSemiSolid(tx, sy))
514  {
515  C4Real xdir = C4REAL100(Random(151) - 75);
516  C4Real ydir = C4REAL100(-int32_t(Random(200)));
517  ::PXS.Create(::Landscape.ExtractMaterial(tx, ty, false),
518  itofix(tx), itofix(sy),
519  xdir,
520  ydir);
521  }
522  }
523  }
524  // Splash sound
525  if (amt >= 20)
526  {
527  StartSoundEffect("Liquids::Splash2", false, 50, this);
528  }
529  else if (amt > 1)
530  {
531  StartSoundEffect("Liquids::Splash1", false, 50, this);
532  }
533 }
534 
536 {
537  // InLiquid check
538  if (IsInLiquidCheck()) // In Liquid
539  {
540  if (!InLiquid) // Enter liquid
541  {
542  if ((OCF & OCF_HitSpeed2) && Mass > 3)
543  {
544  Splash();
545  }
546  InLiquid = true;
547  }
548  }
549  else if (InLiquid) // Leave liquid
550  {
551  InLiquid = false;
552  }
553 }
554 
555 bool C4Object::IsMoveableBySolidMask(int ComparisonPlane) const
556 {
557  return (Status == C4OS_NORMAL)
558  && !(Category & C4D_StaticBack)
559  && (ComparisonPlane < GetPlane())
560  && !Contained;
561 }
562 
564 {
565  // Use SolidMaskPlane property. Fallback to object plane if unassigned.
566  int32_t plane = GetPropertyInt(P_SolidMaskPlane);
567  return plane ? plane : GetPlane();
568 }
const int32_t FullCon
Definition: C4Constants.h:181
const uint32_t OCF_Grab
Definition: C4Constants.h:81
const BYTE CNAT_Bottom
Definition: C4Constants.h:112
const int32_t MNone
Definition: C4Constants.h:177
const uint32_t OCF_HitSpeed2
Definition: C4Constants.h:91
const int NO_OWNER
Definition: C4Constants.h:137
const int32_t C4D_StaticBack
Definition: C4Def.h:40
void GameMsgObjectError(const char *szText, C4Object *pTarget, bool Red)
#define PSF_Stuck
Definition: C4GameScript.h:74
#define PSF_OnMaterialChanged
Definition: C4GameScript.h:153
C4Game Game
Definition: C4Globals.cpp:52
C4GameObjects Objects
Definition: C4Globals.cpp:48
C4Landscape Landscape
bool GBackLiquid(int32_t x, int32_t y)
Definition: C4Landscape.h:239
bool GBackSemiSolid(int32_t x, int32_t y)
Definition: C4Landscape.h:234
int32_t GBackMat(int32_t x, int32_t y)
Definition: C4Landscape.h:219
bool DensityLiquid(int32_t dens)
Definition: C4Landscape.h:206
bool GBackSolid(int32_t x, int32_t y)
Definition: C4Landscape.h:229
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
C4MaterialMap MaterialMap
Definition: C4Material.cpp:974
bool MatValid(int32_t mat)
Definition: C4Material.h:210
#define DIR_Right
Definition: C4Object.h:42
#define DIR_Left
Definition: C4Object.h:41
#define C4OS_NORMAL
Definition: C4Object.h:35
bool ObjectActionJump(C4Object *cObj, C4Real xdir, C4Real ydir, bool fByCom)
Definition: C4ObjectCom.cpp:50
bool ObjectActionTumble(C4Object *cObj, int32_t dir, C4Real xdir, C4Real ydir)
Definition: C4ObjectCom.cpp:88
C4PXSSystem PXS
Definition: C4PXS.cpp:423
const int StableRange
Definition: C4Physics.h:23
const C4Real RotateAccel
Definition: C4Movement.cpp:36
#define GravAccel
Definition: C4Physics.h:27
uint32_t Random()
Definition: C4Random.cpp:43
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
const C4Real Fix0
Definition: C4Real.h:312
C4Real C4REAL100(int x)
Definition: C4Real.h:267
C4SoundInstance * StartSoundEffect(const char *szSndName, bool fLoop, int32_t iVolume, C4Object *pObj, int32_t iCustomFalloffDistance, int32_t iPitch, C4SoundModifier *modifier)
@ P_Touchable
@ P_SolidMaskPlane
uint8_t BYTE
uint32_t DWORD
T Abs(T val)
Definition: Standard.h:42
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
int32_t t_attach
Definition: C4Object.h:86
int32_t Mass
Definition: C4Def.h:114
int32_t Float
Definition: C4Def.h:120
int32_t NoMassFromContents
Definition: C4Def.h:136
C4Shape Shape
Definition: C4Def.h:104
int32_t NoHorizontalMove
Definition: C4Def.h:122
CSurface8 * pSolidMask
Definition: C4Def.h:192
int32_t ClosedContainer
Definition: C4Def.h:138
Definition: C4Real.h:59
int32_t iTick35
Definition: C4Game.h:130
C4Object * CreateObject(C4PropList *type, C4Object *creator, int32_t owner=NO_OWNER, int32_t x=50, int32_t y=50, int32_t r=0, bool grow_from_center=false, C4Real xdir=Fix0, C4Real ydir=Fix0, C4Real rdir=Fix0, int32_t controller=NO_OWNER)
Definition: C4Game.cpp:1334
void UpdatePos(C4Object *game_object)
static const C4ID Bubble
Definition: C4Id.h:41
int32_t ExtractMaterial(int32_t fx, int32_t fy, bool distant_first)
int32_t Density
Definition: C4Material.h:92
int32_t Instable
Definition: C4Material.h:102
C4Material * Map
Definition: C4Material.h:169
void UpdateSolidMask(bool fRestoreAttachedObjects)
int32_t OwnMass
Definition: C4Object.h:113
bool At(int32_t ctx, int32_t cty) const
void GetOCFForPos(int32_t ctx, int32_t cty, DWORD &ocf) const
C4Real ydir
Definition: C4Object.h:124
int32_t ContactCheck(int32_t at_x, int32_t at_y, uint32_t *border_hack_contacts=nullptr, bool collide_halfvehic=false)
Definition: C4Movement.cpp:158
void SetHalfVehicleSolidMask(bool set)
bool HalfVehicleSolidMask
Definition: C4Object.h:149
void UpdateMass()
C4Real xdir
Definition: C4Object.h:124
void UpdateFace(bool bUpdateShape, bool fTemp=false)
bool AdjustWalkRotation(int32_t iRangeX, int32_t iRangeY, int32_t iSpeed)
C4TargetRect SolidMask
Definition: C4Object.h:148
C4Real GetSpeed() const
bool Initializing
Definition: C4Object.h:128
bool IsMoveableBySolidMask(int ComparisonPlane) const
int32_t GetX() const
Definition: C4Object.h:285
int32_t Category
Definition: C4Object.h:111
int32_t GetSolidMaskPlane() const
bool IsInLiquidCheck() const
void UpdateInLiquid()
void SetDir(int32_t tdir)
uint32_t OCF
Definition: C4Object.h:132
void Fling(C4Real txdir, C4Real tydir, bool fAddSpeed)
bool Push(C4Real txdir, C4Real dforce, bool fStraighten)
C4Real fix_r
Definition: C4Object.h:123
bool Mobile
Definition: C4Object.h:126
int32_t Con
Definition: C4Object.h:172
int32_t InMat
Definition: C4Object.h:117
C4SolidMask * pSolidMaskData
Definition: C4Object.h:175
int32_t GetY() const
Definition: C4Object.h:286
bool Lift(C4Real tydir, C4Real dforce)
void DrawSolidMask(C4TargetFacet &cgo) const
C4NotifyingObjectList Contents
Definition: C4Object.h:151
int32_t GetR() const
Definition: C4Object.h:287
int32_t GetPlane() const
Definition: C4Object.h:179
C4ObjectPtr Contained
Definition: C4Object.h:142
bool CheckSolidMaskRect()
C4Real rdir
Definition: C4Object.h:124
C4Action Action
Definition: C4Object.h:145
int32_t Mass
Definition: C4Object.h:113
bool InLiquid
Definition: C4Object.h:129
C4Def * Def
Definition: C4Object.h:141
void UpdatePos()
void SetSolidMask(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, int32_t iTX, int32_t iTY)
int32_t addtop() const
Definition: C4Object.h:280
void SetRotation(int32_t nr)
C4Shape Shape
Definition: C4Object.h:146
BYTE GetMomentum(C4Real &rxdir, C4Real &rydir) const
int ObjectCount(C4ID id=C4ID::None) const
bool Create(int32_t mat, C4Real ix, C4Real iy, C4Real ixdir=Fix0, C4Real iydir=Fix0)
Definition: C4PXS.cpp:175
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val=0) const
Definition: C4PropList.cpp:855
virtual const char * GetName() const
Definition: C4PropList.cpp:618
int32_t Status
Definition: C4PropList.h:173
C4Value Call(C4PropertyName k, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4PropList.h:114
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
int32_t GetX() const
Definition: C4Shape.h:62
int32_t iAttachY
Definition: C4Shape.h:53
int32_t iAttachX
Definition: C4Shape.h:53
int32_t iAttachVtx
Definition: C4Shape.h:53
int32_t GetY() const
Definition: C4Shape.h:63
int32_t VtxX[C4D_MaxVertex]
Definition: C4Shape.h:43
void Draw(C4TargetFacet &cgo)
void Put(bool fCauseInstability, C4TargetRect *pClipRect, bool fRestoreAttachment)
Definition: C4SolidMask.cpp:32
void Remove(bool fBackupAttachment)
void SetHalfVehicle(bool set)
void Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, int32_t iTX, int32_t iTY)
Definition: C4Rect.cpp:45
int32_t tx
Definition: C4Rect.h:79
int32_t ty
Definition: C4Rect.h:79
int Wdt
Definition: CSurface8.h:28
int Hgt
Definition: CSurface8.h:28