1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #ifndef EXPLOSION_GENERATOR_H
4 #define EXPLOSION_GENERATOR_H
5 
6 #include <map>
7 #include <string>
8 #include <vector>
9 #include <boost/shared_ptr.hpp>
10 
11 #include "Sim/Objects/WorldObject.h"
12 
13 #define CEG_PREFIX_STRING "custom:"
14 
15 class LuaParser;
16 class LuaTable;
17 class float3;
18 class CUnit;
19 class IExplosionGenerator;
20 
21 
22 class CExpGenSpawnable: public CWorldObject
23 {
24 	CR_DECLARE(CExpGenSpawnable)
25 public:
26 	CExpGenSpawnable();
27 	CExpGenSpawnable(const float3& pos, const float3& spd);
28 
~CExpGenSpawnable()29 	virtual ~CExpGenSpawnable() {}
30 	virtual void Init(const CUnit* owner, const float3& offset) = 0;
31 };
32 
33 
34 
35 // Finds C++ classes with class aliases
36 class ClassAliasList
37 {
38 public:
39 	void Load(const LuaTable&);
Clear()40 	void Clear() { aliases.clear(); }
41 
42 	creg::Class* GetClass(const std::string& name) const;
43 	std::string FindAlias(const std::string& className) const;
44 
45 private:
46 	std::map<std::string, std::string> aliases;
47 };
48 
49 
50 
51 // loads and stores a list of explosion generators
52 class CExplosionGeneratorHandler
53 {
54 public:
55 	enum {
56 		EXPGEN_ID_INVALID  = -1u,
57 		EXPGEN_ID_STANDARD =  0u,
58 	};
59 
60 	CExplosionGeneratorHandler();
61 	~CExplosionGeneratorHandler();
62 
63 	void ParseExplosionTables();
64 	void ReloadGenerators(const std::string&);
65 
66 	unsigned int LoadGeneratorID(const std::string& tag);
67 	IExplosionGenerator* LoadGenerator(const std::string& tag);
68 	IExplosionGenerator* GetGenerator(unsigned int expGenID);
69 
70 	bool GenExplosion(
71 		unsigned int expGenID,
72 		const float3& pos,
73 		const float3& dir,
74 		float damage,
75 		float radius,
76 		float gfxMod,
77 		CUnit* owner,
78 		CUnit* hit
79 	);
80 
GetExplosionTableRoot()81 	const LuaTable* GetExplosionTableRoot() const { return explTblRoot; }
GetProjectileClasses()82 	const ClassAliasList& GetProjectileClasses() const { return projectileClasses; }
GetGeneratorClasses()83 	const ClassAliasList& GetGeneratorClasses() const { return generatorClasses; }
84 
85 protected:
86 	ClassAliasList projectileClasses;
87 	ClassAliasList generatorClasses;
88 
89 	LuaParser* exploParser;
90 	LuaParser* aliasParser;
91 	LuaTable*  explTblRoot;
92 
93 	std::vector<IExplosionGenerator*> explosionGenerators;
94 
95 	std::map<std::string, unsigned int> expGenTagIdentMap;
96 	std::map<unsigned int, std::string> expGenIdentTagMap;
97 
98 	typedef std::map<std::string, unsigned int>::const_iterator TagIdentMapConstIt;
99 	typedef std::map<unsigned int, std::string>::const_iterator IdentTagMapConstIt;
100 };
101 
102 
103 
104 
105 // Base explosion generator class
106 class IExplosionGenerator
107 {
108 	CR_DECLARE(IExplosionGenerator)
109 
IExplosionGenerator()110 	IExplosionGenerator(): generatorID(CExplosionGeneratorHandler::EXPGEN_ID_INVALID) {}
~IExplosionGenerator()111 	virtual ~IExplosionGenerator() {}
112 
113 	virtual bool Load(CExplosionGeneratorHandler* handler, const std::string& tag) = 0;
Reload(CExplosionGeneratorHandler * handler,const std::string & tag)114 	virtual bool Reload(CExplosionGeneratorHandler* handler, const std::string& tag) { return true; }
115 	virtual bool Explosion(
116 		const float3& pos,
117 		const float3& dir,
118 		float damage,
119 		float radius,
120 		float gfxMod,
121 		CUnit* owner,
122 		CUnit* hit
123 	) = 0;
124 
GetGeneratorID()125 	unsigned int GetGeneratorID() const { return generatorID; }
SetGeneratorID(unsigned int id)126 	void SetGeneratorID(unsigned int id) { generatorID = id; }
127 
128 protected:
129 	unsigned int generatorID;
130 };
131 
132 
133 // spawns non-scriptable explosion effects via hardcoded rules
134 // has no internal state so we never need to allocate instances
135 class CStdExplosionGenerator: public IExplosionGenerator
136 {
CR_DECLARE(CStdExplosionGenerator)137 	CR_DECLARE(CStdExplosionGenerator)
138 
139 public:
140 	CStdExplosionGenerator(): IExplosionGenerator() {}
141 
Load(CExplosionGeneratorHandler * handler,const std::string & tag)142 	bool Load(CExplosionGeneratorHandler* handler, const std::string& tag) { return false; }
143 	bool Explosion(
144 		const float3& pos,
145 		const float3& dir,
146 		float damage,
147 		float radius,
148 		float gfxMod,
149 		CUnit* owner,
150 		CUnit* hit
151 	);
152 };
153 
154 
155 // Uses explosion info from a script file; defines the
156 // result of an explosion as a series of new projectiles
157 class CCustomExplosionGenerator: public IExplosionGenerator
158 {
159 	CR_DECLARE(CCustomExplosionGenerator)
160 	CR_DECLARE_SUB(ProjectileSpawnInfo)
161 	CR_DECLARE_SUB(GroundFlashInfo)
162 	CR_DECLARE_SUB(ExpGenParams)
163 
164 protected:
165 	struct ProjectileSpawnInfo {
166 		CR_DECLARE_STRUCT(ProjectileSpawnInfo)
167 
ProjectileSpawnInfoProjectileSpawnInfo168 		ProjectileSpawnInfo()
169 			: projectileClass(NULL)
170 			, count(0)
171 			, flags(0)
172 		{}
ProjectileSpawnInfoProjectileSpawnInfo173 		ProjectileSpawnInfo(const ProjectileSpawnInfo& psi)
174 			: projectileClass(psi.projectileClass)
175 			, code(psi.code)
176 			, count(psi.count)
177 			, flags(psi.flags)
178 		{}
179 
180 		creg::Class* projectileClass;
181 
182 		/// parsed explosion script code
183 		std::vector<char> code;
184 
185 		/// number of projectiles spawned of this type
186 		unsigned int count;
187 		unsigned int flags;
188 	};
189 
190 	// TODO: Handle ground flashes with more flexibility like the projectiles
191 	struct GroundFlashInfo {
192 		CR_DECLARE_STRUCT(GroundFlashInfo)
193 
GroundFlashInfoGroundFlashInfo194 		GroundFlashInfo()
195 			: flashSize(0.0f)
196 			, flashAlpha(0.0f)
197 			, circleGrowth(0.0f)
198 			, circleAlpha(0.0f)
199 			, ttl(0)
200 			, flags(0)
201 			, color(ZeroVector)
202 		{}
203 
204 		float flashSize;
205 		float flashAlpha;
206 		float circleGrowth;
207 		float circleAlpha;
208 		int ttl;
209 		unsigned int flags;
210 		float3 color;
211 	};
212 
213 	struct ExpGenParams {
214 		CR_DECLARE_STRUCT(ExpGenParams)
215 
216 		std::vector<ProjectileSpawnInfo> projectiles;
217 
218 		GroundFlashInfo groundFlash;
219 
220 		bool useDefaultExplosions;
221 	};
222 
223 public:
CCustomExplosionGenerator()224 	CCustomExplosionGenerator(): IExplosionGenerator() {}
225 
226 	static bool OutputProjectileClassInfo();
227 	static unsigned int GetFlagsFromTable(const LuaTable& table);
228 	static unsigned int GetFlagsFromHeight(float height, float groundHeight);
229 
230 	/// @throws content_error/runtime_error on errors
231 	bool Load(CExplosionGeneratorHandler* handler, const std::string& tag);
232 	bool Reload(CExplosionGeneratorHandler* handler, const std::string& tag);
233 	bool Explosion(const float3& pos, const float3& dir, float damage, float radius, float gfxMod, CUnit* owner, CUnit* hit);
234 
235 
236 	enum {
237 		SPW_WATER      =  1,
238 		SPW_GROUND     =  2,
239 		SPW_AIR        =  4,
240 		SPW_UNDERWATER =  8,
241 		SPW_UNIT       = 16,  // only execute when the explosion hits a unit
242 		SPW_NO_UNIT    = 32,  // only execute when the explosion doesn't hit a unit (environment)
243 	};
244 
245 	enum {
246 		OP_END      =  0,
247 		OP_STOREI   =  1, // int
248 		OP_STOREF   =  2, // float
249 		OP_STOREC   =  3, // char
250 		OP_ADD      =  4,
251 		OP_RAND     =  5,
252 		OP_DAMAGE   =  6,
253 		OP_INDEX    =  7,
254 		OP_LOADP    =  8, // load a void* into the pointer register
255 		OP_STOREP   =  9, // store the pointer register into a void*
256 		OP_DIR      = 10, // store the float3 direction
257 		OP_SAWTOOTH = 11, // Performs a modulo to create a sawtooth wave
258 		OP_DISCRETE = 12, // Floors the value to a multiple of its parameter
259 		OP_SINE     = 13, // Uses val as the phase of a sine wave
260 		OP_YANK     = 14, // Moves the input value into a buffer, returns zero
261 		OP_MULTIPLY = 15, // Multiplies with buffer value
262 		OP_ADDBUFF  = 16, // Adds buffer value
263 		OP_POW      = 17, // Power with code as exponent
264 		OP_POWBUFF  = 18, // Power with buffer as exponent
265 	};
266 
267 private:
268 	void ParseExplosionCode(ProjectileSpawnInfo* psi, const int offset, const boost::shared_ptr<creg::IType> type, const std::string& script, std::string& code);
269 	void ExecuteExplosionCode(const char* code, float damage, char* instance, int spawnIndex, const float3& dir);
270 
271 protected:
272 	ExpGenParams expGenParams;
273 };
274 
275 
276 extern CExplosionGeneratorHandler* explGenHandler;
277 
278 #endif // EXPLOSION_GENERATOR_H
279