File: Unit.h

package info (click to toggle)
spring 105.0.1%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 108,860 kB
  • sloc: cpp: 467,785; ansic: 302,607; python: 12,925; java: 12,201; awk: 5,889; sh: 2,371; xml: 655; perl: 405; php: 276; objc: 194; makefile: 75; sed: 2
file content (551 lines) | stat: -rw-r--r-- 17,590 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */

#ifndef UNIT_H
#define UNIT_H

#include <vector>

#include "Sim/Objects/SolidObject.h"
#include "Sim/Misc/Resource.h"
#include "Sim/Weapons/WeaponTarget.h"
#include "System/Matrix44f.h"
#include "System/type2.h"


class CPlayer;
class CCommandAI;
class CGroup;
class CMissileProjectile;
class AMoveType;
class CWeapon;
class CUnitScript;
class DamageArray;
class DynDamageArray;
struct SolidObjectDef;
struct UnitDef;
struct UnitLoadParams;
struct SLosInstance;


// LOS state bits
#define LOS_INLOS      (1 << 0)  // the unit is currently in the los of the allyteam
#define LOS_INRADAR    (1 << 1)  // the unit is currently in radar from the allyteam
#define LOS_PREVLOS    (1 << 2)  // the unit has previously been in los from the allyteam
#define LOS_CONTRADAR  (1 << 3)  // the unit has continuously been in radar since it was last inlos by the allyteam

#define LOS_MASK_SHIFT 4

// LOS mask bits  (masked bits are not automatically updated)
#define LOS_INLOS_MASK     (LOS_INLOS << LOS_MASK_SHIFT)   // do not update LOS_INLOS
#define LOS_INRADAR_MASK   (LOS_INRADAR << LOS_MASK_SHIFT)   // do not update LOS_INRADAR
#define LOS_PREVLOS_MASK   (LOS_PREVLOS << LOS_MASK_SHIFT)  // do not update LOS_PREVLOS
#define LOS_CONTRADAR_MASK (LOS_CONTRADAR << LOS_MASK_SHIFT)  // do not update LOS_CONTRADAR

#define LOS_ALL_BITS \
	(LOS_INLOS      | LOS_INRADAR      | LOS_PREVLOS      | LOS_CONTRADAR)
#define LOS_ALL_MASK_BITS \
	(LOS_INLOS_MASK | LOS_INRADAR_MASK | LOS_PREVLOS_MASK | LOS_CONTRADAR_MASK)


class CUnit : public CSolidObject
{
public:
	CR_DECLARE_DERIVED(CUnit)

	CUnit();
	virtual ~CUnit();

	static void InitStatic();

	void SanityCheck() const;
	void PreUpdate() { preFramePos = pos; }

	virtual void PreInit(const UnitLoadParams& params);
	virtual void PostInit(const CUnit* builder);

	virtual void Update();
	virtual void SlowUpdate();

	const SolidObjectDef* GetDef() const override { return ((const SolidObjectDef*) unitDef); }

	virtual void DoDamage(const DamageArray& damages, const float3& impulse, CUnit* attacker, int weaponDefID, int projectileID) override;
	virtual void DoWaterDamage();
	virtual void FinishedBuilding(bool postInit);

	void ApplyDamage(CUnit* attacker, const DamageArray& damages, float& baseDamage, float& experienceMod);
	void ApplyImpulse(const float3& impulse) override;

	bool AttackUnit(CUnit* unit, bool isUserTarget, bool wantManualFire, bool fpsMode = false);
	bool AttackGround(const float3& pos, bool isUserTarget, bool wantManualFire, bool fpsMode = false);
	void DropCurrentAttackTarget();

	int GetBlockingMapID() const override { return id; }

	void ChangeLos(int losRad, int airRad);
	// negative amount=reclaim, return= true -> build power was successfully applied
	bool AddBuildPower(CUnit* builder, float amount) override;

	void Activate();
	void Deactivate();

	void ForcedMove(const float3& newPos) override;

	void DeleteScript();
	void EnableScriptMoveType();
	void DisableScriptMoveType();

	CMatrix44f GetTransformMatrix(bool synced = false, bool fullread = false) const final override;

	void DependentDied(CObject* o) override;

	bool AllowedReclaim(CUnit* builder) const;

	void SetMetalStorage(float newStorage);
	void SetEnergyStorage(float newStorage);

	bool UseMetal(float metal);
	void AddMetal(float metal, bool useIncomeMultiplier = true);
	bool UseEnergy(float energy);
	void AddEnergy(float energy, bool useIncomeMultiplier = true);
	bool AddHarvestedMetal(float metal);

	void SetStorage(const SResourcePack& newstorage);
	bool HaveResources(const SResourcePack& res) const;
	bool UseResources(const SResourcePack& res);
	void AddResources(const SResourcePack& res, bool useIncomeMultiplier = true);
	bool IssueResourceOrder(SResourceOrder* order);

	// push the new wind to the script
	void UpdateWind(float x, float z, float strength);

	void UpdateTransportees();
	void ReleaseTransportees(CUnit* attacker, bool selfDestruct, bool reclaimed);
	void TransporteeKilled(const CObject* o);

	void AddExperience(float exp);

	void SetMass(float newMass) override;

	void DoSeismicPing(float pingSize);

	void CalculateTerrainType();
	void UpdateTerrainType();
	void UpdatePhysicalState(float eps) override;

	float3 GetErrorVector(int allyteam) const;
	float3 GetErrorPos(int allyteam, bool aiming = false) const { return (aiming? aimPos: midPos) + GetErrorVector(allyteam); }
	float3 GetObjDrawErrorPos(int allyteam) const { return (GetObjDrawMidPos() + GetErrorVector(allyteam)); }

	float3 GetLuaErrorVector(int allyteam, bool fullRead) const { return (fullRead? ZeroVector: GetErrorVector(allyteam)); }
	float3 GetLuaErrorPos(int allyteam, bool fullRead) const { return (midPos + GetLuaErrorVector(allyteam, fullRead)); }

	float3 GetDrawDeltaPos(float dt) const { return ((pos - preFramePos) * dt); }

	void UpdatePosErrorParams(bool updateError, bool updateDelta);

	bool UsingScriptMoveType() const { return (prevMoveType != nullptr); }
	bool UnderFirstPersonControl() const { return (fpsControlPlayer != nullptr); }

	bool FloatOnWater() const;

	bool IsNeutral() const { return neutral; }
	bool IsCloaked() const { return isCloaked; }
	bool IsStunned() const { return stunned; }
	bool IsIdle() const;

	bool HaveTarget() const { return (curTarget.type != Target_None); }
	bool CanUpdateWeapons() const {
		return (forceUseWeapons || (allowUseWeapons && !onTempHoldFire && !isDead && !beingBuilt && !IsStunned()));
	}

	void SetNeutral(bool b);
	void SetStunned(bool stun);

	bool GetPosErrorBit(int at) const {
		return (posErrorMask[at / 32] & (1 << (at % 32)));
	}
	void SetPosErrorBit(int at, int bit) {
		posErrorMask[at / 32] |=  ((1 << (at % 32)) * (bit == 1));
		posErrorMask[at / 32] &= ~((1 << (at % 32)) * (bit == 0));
	}

	bool IsInLosForAllyTeam(int allyTeam) const { return ((losStatus[allyTeam] & LOS_INLOS) != 0); }

	void SetLosStatus(int allyTeam, unsigned short newStatus);
	void UpdateLosStatus(int allyTeam);
	unsigned short CalcLosStatus(int allyTeam) const;

	void UpdateWeapons();

	void SlowUpdateWeapons();
	void SlowUpdateKamikaze(bool scanForTargets);
	void SlowUpdateCloak(bool stunCheck);

	bool ScriptCloak();
	bool ScriptDecloak(const CSolidObject* object, const CWeapon* weapon);
	bool GetNewCloakState(bool checkStun);

	enum ChangeType {
		ChangeGiven,
		ChangeCaptured
	};
	virtual bool ChangeTeam(int team, ChangeType type);
	virtual void StopAttackingAllyTeam(int ally);

	//Transporter stuff
	CR_DECLARE_SUB(TransportedUnit)

	struct TransportedUnit {
		CR_DECLARE_STRUCT(TransportedUnit)
		CUnit* unit;
		int piece;
	};

	bool SetSoloBuilder(CUnit* builder, const UnitDef* buildeeDef);
	void SetLastAttacker(CUnit* attacker);

	void SetTransporter(CUnit* trans) { transporter = trans; }
	CUnit* GetTransporter() const { return transporter; }

	bool AttachUnit(CUnit* unit, int piece, bool force = false);
	bool CanTransport(const CUnit* unit) const;

	bool DetachUnit(CUnit* unit);
	bool DetachUnitCore(CUnit* unit);
	bool DetachUnitFromAir(CUnit* unit, const float3& pos); // orders <unit> to move to <pos> after detach

	bool CanLoadUnloadAtPos(const float3& wantedPos, const CUnit* unit, float* wantedHeightPtr = nullptr) const;
	float GetTransporteeWantedHeight(const float3& wantedPos, const CUnit* unit, bool* ok = nullptr) const;
	short GetTransporteeWantedHeading(const CUnit* unit) const;

public:
	void KilledScriptFinished(int wreckLevel) { deathScriptFinished = true; delayedWreckLevel = wreckLevel; }
	void ForcedKillUnit(CUnit* attacker, bool selfDestruct, bool reclaimed, bool showDeathSequence = true);
	virtual void KillUnit(CUnit* attacker, bool selfDestruct, bool reclaimed, bool showDeathSequence = true);
	virtual void IncomingMissile(CMissileProjectile* missile);

	void TempHoldFire(int cmdID);
	void SetHoldFire(bool b) { onTempHoldFire = b; }

	// start this unit in free fall from parent unit
	void Drop(const float3& parentPos, const float3& parentDir, CUnit* parent);
	void PostLoad();

protected:
	void ChangeTeamReset();
	void UpdateResources();
	float GetFlankingDamageBonus(const float3& attackDir);

public: // unsynced methods
	bool SetGroup(CGroup* newGroup, bool fromFactory = false, bool autoSelect = true);

	const CGroup* GetGroup() const;
	      CGroup* GetGroup();

public:
	static void  SetEmpDeclineRate(float value) { empDeclineRate = value; }
	static void  SetExpMultiplier(float value) { expMultiplier = value; }
	static void  SetExpPowerScale(float value) { expPowerScale = value; }
	static void  SetExpHealthScale(float value) { expHealthScale = value; }
	static void  SetExpReloadScale(float value) { expReloadScale = value; }
	static void  SetExpGrade(float value) { expGrade = value; }

	static float GetExpMultiplier() { return expMultiplier; }
	static float GetExpPowerScale() { return expPowerScale; }
	static float GetExpHealthScale() { return expHealthScale; }
	static float GetExpReloadScale() { return expReloadScale; }
	static float GetExpGrade() { return expGrade; }

	static float ExperienceScale(const float limExperience, const float experienceWeight) {
		// limExperience ranges from 0.0 to 0.9999..., experienceWeight
		// should be in [0, 1] and have no effect on accuracy when zero
		return (1.0f - (limExperience * experienceWeight));
	}

public:
	const UnitDef* unitDef = nullptr;

	// Our shield weapon, NULL if we have none
	CWeapon* shieldWeapon = nullptr;
	// Our weapon with stockpiled ammo, NULL if we have none
	CWeapon* stockpileWeapon = nullptr;

	const DynDamageArray* selfdExpDamages = nullptr;
	const DynDamageArray* deathExpDamages = nullptr;

	CUnit* soloBuilder = nullptr;
	CUnit* lastAttacker = nullptr;
	// transport that the unit is currently in
	CUnit* transporter = nullptr;

	// player who is currently FPS'ing this unit
	CPlayer* fpsControlPlayer = nullptr;

	AMoveType* moveType = nullptr;
	AMoveType* prevMoveType = nullptr;

	CCommandAI* commandAI = nullptr;
	CUnitScript* script = nullptr;

	// current attackee
	SWeaponTarget curTarget;


	// sufficient for the largest UnitScript (CLuaUnitScript)
	uint8_t usMemBuffer[368];
	// sufficient for the largest AMoveType (CGroundMoveType)
	// need two buffers since ScriptMoveType might be enabled
	uint8_t amtMemBuffer[498];
	uint8_t smtMemBuffer[370];
	// sufficient for the largest CommandAI type (CBuilderCAI)
	// knowing the exact CAI object size here is not required;
	// static asserts will catch any overflow
	uint8_t caiMemBuffer[700];


	std::vector<CWeapon*> weapons;

	// which squares the unit can currently observe, per los-type
	std::array<SLosInstance*, /*ILosType::LOS_TYPE_COUNT*/ 7> los{{nullptr}};

	// indicates the los/radar status each allyteam has on this unit
	// should technically be MAX_ALLYTEAMS, but #allyteams <= #teams
	std::array<unsigned char, /*MAX_TEAMS*/ 255> losStatus{{0}};
	// bit-mask indicating which allyteams see this unit with positional error
	std::array<unsigned  int, /*MAX_TEAMS/32*/ 8> posErrorMask{{1}};

	// quads the unit is part of
	std::vector<int> quads;

	std::vector<TransportedUnit> transportedUnits;
	// incoming projectiles for which flares can cause retargeting
	std::array<CMissileProjectile*, /*MAX_INCOMING_MISSILES*/ 8> incomingMissiles{{nullptr}};


	// position at start of current simframe; updated by ForcedMove
	// used as interpolation reference for drawpos since a unit can
	// move along vectors other than its velocity
	float3 preFramePos;

	float3 lastMuzzleFlameDir = UpVector;
	// units take less damage when attacked from this dir (encourage flanking fire)
	float3 flankingBonusDir = RgtVector;

	// used for radar inaccuracy etc
	float3 posErrorVector;
	float3 posErrorDelta;


	int featureDefID = -1; // FeatureDef id of the wreck we spawn on death

	// indicate the relative power of the unit, used for experience calulations etc
	float power = 100.0f;

	// 0.0-1.0
	float buildProgress = 0.0f;
	// if (health - this) is negative the unit is stunned
	float paralyzeDamage = 0.0f;
	// how close this unit is to being captured
	float captureProgress = 0.0f;
	float experience = 0.0f;
	// approaches 1 as experience approaches infinity
	float limExperience = 0.0f;


	// how much terraforming is left to do
	float terraformLeft = 0.0f;
	// How much reapir power has been added to this recently
	float repairAmount = 0.0f;

	// last frame unit was attacked by other unit
	int lastAttackFrame = -200;
	// last time this unit fired a weapon
	int lastFireWeapon = 0;

	// if we arent built on for a while start decaying
	int lastNanoAdd = 0;
	int lastFlareDrop = 0;

	// id of transport that the unit is about to be {un}loaded by
	int loadingTransportId = -1;
	int unloadingTransportId = -1;

	int transportCapacityUsed = 0;
	float transportMassUsed = 0.0f;


	// the wreck level the unit will eventually create when it has died
	int delayedWreckLevel = -1;

	// how long the unit has been inactive
	unsigned int restTime = 0;
	unsigned int outOfMapTime = 0;

	float reloadSpeed = 1.0f;
	float maxRange = 0.0f;

	// used to determine muzzle flare size
	float lastMuzzleFlameSize = 0.0f;

	int armorType = 0;
	// what categories the unit is part of (bitfield)
	unsigned int category = 0;

	int mapSquare = -1;

	// set los to this when finished building
	int realLosRadius = 0;
	int realAirLosRadius = 0;

	int losRadius = 0;
	int airLosRadius = 0;

	int radarRadius = 0;
	int sonarRadius = 0;
	int jammerRadius = 0;
	int sonarJamRadius = 0;
	int seismicRadius = 0;

	float seismicSignature = 0.0f;
	float decloakDistance = 0.0f;


	// only when the unit is active
	SResourcePack resourcesCondUse;
	SResourcePack resourcesCondMake;

	// always applied
	SResourcePack resourcesUncondUse;
	SResourcePack resourcesUncondMake;

	// costs per UNIT_SLOWUPDATE_RATE frames
	SResourcePack resourcesUse;

	// incomes per UNIT_SLOWUPDATE_RATE frames
	SResourcePack resourcesMake;

	// variables used for calculating unit resource usage
	SResourcePack resourcesUseI;
	SResourcePack resourcesMakeI;
	SResourcePack resourcesUseOld;
	SResourcePack resourcesMakeOld;

	// the amount of storage the unit contributes to the team
	SResourcePack storage;

	// per unit metal storage (gets filled on reclaim and needs then to be unloaded at some storage building -> 2nd part is lua's job)
	SResourcePack harvestStorage;
	SResourcePack harvested;

	SResourcePack cost = {100.0f, 0.0f};

	// how much metal the unit currently extracts from the ground
	float metalExtract = 0.0f;

	float buildTime = 100.0f;

	// decaying value of how much damage the unit has taken recently (for severity of death)
	float recentDamage = 0.0f;

	int fireState = 0;
	int moveState = 0;

	// for units being dropped from transports (parachute drops)
	float fallSpeed = 0.2f;

	/**
	 * 0 = no flanking bonus
	 * 1 = global coords, mobile
	 * 2 = unit coords, mobile
	 * 3 = unit coords, locked
	 */
	int flankingBonusMode = 0;

	// how much the lowest damage direction of the flanking bonus can turn upon an attack (zeroed when attacked, slowly increases)
	float  flankingBonusMobility = 10.0f;
	// how much ability of the flanking bonus direction to move builds up each frame
	float  flankingBonusMobilityAdd = 0.01f;
	// average factor to multiply damage by
	float  flankingBonusAvgDamage = 1.4f;
	// (max damage - min damage) / 2
	float  flankingBonusDifDamage = 0.5f;

	float armoredMultiple = 1.0f;
	// multiply all damage the unit take with this
	float curArmorMultiple = 1.0f;

	int nextPosErrorUpdate = 1;

	int lastTerrainType = -1;
	// Used for calling setSFXoccupy which TA scripts want
	int curTerrainType = 0;

	int selfDCountdown = 0;

	// the damage value passed to CEGs spawned by this unit's script
	int cegDamage = 0;


	// if the unit is in it's 'on'-state
	bool activated = false;
	// prevent damage from hitting an already dead unit (causing multi wreck etc)
	bool isDead = false;

	bool armoredState = false;

	bool stealth = false;
	bool sonarStealth = false;

	// used by constructing units
	bool inBuildStance = false;
	// tells weapons that support it to try to use a high trajectory
	bool useHighTrajectory = false;
	// used by landed gunships to block weapon Update()'s, also by builders to
	// prevent weapon SlowUpdate()'s and Attack{Unit,Ground}()'s during certain
	// commands
	bool onTempHoldFire = false;

	// Lua overrides for CanUpdateWeapons
	bool forceUseWeapons = false;
	bool allowUseWeapons =  true;

	// signals if script has finished executing Killed and the unit can be deleted
	bool deathScriptFinished = false;

	// if true, unit will not be automatically fired upon unless attacker's fireState is set to > FIREATWILL
	bool neutral = false;
	// if unit is currently incompletely constructed (implies buildProgress < 1)
	bool beingBuilt = true;
	// if the updir is straight up or align to the ground vector
	bool upright = true;
	// whether the ground below this unit has been terraformed
	bool groundLevelled = true;

	// true if the unit is currently cloaked (has enough energy etc)
	bool isCloaked = false;
	// true if the unit currently wants to be cloaked
	bool wantCloak = false;


	// unsynced vars
	bool noMinimap = false;
	bool leaveTracks = false;

	bool isSelected = false;
	bool isIcon = false;

	float iconRadius = 0.0f;

private:
	// if we are stunned by a weapon or for other reason, access via IsStunned/SetStunned(bool)
	bool stunned = false;

	static float empDeclineRate;
	static float expMultiplier;
	static float expPowerScale;
	static float expHealthScale;
	static float expReloadScale;
	static float expGrade;
};

#endif // UNIT_H