1/*
2 * LegacyClonk
3 *
4 * Copyright (c) 1998-2000, Matthes Bender (RedWolf Design)
5 * Copyright (c) 2017-2022, The LegacyClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16
17/* That which fills the world with life */
18
19#pragma once
20
21#include "C4Command.h"
22#include "C4Effects.h"
23#include "C4EnumeratedObjectPtr.h"
24#include "C4Facet.h"
25#include "C4Id.h"
26#include "C4Landscape.h"
27#include "C4ObjectInfo.h"
28#include "C4Particles.h"
29#include "C4Player.h"
30#include "C4Sector.h"
31#include "C4Value.h"
32#include "C4ValueList.h"
33
34#include <array>
35#include <string>
36
37/* Object status */
38
39#define C4OS_DELETED 0
40#define C4OS_NORMAL 1
41#define C4OS_INACTIVE 2
42
43/* Action.Dir is the direction the object is actually facing. */
44
45#define DIR_None 0
46#define DIR_Left 0
47#define DIR_Right 1
48
49/*
50Action.ComDir tells an active object which way it ought to be going.
51If you set the ComDir to COMD_Stop, the object won't sit still immediately
52but will try to slow down according to it's current Action. ComDir values
53circle clockwise from COMD_Up 1 through COMD_UpLeft 8.
54*/
55
56#define COMD_None 0
57#define COMD_Stop 0
58#define COMD_Up 1
59#define COMD_UpRight 2
60#define COMD_Right 3
61#define COMD_DownRight 4
62#define COMD_Down 5
63#define COMD_DownLeft 6
64#define COMD_Left 7
65#define COMD_UpLeft 8
66
67// Visibility values tell conditions for an object's visibility
68
69#define VIS_All 0
70#define VIS_None 1
71#define VIS_Owner 2
72#define VIS_Allies 4
73#define VIS_Enemies 8
74#define VIS_Local 16
75#define VIS_God 32
76#define VIS_LayerToggle 64
77#define VIS_OverlayOnly 128
78
79const int32_t FullCon = 100000;
80
81const int32_t MagicPhysicalFactor = 1000;
82
83#define ANY_CONTAINER (123)
84#define NO_CONTAINER (124)
85
86class C4SolidMask;
87
88class C4Action
89{
90public:
91 C4Action();
92 ~C4Action();
93
94public:
95 char Name[C4D_MaxIDLen + 1];
96 int32_t Act; // NoSave //
97 int32_t Dir;
98 int32_t DrawDir; // NoSave // - needs to be calculated for old-style objects.txt anyway
99 int32_t ComDir;
100 int32_t Time;
101 int32_t Data;
102 int32_t Phase, PhaseDelay;
103 int32_t t_attach; // SyncClearance-NoSave //
104 C4EnumeratedObjectPtr Target, Target2;
105 C4Facet Facet; // NoSave //
106 int32_t FacetX, FacetY; // NoSave //
107
108public:
109 void Default();
110 void CompileFunc(StdCompiler *pComp);
111
112 // BRIDGE procedure: data mask
113 void SetBridgeData(int32_t iBridgeTime, bool fMoveClonk, bool fWall, int32_t iBridgeMaterial);
114 void GetBridgeData(int32_t &riBridgeTime, bool &rfMoveClonk, bool &rfWall, int32_t &riBridgeMaterial);
115};
116
117class C4Object
118{
119public:
120 C4Object();
121 ~C4Object();
122 int32_t Number; // int32_t, for sync safety on all machines
123 C4ID id;
124 int32_t Status; // NoSave //
125 int32_t RemovalDelay; // NoSave //
126 int32_t Owner;
127 int32_t Controller;
128 int32_t LastEnergyLossCausePlayer; // last player that caused an energy loss to this Clonk (used to trace kills when player tumbles off a cliff, etc.)
129 int32_t Category;
130 int32_t x, y;
131 int32_t old_x, old_y; C4LArea Area; // position as currently seen by Game.Objecets.Sectors. UpdatePos to sync.
132 int32_t r;
133 int32_t motion_x, motion_y;
134 int32_t NoCollectDelay;
135 int32_t Base;
136 int32_t Mass, OwnMass;
137 int32_t Damage;
138 int32_t Energy;
139 int32_t MagicEnergy;
140 int32_t Breath;
141 int32_t FirePhase;
142 int32_t InMat; // SyncClearance-NoSave //
143 uint32_t Color;
144 int32_t Timer;
145 int32_t ViewEnergy; // NoSave //
146 C4ValueList Local;
147 C4ValueMapData LocalNamed;
148 int32_t PlrViewRange;
149 C4Fixed fix_x, fix_y, fix_r; // SyncClearance-Fix //
150 C4Fixed xdir, ydir, rdir;
151 int32_t iLastAttachMovementFrame; // last frame in which Attach-movement by a SolidMask was done
152 bool Mobile;
153 bool Select;
154 bool Unsorted; // NoSave //
155 bool Initializing; // NoSave //
156 bool InLiquid;
157 bool EntranceStatus;
158 bool NeedEnergy;
159 uint32_t t_contact; // SyncClearance-NoSave //
160 uint32_t OCF;
161 int32_t Visibility;
162 uint32_t Marker; // state var used by Objects::CrossCheck and C4FindObject - NoSave
163 C4EnumeratedObjectPtr pLayer; // layer-object containing this object
164 C4DrawTransform *pDrawTransform; // assigned drawing transformation
165
166 // Menu
167 class C4ObjectMenu *Menu; // SyncClearance-NoSave //
168
169 C4Facet TopFace; // NoSave //
170 C4Def *Def;
171 C4EnumeratedObjectPtr Contained;
172 C4ObjectInfo *Info;
173
174 C4Action Action;
175 C4Shape Shape;
176 bool fOwnVertices; // if set, vertices aren't restored from def but from end of own vtx list
177 C4TargetRect SolidMask;
178 C4SolidMask *pSolidMaskData; // NoSave //
179 C4IDList Component;
180 C4Rect PictureRect;
181 C4NotifyingObjectList Contents;
182 std::array<int32_t, C4MaxMaterial> MaterialContents; // SyncClearance-NoSave //
183 C4DefGraphics *pGraphics; // currently set object graphics
184 C4Effect *pEffects; // linked list of effects
185 C4ParticleList FrontParticles, BackParticles; // lists of object local particles
186
187 bool PhysicalTemporary; // physical temporary counter
188 C4TempPhysicalInfo TemporaryPhysical;
189
190 uint32_t ColorMod; // color by which the object-drawing is modulated
191 uint32_t BlitMode; // extra blitting flags (like additive, ClrMod2, etc.)
192 bool CrewDisabled; // CrewMember-functionality currently disabled
193
194 // Commands
195 C4Command *Command;
196
197 StdStrBuf nInfo;
198
199 C4Value *FirstRef; // No-Save
200
201 class C4GraphicsOverlay *pGfxOverlay; // singly linked list of overlay graphics
202
203protected:
204 std::string CustomName;
205 bool OnFire;
206 int32_t Con;
207 bool Alive;
208 int32_t Audible, AudiblePan; // NoSave //
209
210public:
211 void Resort();
212 void DigOutMaterialCast(bool fRequest);
213 void AddMaterialContents(int32_t iMaterial, int32_t iAmount);
214 void SetCommand(int32_t iCommand, C4Object *pTarget, C4Value iTx, int32_t iTy = 0, C4Object *pTarget2 = nullptr, bool fControl = false, int32_t iData = 0, int32_t iRetries = 0, const char *szText = nullptr);
215
216 void SetCommand(int32_t iCommand, C4Object *pTarget = nullptr, int32_t iTx = 0, int32_t iTy = 0, C4Object *pTarget2 = nullptr, bool fControl = false, int32_t iData = 0, int32_t iRetries = 0, const char *szText = nullptr)
217 {
218 SetCommand(iCommand, pTarget, iTx: C4VInt(iVal: iTx), iTy, pTarget2, fControl, iData, iRetries, szText);
219 }
220
221 bool AddCommand(int32_t iCommand, C4Object *pTarget, C4Value iTx, int32_t iTy = 0, int32_t iUpdateInterval = 0, C4Object *pTarget2 = nullptr, bool fInitEvaluation = true, int32_t iData = 0, bool fAppend = false, int32_t iRetries = 0, const char *szText = nullptr, int32_t iBaseMode = 0);
222
223 bool AddCommand(int32_t iCommand, C4Object *pTarget = nullptr, int32_t iTx = 0, int32_t iTy = 0, int32_t iUpdateInterval = 0, C4Object *pTarget2 = nullptr, bool fInitEvaluation = true, int32_t iData = 0, bool fAppend = false, int32_t iRetries = 0, const char *szText = nullptr, int32_t iBaseMode = 0)
224 {
225 return AddCommand(iCommand, pTarget, iTx: C4VInt(iVal: iTx), iTy, iUpdateInterval, pTarget2, fInitEvaluation, iData, fAppend, iRetries, szText, iBaseMode);
226 }
227
228 C4Command *FindCommand(int32_t iCommandType); // find a command of the given type
229 void ClearCommand(C4Command *pUntil);
230 void ClearCommands();
231 void DrawSelectMark(C4FacetEx &cgo);
232 void UpdateActionFace();
233 void SyncClearance();
234 void SetSolidMask(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt, int32_t iTX, int32_t iTY);
235 bool CheckSolidMaskRect(); // clip bounds of SolidMask in graphics - return whether the solidmask still exists
236 C4Object *ComposeContents(C4ID id);
237 bool MenuCommand(const char *szCommand);
238
239 bool CallControl(C4Player *pPlr, uint8_t byCom, const C4AulParSet &pPars = C4AulParSet{});
240 C4Value Call(const char *szFunctionCall, const C4AulParSet &pPars = C4AulParSet{}, bool fPassError = false, bool convertNilToIntBool = true);
241
242 bool ContainedControl(uint8_t byCom);
243
244 void Clear();
245 void ClearInfo(C4ObjectInfo *pInfo);
246 bool AssignInfo();
247 bool ValidateOwner();
248 bool AssignPlrViewRange();
249 void DrawPicture(C4Facet &cgo, bool fSelected = false, C4RegionList *pRegions = nullptr);
250 void Picture2Facet(C4FacetExSurface &cgo); // set picture to facet, or create facet in current size and draw if specific states are being needed
251 void DenumeratePointers();
252 void EnumeratePointers();
253 void Default();
254 bool Init(C4Def *ndef, C4Object *pCreator,
255 int32_t owner, C4ObjectInfo *info,
256 int32_t nx, int32_t ny, int32_t nr,
257 C4Fixed nxdir, C4Fixed nydir, C4Fixed nrdir, int32_t iController);
258 void CompileFunc(StdCompiler *pComp);
259 void DrawEnergy(C4Facet &cgo);
260 void DrawMagicEnergy(C4Facet &cgo);
261 void DrawBreath(C4Facet &cgo);
262 void DrawLine(C4FacetEx &cgo);
263 void DrawCommands(C4Facet &cgo, C4Facet &cgo2, C4RegionList *pRegions);
264 void DrawCommand(C4Facet &cgoBar, int32_t iAlign, const char *szFunctionFormat,
265 int32_t iCom, C4RegionList *pRegions, int32_t iPlayer, const char *szDesc = nullptr,
266 C4Facet *pfctImage = nullptr);
267 bool SetPhase(int32_t iPhase);
268 void AssignRemoval(bool fExitContents = false);
269 enum DrawMode { ODM_Normal = 0, ODM_Overlay = 1, ODM_BaseOnly = 2, };
270 void Draw(C4FacetEx &cgo, int32_t iByPlayer = -1, DrawMode eDrawMode = ODM_Normal);
271 void DrawTopFace(C4FacetEx &cgo, int32_t iByPlayer = -1, DrawMode eDrawMode = ODM_Normal);
272 void DrawFace(C4FacetEx &cgo, int32_t cgoX, int32_t cgoY, int32_t iPhaseX = 0, int32_t iPhaseY = 0);
273 void Execute();
274 void ClearPointers(C4Object *ptr);
275 bool ExecMovement();
276 bool ExecFire(int32_t iIndex, int32_t iCausedByPlr);
277 void ExecAction();
278 bool ExecLife();
279 bool ExecuteCommand();
280 void ExecBase();
281 void AssignDeath(bool fForced); // assigns death - if forced, it's killed even if an effect stopped this
282 void ContactAction();
283 void NoAttachAction();
284 void DoMovement();
285 void Stabilize();
286 void SetOCF();
287 void UpdateOCF(); // Update fluctuant OCF
288 void UpdateShape(bool bUpdateVertices = true);
289 void UpdatePos(); // pos/shape changed
290 void UpdateSolidMask(bool fRestoreAttachedObjects);
291 void UpdateMass();
292 void ComponentConCutoff();
293 void ComponentConGain();
294 bool ChangeDef(C4ID idNew);
295 void UpdateFace(bool bUpdateShape, bool fTemp = false);
296 void UpdateGraphics(bool fGraphicsChanged, bool fTemp = false); // recreates solidmasks (if fGraphicsChanged), validates Color
297 void UpdateFlipDir(); // applies new flipdir to draw transform matrix; creates/deletes it if necessary
298 bool At(int32_t ctx, int32_t cty);
299 bool At(int32_t ctx, int32_t cty, uint32_t &ocf);
300 void GetOCFForPos(int32_t ctx, int32_t cty, uint32_t &ocf);
301 bool CloseMenu(bool fForce);
302 bool ActivateMenu(int32_t iMenu, int32_t iMenuSelect = 0, int32_t iMenuData = 0, int32_t iMenuPosition = 0, C4Object *pTarget = nullptr);
303 void AutoContextMenu(int32_t iMenuSelect);
304 int32_t ContactCheck(int32_t atx, int32_t aty);
305 bool Contact(int32_t cnat);
306 void TargetBounds(int32_t &ctco, int32_t limit_low, int32_t limit_hi, int32_t cnat_low, int32_t cnat_hi);
307 enum { SAC_StartCall = 1, SAC_EndCall = 2, SAC_AbortCall = 4, };
308 bool SetAction(int32_t iAct, C4Object *pTarget = nullptr, C4Object *pTarget2 = nullptr, int32_t iCalls = SAC_StartCall | SAC_AbortCall, bool fForce = false);
309 bool SetActionByName(const char *szActName, C4Object *pTarget = nullptr, C4Object *pTarget2 = nullptr, int32_t iCalls = SAC_StartCall | SAC_AbortCall, bool fForce = false);
310 void SetDir(int32_t tdir);
311 void SetCategory(int32_t Category) { this->Category = Category; Resort(); SetOCF(); }
312 int32_t GetProcedure();
313 bool Enter(C4Object *pTarget, bool fCalls = true, bool fCopyMotion = true, bool *pfRejectCollect = nullptr);
314 bool Exit(int32_t iX = 0, int32_t iY = 0, int32_t iR = 0, C4Fixed iXDir = Fix0, C4Fixed iYDir = Fix0, C4Fixed iRDir = Fix0, bool fCalls = true);
315 void CopyMotion(C4Object *from);
316 void ForcePosition(int32_t tx, int32_t ty);
317 void MovePosition(int32_t dx, int32_t dy);
318 void DoMotion(int32_t mx, int32_t my);
319 bool ActivateEntrance(int32_t by_plr, C4Object *by_obj);
320 bool Incinerate(int32_t iCausedBy, bool fBlasted = false, C4Object *pIncineratingObject = nullptr);
321 bool Extinguish(int32_t iFireNumber);
322 void DoDamage(int32_t iLevel, int32_t iCausedByPlr, int32_t iCause);
323 void DoEnergy(int32_t iChange, bool fExact, int32_t iCause, int32_t iCausedByPlr);
324 void UpdatLastEnergyLossCause(int32_t iNewCausePlr);
325 void DoBreath(int32_t iChange);
326 void DoCon(int32_t iChange, bool fInitial = false, bool fNoComponentChange = false);
327 int32_t GetCon() { return Con; }
328 void DoExperience(int32_t change);
329 bool Promote(int32_t torank, bool fForceRankName);
330 void Explode(int32_t iLevel, C4ID idEffect = 0, const char *szEffect = nullptr);
331 void Blast(int32_t iLevel, int32_t iCausedBy);
332 bool Build(int32_t iLevel, C4Object *pBuilder);
333 bool Chop(C4Object *pByObject);
334 bool Push(C4Fixed txdir, C4Fixed dforce, bool fStraighten);
335 bool Lift(C4Fixed tydir, C4Fixed dforce);
336 void Fling(C4Fixed txdir, C4Fixed tydir, bool fAddSpeed, int32_t byPlayer); // set/add given speed to current, setting jump/tumble-actions. also sets controller for kill tracing.
337 C4Object *CreateContents(C4ID n_id);
338 bool CreateContentsByList(C4IDList &idlist);
339 uint8_t GetArea(int32_t &aX, int32_t &aY, int32_t &aWdt, int32_t &aHgt);
340 inline int32_t addtop() { return std::max<int32_t>(a: 18 - Shape.Hgt, b: 0); } // Minimum top action size for build check
341 inline int32_t Left() { return x + Shape.x; } // left border of shape
342 inline int32_t Top() { return y + Shape.y - addtop(); } // top border of shape (+build-top)
343 inline int32_t Width() { return Shape.Wdt; } // width of shape
344 inline int32_t Height() { return Shape.Hgt + addtop(); } // height of shape (+build-top)
345 uint8_t GetEntranceArea(int32_t &aX, int32_t &aY, int32_t &aWdt, int32_t &aHgt);
346 C4Fixed GetSpeed();
347 C4PhysicalInfo *GetPhysical(bool fPermanent = false);
348 bool TrainPhysical(C4PhysicalInfo::Offset mpiOffset, int32_t iTrainBy, int32_t iMaxTrain);
349 const char *GetName();
350 void SetName(const char *NewName = nullptr);
351 int32_t GetValue(C4Object *pInBase, int32_t iForPlayer);
352 void DirectCom(uint8_t byCom, int32_t iData);
353 void AutoStopDirectCom(uint8_t byCom, int32_t iData);
354 void AutoStopUpdateComDir();
355 bool BuyEnergy();
356 void AutoSellContents();
357 bool SetOwner(int32_t iOwner);
358 bool SetPlrViewRange(int32_t iToRange);
359 void SetOnFire(bool OnFire) { this->OnFire = OnFire; SetOCF(); }
360 bool GetOnFire() { return OnFire; }
361 void SetAlive(bool Alive) { this->Alive = Alive; SetOCF(); }
362 bool GetAlive() { return Alive; }
363 void PlrFoWActualize();
364 void SetAudibilityAt(C4FacetEx &cgo, int32_t iX, int32_t iY);
365 int32_t GetAudibility();
366 int32_t GetAudiblePan();
367 void ResetAudibility() { Audible = -1; AudiblePan = 0; }
368 bool IsVisible(int32_t iForPlr, bool fAsOverlay); // return whether an object is visible for the given player
369 void SetRotation(int32_t nr);
370 void PrepareDrawing(); // set blit modulation and/or additive blitting
371 void FinishedDrawing(); // reset any modulation
372 bool Collect(C4Object *pObj); // add object to contents if it can be carried - no OCF and range checks are done!
373 bool GrabInfo(C4Object *pFrom); // grab info object from other object
374 bool ShiftContents(bool fShiftBack, bool fDoCalls); // rotate through contents
375 void DirectComContents(C4Object *pTarget, bool fDoCalls); // direct com: scroll contents to given ID
376
377 inline void TargetPos(int32_t &riTx, int32_t &riTy, const C4Facet &fctViewport) // update scroll pos applying parallaxity
378 {
379 if (Category & C4D_Parallax) ApplyParallaxity(riTx, riTy, fctViewport);
380 }
381
382 void ApplyParallaxity(int32_t &riTx, int32_t &riTy, const C4Facet &fctViewport); // apply parallaxity by locals of object
383 bool IsInLiquidCheck(); // returns whether the Clonk is within liquid material
384 void UpdateInLiquid(); // makes splash when a liquid is entered
385 void GrabContents(C4Object *pFrom); // grab all contents that don't reject it
386
387protected:
388 void SideBounds(int32_t &ctcox); // apply bounds at side; regarding bourder bound and pLayer
389 void VerticalBounds(int32_t &ctcoy); // apply bounds at top and bottom; regarding border bound and pLayer
390
391public:
392 void BoundsCheck(int32_t &ctcox, int32_t &ctcoy) // do bound checks, correcting target positions as necessary and doing contact-calls
393 {
394 SideBounds(ctcox); VerticalBounds(ctcoy);
395 }
396
397public:
398 bool DoSelect(bool fCursor = false); // select in crew (or just set cursor) if not disabled
399 void UnSelect(bool fCursor = false); // unselect in crew (or just task away cursor)
400
401 void GetViewPos(int32_t &riX, int32_t &riY, int32_t tx, int32_t ty, const C4Facet &fctViewport) // get position this object is seen at (for given scroll)
402 {
403 if (Category & C4D_Parallax) GetViewPosPar(riX, riY, tx, ty, fctViewport); else { riX = x; riY = y; }
404 }
405
406 void GetViewPosPar(int32_t &riX, int32_t &riY, int32_t tx, int32_t ty, const C4Facet &fctViewport); // get position this object is seen at, calculating parallaxity
407 bool PutAwayUnusedObject(C4Object *pToMakeRoomForObject); // either directly put the least-needed object away, or add a command to do it - return whether successful
408
409 C4DefGraphics *GetGraphics() { return pGraphics; } // return current object graphics
410 bool SetGraphics(const char *szGraphicsName = nullptr, C4Def *pSourceDef = nullptr); // set used graphics for object; if szGraphicsName or *szGraphicsName are nullptr, the default graphics of the given def are used; pSourceDef defaults to own def
411 bool SetGraphics(C4DefGraphics *pNewGfx, bool fUpdateData); // set used graphics for object
412
413 class C4GraphicsOverlay *GetGraphicsOverlay(int32_t iForID, bool fCreate); // get specified gfx overlay; create if not existent and specified
414 bool RemoveGraphicsOverlay(int32_t iOverlayID); // remove specified overlay from the overlay list; return if found
415 bool HasGraphicsOverlayRecursion(const C4Object *pCheckObj) const; // returns whether, at any overlay recursion depth, the given object appears as an MODE_Object-overlay
416 void UpdateScriptPointers(); // update ptrs to C4AulScript *
417
418 bool StatusActivate(); // put into active list
419 bool StatusDeactivate(bool fClearPointers); // put into inactive list
420
421 void ClearContentsAndContained(bool fDoCalls = true); // exit from container and eject contents (doing calbacks)
422
423 bool AdjustWalkRotation(int32_t iRangeX, int32_t iRangeY, int32_t iSpeed);
424
425 void AddRef(C4Value *pRef);
426 void DelRef(const C4Value *pRef, C4Value *pNextRef);
427
428 StdStrBuf GetInfoString(); // return def desc plus effects
429
430 bool CanConcatPictureWith(C4Object *pOtherObject); // return whether this object should be grouped with the other in activation lists, contents list, etc.
431
432 int32_t GetFireCausePlr();
433
434 bool IsMoveableBySolidMask()
435 {
436 return (Status == C4OS_NORMAL) &&
437 !(Category & (C4D_StaticBack | C4D_Structure)) &&
438 !Contained &&
439 ((~Category & C4D_Vehicle) || (OCF & OCF_Grab)) &&
440 (Action.Act <= ActIdle || Def->ActMap[Action.Act].Procedure != DFA_FLOAT);
441 }
442
443 std::string GetNeededMatStr(C4Object *pBuilder);
444
445 // This function is used for:
446 // -Objects to be removed when a player is removed
447 // -Objects that are not to be saved in "SaveScenario"-mode
448 bool IsPlayerObject(int32_t iPlayerNumber = NO_OWNER); // true for any object that belongs to any player (NO_OWNER) or a specified player
449
450 // This function is used for:
451 // -Objects that are not to be saved in "SaveScenario"-mode
452 bool IsUserPlayerObject(); // true for any object that belongs to any player (NO_OWNER) or a specified player
453};
454