1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 /* heavily based on CobInstance.h */
4 
5 #ifndef UNIT_SCRIPT_H
6 #define UNIT_SCRIPT_H
7 
8 #include <string>
9 #include <vector>
10 #include <list>
11 
12 #include "System/Object.h"
13 #include "Rendering/Models/3DModel.h"
14 
15 
16 class CUnit;
17 class CPlasmaRepulser;
18 
19 
20 class CUnitScript : public CObject
21 {
22 public:
23 	enum AnimType {ANone = -1, ATurn = 0, ASpin = 1, AMove = 2};
24 
25 	struct IAnimListener {
~IAnimListenerIAnimListener26 		virtual ~IAnimListener() {}
27 		virtual void AnimFinished(AnimType type, int piece, int axis) = 0;
28 	};
29 
30 public:
31 	static const int UNIT_VAR_COUNT   = 8;
32 	static const int TEAM_VAR_COUNT   = 64;
33 	static const int ALLY_VAR_COUNT   = 64;
34 	static const int GLOBAL_VAR_COUNT = 4096;
35 
36 	static const int UNIT_VAR_START   = 1024;
37 	static const int TEAM_VAR_START   = 2048;
38 	static const int ALLY_VAR_START   = 3072;
39 	static const int GLOBAL_VAR_START = 4096;
40 
41 	static const int UNIT_VAR_END   = UNIT_VAR_START   + UNIT_VAR_COUNT   - 1;
42 	static const int TEAM_VAR_END   = TEAM_VAR_START   + TEAM_VAR_COUNT   - 1;
43 	static const int ALLY_VAR_END   = ALLY_VAR_START   + ALLY_VAR_COUNT   - 1;
44 	static const int GLOBAL_VAR_END = GLOBAL_VAR_START + GLOBAL_VAR_COUNT - 1;
45 
46 	static void InitVars(int numTeams, int numAllyTeams);
47 
48 public:
GetTeamVars(int team)49 	static const int* GetTeamVars(int team) { return &teamVars[team][0]; }
GetAllyVars(int ally)50 	static const int* GetAllyVars(int ally) { return &allyVars[ally][0]; }
GetGlobalVars()51 	static const int* GetGlobalVars()       { return globalVars; }
52 
GetUnitVars()53 	const int* GetUnitVars() const { return unitVars; }
54 protected:
55 	static std::vector< std::vector<int> > teamVars;
56 	static std::vector< std::vector<int> > allyVars;
57 	static int globalVars[GLOBAL_VAR_COUNT];
58 
59 	int unitVars[UNIT_VAR_COUNT];
60 
61 protected:
62 	CUnit* unit;
63 	bool yardOpen;
64 	bool busy;
65 
66 	struct AnimInfo {
67 		AnimType type;
68 		int axis;
69 		int piece;
70 		float speed;
71 		float dest;     // means final position when turning or moving, final speed when spinning
72 		float accel;    // used for spinning, can be negative
73 		bool done;
74 		std::list<IAnimListener*> listeners;
75 	};
76 
77 	std::list<AnimInfo*> anims[AMove + 1];
78 
79 	bool hasSetSFXOccupy;
80 	bool hasRockUnit;
81 	bool hasStartBuilding;
82 
83 	void UnblockAll(AnimInfo* anim);
84 
85 	bool MoveToward(float& cur, float dest, float speed);
86 	bool TurnToward(float& cur, float dest, float speed);
87 	bool DoSpin(float& cur, float dest, float& speed, float accel, int divisor);
88 
89 	std::list<AnimInfo*>::iterator FindAnim(AnimType anim, int piece, int axis);
90 	void RemoveAnim(AnimType type, const std::list<AnimInfo*>::iterator& animInfoIt);
91 	void AddAnim(AnimType type, int piece, int axis, float speed, float dest, float accel);
92 
93 	virtual void ShowScriptError(const std::string& msg) = 0;
94 
95 public:
96 	// subclass is responsible for populating this with script pieces
97 	const std::vector<LocalModelPiece*>& pieces;
98 
PieceExists(unsigned int scriptPieceNum)99 	bool PieceExists(unsigned int scriptPieceNum) const {
100 		// NOTE: there can be NULL pieces present from the remapping in CobInstance
101 		return ((scriptPieceNum < pieces.size()) && (pieces[scriptPieceNum] != NULL));
102 	}
103 
GetScriptLocalModelPiece(unsigned int scriptPieceNum)104 	LocalModelPiece* GetScriptLocalModelPiece(unsigned int scriptPieceNum) const {
105 		assert(PieceExists(scriptPieceNum));
106 		return pieces[scriptPieceNum];
107 	}
108 
109 	int ScriptToModel(int scriptPieceNum) const;
110 	int ModelToScript(int lmodelPieceNum) const;
111 
112 #define SCRIPT_TO_LOCALPIECE_FUNC(x, y, z, w)                          \
113 	x y(int scriptPieceNum) const {                                    \
114 		if (!PieceExists(scriptPieceNum))                              \
115 			return w;                                                  \
116 		LocalModelPiece* p = GetScriptLocalModelPiece(scriptPieceNum); \
117 		return (p->z());                                               \
118 	}
119 
120 	SCRIPT_TO_LOCALPIECE_FUNC(float3,     GetPiecePos,       GetAbsolutePos,      float3(0.0f,0.0f,0.0f))
SCRIPT_TO_LOCALPIECE_FUNC(CMatrix44f,GetPieceMatrix,GetModelSpaceMatrix,CMatrix44f ())121 	SCRIPT_TO_LOCALPIECE_FUNC(CMatrix44f, GetPieceMatrix,    GetModelSpaceMatrix,           CMatrix44f())
122 	SCRIPT_TO_LOCALPIECE_FUNC(float3,     GetPieceDirection, GetDirection,        float3(1.0f,1.0f,1.0f))
123 
124 	bool GetEmitDirPos(int scriptPieceNum, float3& pos, float3& dir) const {
125 		if (!PieceExists(scriptPieceNum))
126 			return true;
127 
128 		LocalModelPiece* p = GetScriptLocalModelPiece(scriptPieceNum);
129 		return (p->GetEmitDirPos(pos, dir));
130 	}
131 
132 public:
133 	CUnitScript(CUnit* unit, const std::vector<LocalModelPiece*>& pieces);
134 	virtual ~CUnitScript();
135 
IsBusy()136 	bool IsBusy() const { return busy; }
137 
GetUnit()138 	      CUnit* GetUnit()       { return unit; }
GetUnit()139 	const CUnit* GetUnit() const { return unit; }
140 
141 	bool Tick(int deltaTime);
142 	void TickAnims(int deltaTime, AnimType type, std::list< std::list<AnimInfo*>::iterator >& doneAnims);
143 
144 	// animation, used by CCobThread
145 	void Spin(int piece, int axis, float speed, float accel);
146 	void StopSpin(int piece, int axis, float decel);
147 	void Turn(int piece, int axis, float speed, float destination);
148 	void Move(int piece, int axis, float speed, float destination);
149 	void MoveNow(int piece, int axis, float destination);
150 	void TurnNow(int piece, int axis, float destination);
151 
152 	bool AddAnimListener(AnimType type, int piece, int axis, IAnimListener* listener);
153 
154 	// misc, used by CCobThread and callouts for Lua unitscripts
155 	void SetVisibility(int piece, bool visible);
156 	void EmitSfx(int type, int piece);
157 	void AttachUnit(int piece, int unit);
158 	void DropUnit(int unit);
159 	void Explode(int piece, int flags);
160 	void Shatter(int piece, const float3& pos, const float3& speed);
161 	void ShowFlare(int piece);
162 	int GetUnitVal(int val, int p1, int p2, int p3, int p4);
163 	void SetUnitVal(int val, int param);
164 
IsInAnimation(AnimType type,int piece,int axis)165 	bool IsInAnimation(AnimType type, int piece, int axis) {
166 		return (FindAnim(type, piece, axis) != anims[type].end());
167 	}
HaveAnimations()168 	bool HaveAnimations() const {
169 		return (!anims[ATurn].empty() || !anims[ASpin].empty() || !anims[AMove].empty());
170 	}
171 	inline bool HaveListeners() const;
172 
173 	// checks for callin existence
HasSetSFXOccupy()174 	bool HasSetSFXOccupy () const { return hasSetSFXOccupy; }
HasRockUnit()175 	bool HasRockUnit     () const { return hasRockUnit; }
HasStartBuilding()176 	bool HasStartBuilding() const { return hasStartBuilding; }
HasBlockShot(int weaponNum)177 	virtual bool HasBlockShot   (int weaponNum) const { return false; }
HasTargetWeight(int weaponNum)178 	virtual bool HasTargetWeight(int weaponNum) const { return false; }
179 
180 	// callins, called throughout sim
181 	virtual void RawCall(int functionId) = 0;
182 	virtual void Create() = 0;
183 	// Killed must cause unit->deathScriptFinished and unit->delayedWreckLevel to be set!
184 	virtual void Killed() = 0;
185 	virtual void WindChanged(float heading, float speed) = 0;
186 	virtual void ExtractionRateChanged(float speed) = 0;
187 	virtual void RockUnit(const float3& rockDir) = 0;
188 	virtual void HitByWeapon(const float3& hitDir, int weaponDefId, float& inout_damage) = 0;
189 	virtual void SetSFXOccupy(int curTerrainType) = 0;
190 	// doubles as QueryLandingPadCount and QueryLandingPad
191 	// in COB, the first one determines the number of arguments to the second one
192 	// in Lua, we can just count the number of return values
193 	virtual void QueryLandingPads(std::vector<int>& out_pieces) = 0;
194 	virtual void BeginTransport(const CUnit* unit) = 0;
195 	virtual int  QueryTransport(const CUnit* unit) = 0; // returns piece
196 	virtual void TransportPickup(const CUnit* unit) = 0;
197 	virtual void TransportDrop(const CUnit* unit, const float3& pos) = 0;
198 	virtual void StartBuilding(float heading, float pitch) = 0;
199 	virtual int  QueryNanoPiece() = 0; // returns piece
200 	virtual int  QueryBuildInfo() = 0; // returns piece
201 
202 	virtual void Destroy() = 0;
203 	virtual void StartMoving(bool reversing) = 0;
204 	virtual void StopMoving() = 0;
205 	virtual void StartUnload() = 0;
206 	virtual void EndTransport() = 0;
207 	virtual void StartBuilding() = 0;
208 	virtual void StopBuilding() = 0;
209 	virtual void Falling() = 0;
210 	virtual void Landed() = 0;
211 	virtual void Activate() = 0;
212 	virtual void Deactivate() = 0;
213 	virtual void MoveRate(int curRate) = 0;
214 	virtual void FireWeapon(int weaponNum) = 0;
215 	virtual void EndBurst(int weaponNum) = 0;
216 
217 	// weapon callins
218 	virtual int   QueryWeapon(int weaponNum) = 0; // returns piece, former QueryPrimary
219 	virtual void  AimWeapon(int weaponNum, float heading, float pitch) = 0;
220 	virtual void  AimShieldWeapon(CPlasmaRepulser* weapon) = 0;
221 	virtual int   AimFromWeapon(int weaponNum) = 0; // returns piece, former AimFromPrimary
222 	virtual void  Shot(int weaponNum) = 0;
223 	virtual bool  BlockShot(int weaponNum, const CUnit* targetUnit, bool userTarget) = 0; // returns whether shot should be blocked
224 	virtual float TargetWeight(int weaponNum, const CUnit* targetUnit) = 0; // returns target weight
225 };
226 
HaveListeners()227 inline bool CUnitScript::HaveListeners() const {
228 	for (int animType = ATurn; animType <= AMove; animType++) {
229 		for (std::list<AnimInfo *>::const_iterator i = anims[animType].begin(); i != anims[animType].end(); ++i) {
230 			if (!(*i)->listeners.empty()) {
231 				return true;
232 			}
233 		}
234 	}
235 	return false;
236 }
237 
238 #endif // UNIT_SCRIPT_H
239