1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 
4 #include <set>
5 #include <string>
6 #include <vector>
7 #include <set>
8 #include <map>
9 #include <cctype>
10 
11 #include "LuaWeaponDefs.h"
12 
13 #include "LuaInclude.h"
14 
15 #include "LuaDefs.h"
16 #include "LuaHandle.h"
17 #include "LuaUtils.h"
18 #include "Game/TraceRay.h"
19 #include "Rendering/Models/IModelParser.h"
20 #include "Sim/Misc/CategoryHandler.h"
21 #include "Sim/Misc/DamageArrayHandler.h"
22 #include "Sim/Projectiles/Projectile.h"
23 #include "Sim/Weapons/Weapon.h"
24 #include "Sim/Weapons/WeaponDefHandler.h"
25 #include "System/FileSystem/SimpleParser.h"
26 #include "System/Log/ILog.h"
27 #include "System/Util.h"
28 #include "Sim/Misc/GlobalSynced.h"
29 
30 
31 static ParamMap paramMap;
32 
33 static bool InitParamMap();
34 
35 // iteration routines
36 static int Next(lua_State* L);
37 static int Pairs(lua_State* L);
38 
39 // meta-table calls
40 static int WeaponDefIndex(lua_State* L);
41 static int WeaponDefNewIndex(lua_State* L);
42 static int WeaponDefMetatable(lua_State* L);
43 
44 // special access functions
45 static int NoFeatureCollide(lua_State* L, const void* data);
46 static int NoFriendlyCollide(lua_State* L, const void* data);
47 static int NoNeutralCollide(lua_State* L, const void* data);
48 
49 static int VisualsTable(lua_State* L, const void* data);
50 static int DamagesArray(lua_State* L, const void* data);
51 static int CustomParamsTable(lua_State* L, const void* data);
52 static int GuiSoundSetTable(lua_State* L, const void* data);
53 //static int CategorySetFromBits(lua_State* L, const void* data);
54 
55 
56 /******************************************************************************/
57 /******************************************************************************/
58 
PushEntries(lua_State * L)59 bool LuaWeaponDefs::PushEntries(lua_State* L)
60 {
61 	if (paramMap.empty()) {
62 	  InitParamMap();
63 	}
64 
65 	const map<string, int>& weaponMap = weaponDefHandler->weaponID;
66 	map<string, int>::const_iterator wit;
67 	for (wit = weaponMap.begin(); wit != weaponMap.end(); ++wit) {
68 		const WeaponDef* wd = &weaponDefHandler->weaponDefs[wit->second];
69 		if (wd == NULL) {
70 	  	continue;
71 		}
72 		lua_pushnumber(L, wd->id);
73 		lua_newtable(L); { // the proxy table
74 
75 			lua_newtable(L); { // the metatable
76 
77 				HSTR_PUSH(L, "__index");
78 				lua_pushlightuserdata(L, (void*)wd);
79 				lua_pushcclosure(L, WeaponDefIndex, 1);
80 				lua_rawset(L, -3); // closure
81 
82 				HSTR_PUSH(L, "__newindex");
83 				lua_pushlightuserdata(L, (void*)wd);
84 				lua_pushcclosure(L, WeaponDefNewIndex, 1);
85 				lua_rawset(L, -3);
86 
87 				HSTR_PUSH(L, "__metatable");
88 				lua_pushlightuserdata(L, (void*)wd);
89 				lua_pushcclosure(L, WeaponDefMetatable, 1);
90 				lua_rawset(L, -3);
91 			}
92 
93 			lua_setmetatable(L, -2);
94 		}
95 
96 		HSTR_PUSH(L, "pairs");
97 		lua_pushcfunction(L, Pairs);
98 		lua_rawset(L, -3);
99 
100 		HSTR_PUSH(L, "next");
101 		lua_pushcfunction(L, Next);
102 		lua_rawset(L, -3);
103 
104 		lua_rawset(L, -3); // proxy table into WeaponDefs
105 	}
106 
107 	return true;
108 }
109 
110 
111 /******************************************************************************/
112 
WeaponDefIndex(lua_State * L)113 static int WeaponDefIndex(lua_State* L)
114 {
115 	// not a default value
116 	if (!lua_isstring(L, 2)) {
117 		lua_rawget(L, 1);
118 		return 1;
119 	}
120 
121 	const char* name = lua_tostring(L, 2);
122 	ParamMap::const_iterator it = paramMap.find(name);
123 
124 	// not a default value
125 	if (it == paramMap.end()) {
126 		lua_rawget(L, 1);
127 		return 1;
128 	}
129 
130 	const void* userData = lua_touserdata(L, lua_upvalueindex(1));
131 	const WeaponDef* wd = static_cast<const WeaponDef*>(userData);
132 	const DataElement& elem = it->second;
133 	const void* p = ((const char*)wd) + elem.offset;
134 	switch (elem.type) {
135 		case READONLY_TYPE: {
136 			lua_rawget(L, 1);
137 			return 1;
138 		}
139 		case INT_TYPE: {
140 			lua_pushnumber(L, *reinterpret_cast<const int*>(p));
141 			return 1;
142 		}
143 		case BOOL_TYPE: {
144 			lua_pushboolean(L, *reinterpret_cast<const bool*>(p));
145 			return 1;
146 		}
147 		case FLOAT_TYPE: {
148 			lua_pushnumber(L, *reinterpret_cast<const float*>(p));
149 			return 1;
150 		}
151 		case STRING_TYPE: {
152 			lua_pushsstring(L, *reinterpret_cast<const std::string*>(p));
153 			return 1;
154 		}
155 		case FUNCTION_TYPE: {
156 			return elem.func(L, p);
157 		}
158 		case ERROR_TYPE: {
159 			LOG_L(L_ERROR, "[%s] ERROR_TYPE for key \"%s\" in WeaponDefs __index", __FUNCTION__, name);
160 			lua_pushnil(L);
161 			return 1;
162 		}
163 	}
164 
165 	return 0;
166 }
167 
168 
WeaponDefNewIndex(lua_State * L)169 static int WeaponDefNewIndex(lua_State* L)
170 {
171 	// not a default value, set it
172 	if (!lua_isstring(L, 2)) {
173 		lua_rawset(L, 1);
174 		return 0;
175 	}
176 
177 	const char* name = lua_tostring(L, 2);
178 	ParamMap::const_iterator it = paramMap.find(name);
179 
180 	// not a default value, set it
181 	if (it == paramMap.end()) {
182 		lua_rawset(L, 1);
183 		return 0;
184 	}
185 
186 	const void* userData = lua_touserdata(L, lua_upvalueindex(1));
187 	const WeaponDef* wd = static_cast<const WeaponDef*>(userData);
188 
189 	// write-protected
190 	if (!gs->editDefsEnabled) {
191 	 	luaL_error(L, "Attempt to write WeaponDefs[%d].%s", wd->id, name);
192 	 	return 0;
193 	}
194 
195 	// Definition editing
196 	const DataElement& elem = it->second;
197 	const void* p = ((const char*)wd) + elem.offset;
198 
199 	switch (elem.type) {
200 		case FUNCTION_TYPE:
201 		case READONLY_TYPE: {
202 			luaL_error(L, "Can not write to %s", name);
203 			return 0;
204 		}
205 		case INT_TYPE: {
206 			*((int*)p) = lua_toint(L, -1);
207 			return 0;
208 		}
209 		case BOOL_TYPE: {
210 			*((bool*)p) = lua_toboolean(L, -1);
211 			return 0;
212 		}
213 		case FLOAT_TYPE: {
214 			*((float*)p) = lua_tofloat(L, -1);
215 			return 0;
216 		}
217 		case STRING_TYPE: {
218 			*((string*)p) = lua_tostring(L, -1);
219 			return 0;
220 		}
221 		case ERROR_TYPE: {
222 			LOG_L(L_ERROR, "[%s] ERROR_TYPE for key \"%s\" in WeaponDefs __newindex", __FUNCTION__, name);
223 			lua_pushnil(L);
224 			return 1;
225 		}
226 	}
227 
228 	return 0;
229 }
230 
231 
WeaponDefMetatable(lua_State * L)232 static int WeaponDefMetatable(lua_State* L)
233 {
234 	//const void* userData = lua_touserdata(L, lua_upvalueindex(1));
235 	//const WeaponDef* wd = (const WeaponDef*)userData;
236 	return 0;
237 }
238 
239 
240 /******************************************************************************/
241 
Next(lua_State * L)242 static int Next(lua_State* L)
243 {
244 	return LuaUtils::Next(paramMap, L);
245 }
246 
247 
Pairs(lua_State * L)248 static int Pairs(lua_State* L)
249 {
250 	luaL_checktype(L, 1, LUA_TTABLE);
251 	lua_pushcfunction(L, Next);	// iterator
252 	lua_pushvalue(L, 1);        // state (table)
253 	lua_pushnil(L);             // initial value
254 	return 3;
255 }
256 
257 
258 /******************************************************************************/
259 /******************************************************************************/
260 
DamagesArray(lua_State * L,const void * data)261 static int DamagesArray(lua_State* L, const void* data)
262 {
263 	const DamageArray& d = *static_cast<const DamageArray*>(data);
264 	lua_newtable(L);
265 	HSTR_PUSH_NUMBER(L, "impulseFactor",      d.impulseFactor);
266 	HSTR_PUSH_NUMBER(L, "impulseBoost",       d.impulseBoost);
267 	HSTR_PUSH_NUMBER(L, "craterMult",         d.craterMult);
268 	HSTR_PUSH_NUMBER(L, "craterBoost",        d.craterBoost);
269 	HSTR_PUSH_NUMBER(L, "paralyzeDamageTime", d.paralyzeDamageTime);
270 
271 	// damage values
272 	const int typeCount = damageArrayHandler->GetNumTypes();
273 	for (int i = 0; i < typeCount; i++) {
274 		lua_pushnumber(L, i);
275 		lua_pushnumber(L, d[i]);
276 		lua_rawset(L, -3);
277 	}
278 
279 	return 1;
280 }
281 
282 
VisualsTable(lua_State * L,const void * data)283 static int VisualsTable(lua_State* L, const void* data)
284 {
285 	const struct WeaponDef::Visuals& v = *static_cast<const struct WeaponDef::Visuals*>(data);
286 	lua_newtable(L);
287 	HSTR_PUSH_STRING(L, "modelName",      modelParser->FindModelPath(v.modelName));
288 	HSTR_PUSH_NUMBER(L, "colorR",         v.color.x);
289 	HSTR_PUSH_NUMBER(L, "colorG",         v.color.y);
290 	HSTR_PUSH_NUMBER(L, "colorB",         v.color.z);
291 	HSTR_PUSH_NUMBER(L, "color2R",        v.color2.x);
292 	HSTR_PUSH_NUMBER(L, "color2G",        v.color2.y);
293 	HSTR_PUSH_NUMBER(L, "color2B",        v.color2.z);
294 	HSTR_PUSH_BOOL  (L, "smokeTrail",     v.smokeTrail);
295 	HSTR_PUSH_NUMBER(L, "tileLength",     v.tilelength);
296 	HSTR_PUSH_NUMBER(L, "scrollSpeed",    v.scrollspeed);
297 	HSTR_PUSH_NUMBER(L, "pulseSpeed",     v.pulseSpeed);
298 	HSTR_PUSH_NUMBER(L, "laserFlareSize", v.laserflaresize);
299 	HSTR_PUSH_NUMBER(L, "thickness",      v.thickness);
300 	HSTR_PUSH_NUMBER(L, "coreThickness",  v.corethickness);
301 	HSTR_PUSH_NUMBER(L, "beamDecay",      v.beamdecay);
302 	HSTR_PUSH_NUMBER(L, "stages",         v.stages);
303 	HSTR_PUSH_NUMBER(L, "sizeDecay",      v.sizeDecay);
304 	HSTR_PUSH_NUMBER(L, "alphaDecay",     v.alphaDecay);
305 	HSTR_PUSH_NUMBER(L, "separation",     v.separation);
306 	HSTR_PUSH_BOOL  (L, "noGap",          v.noGap);
307 	HSTR_PUSH_BOOL  (L, "alwaysVisible",  v.alwaysVisible);
308 	HSTR_PUSH_BOOL  (L, "beamWeapon",     false); // DEPRECATED
309 
310 	return 1;
311 //	CColorMap *colorMap;
312 //	AtlasedTexture *texture1;
313 //	AtlasedTexture *texture2;
314 //	AtlasedTexture *texture3;
315 //	AtlasedTexture *texture4;
316 }
317 
318 
319 
NoEnemyCollide(lua_State * L,const void * data)320 static int NoEnemyCollide(lua_State* L, const void* data)
321 {
322 	const int bits = *((const int*) data);
323 	lua_pushboolean(L, (bits & Collision::NOENEMIES));
324 	return 1;
325 }
326 
NoFriendlyCollide(lua_State * L,const void * data)327 static int NoFriendlyCollide(lua_State* L, const void* data)
328 {
329 	const int bits = *((const int*) data);
330 	lua_pushboolean(L, (bits & Collision::NOFRIENDLIES));
331 	return 1;
332 }
333 
NoFeatureCollide(lua_State * L,const void * data)334 static int NoFeatureCollide(lua_State* L, const void* data)
335 {
336 	const int bits = *((const int*) data);
337 	lua_pushboolean(L, (bits & Collision::NOFEATURES));
338 	return 1;
339 }
340 
NoNeutralCollide(lua_State * L,const void * data)341 static int NoNeutralCollide(lua_State* L, const void* data)
342 {
343 	const int bits = *((const int*) data);
344 	lua_pushboolean(L, (bits & Collision::NONEUTRALS));
345 	return 1;
346 }
347 
NoGroundCollide(lua_State * L,const void * data)348 static int NoGroundCollide(lua_State* L, const void* data)
349 {
350 	const int bits = *((const int*) data);
351 	lua_pushboolean(L, (bits & Collision::NOGROUND));
352 	return 1;
353 }
354 
355 
356 
BuildCategorySet(lua_State * L,const vector<string> & cats)357 static inline int BuildCategorySet(lua_State* L, const vector<string>& cats)
358 {
359 	lua_newtable(L);
360 	const int count = (int)cats.size();
361 	for (int i = 0; i < count; i++) {
362 		lua_pushsstring(L, cats[i]);
363 		lua_pushboolean(L, true);
364 		lua_rawset(L, -3);
365 	}
366 	return 1;
367 }
368 
369 
370 /*
371 static int CategorySetFromBits(lua_State* L, const void* data)
372 {
373 	const int bits = *((const int*)data);
374 	const vector<string> &cats =
375 		CCategoryHandler::Instance()->GetCategoryNames(bits);
376 	return BuildCategorySet(L, cats);
377 }
378 */
379 
380 /*static int CategorySetFromString(lua_State* L, const void* data)
381 {
382 	const string& str = *((const string*)data);
383 	const string lower = StringToLower(str);
384 	const vector<string> &cats = CSimpleParser::Tokenize(lower, 0);
385 	return BuildCategorySet(L, cats);
386 }*/
387 
388 
CustomParamsTable(lua_State * L,const void * data)389 static int CustomParamsTable(lua_State* L, const void* data)
390 {
391 	const map<string, string>& params = *((const map<string, string>*)data);
392 	lua_newtable(L);
393 	map<string, string>::const_iterator it;
394 	for (it = params.begin(); it != params.end(); ++it) {
395 		lua_pushsstring(L, it->first);
396 		lua_pushsstring(L, it->second);
397 		lua_rawset(L, -3);
398 	}
399 	return 1;
400 }
401 
402 
GuiSoundSetTable(lua_State * L,const void * data)403 static int GuiSoundSetTable(lua_State* L, const void* data)
404 {
405 	const GuiSoundSet& soundSet = *static_cast<const GuiSoundSet*>(data);
406 	const int soundCount = (int)soundSet.sounds.size();
407 	lua_newtable(L);
408 	for (int i = 0; i < soundCount; i++) {
409 		lua_pushnumber(L, i + 1);
410 		lua_newtable(L);
411 		const GuiSoundSet::Data& sound = soundSet.sounds[i];
412 		HSTR_PUSH_STRING(L, "name",   sound.name);
413 		HSTR_PUSH_NUMBER(L, "volume", sound.volume);
414 		if (!CLuaHandle::GetHandleSynced(L)) {
415 			HSTR_PUSH_NUMBER(L, "id", sound.id);
416 		}
417 		lua_rawset(L, -3);
418 	}
419 	return 1;
420 }
421 
422 
423 
424 /******************************************************************************/
425 /******************************************************************************/
426 
InitParamMap()427 static bool InitParamMap()
428 {
429 	paramMap["next"]  = DataElement(READONLY_TYPE);
430 	paramMap["pairs"] = DataElement(READONLY_TYPE);
431 
432 	// dummy WeaponDef for offset generation
433 	const WeaponDef wd;
434 	const char* start = ADDRESS(wd);
435 
436 	ADD_FUNCTION("damages",      wd.damages,   DamagesArray);
437 	ADD_FUNCTION("visuals",      wd.visuals,   VisualsTable);
438 
439 	ADD_FUNCTION("hitSound",     wd.hitSound,  GuiSoundSetTable);
440 	ADD_FUNCTION("fireSound",    wd.fireSound, GuiSoundSetTable);
441 
442 	ADD_FUNCTION("customParams",         wd.customParams,   CustomParamsTable);
443 	ADD_FUNCTION("noEnemyCollide",       wd.collisionFlags, NoEnemyCollide);
444 	ADD_FUNCTION("noFriendlyCollide",    wd.collisionFlags, NoFriendlyCollide);
445 	ADD_FUNCTION("noFeatureCollide",     wd.collisionFlags, NoFeatureCollide);
446 	ADD_FUNCTION("noNeutralCollide",     wd.collisionFlags, NoNeutralCollide);
447 	ADD_FUNCTION("noGroundCollide",      wd.collisionFlags, NoGroundCollide);
448 
449 	ADD_DEPRECATED_LUADEF_KEY("areaOfEffect");
450 	ADD_DEPRECATED_LUADEF_KEY("maxVelocity");
451 	ADD_DEPRECATED_LUADEF_KEY("onlyTargetCategories");
452 	ADD_DEPRECATED_LUADEF_KEY("restTime");
453 
454 	ADD_INT("id", wd.id);
455 
456 	ADD_INT("tdfId", wd.tdfId);
457 
458 	ADD_STRING("name",        wd.name);
459 	ADD_STRING("description", wd.description);
460 
461 	// FIXME: why is this expgen-tag exposed but not the other two?
462 	ADD_STRING("cegTag", wd.visuals.ptrailExpGenTag);
463 
464 	ADD_STRING("type", wd.type);
465 
466 	ADD_FLOAT("range", wd.range);
467 	ADD_FLOAT("heightMod", wd.heightmod);
468 	ADD_FLOAT("accuracy", wd.accuracy);
469 	ADD_FLOAT("sprayAngle", wd.sprayAngle);
470 	ADD_FLOAT("movingAccuracy", wd.movingAccuracy);
471 	ADD_FLOAT("targetMoveError", wd.targetMoveError);
472 	ADD_FLOAT("leadLimit", wd.leadLimit);
473 	ADD_FLOAT("leadBonus", wd.leadBonus);
474 	ADD_FLOAT("predictBoost", wd.predictBoost);
475 	ADD_INT("highTrajectory", wd.highTrajectory);
476 
477 	ADD_BOOL("noSelfDamage",  wd.noSelfDamage);
478 	ADD_BOOL("impactOnly",    wd.impactOnly);
479 
480 	ADD_FLOAT("craterAreaOfEffect", wd.craterAreaOfEffect);
481 	ADD_FLOAT("damageAreaOfEffect", wd.damageAreaOfEffect);
482 	ADD_FLOAT("edgeEffectiveness",  wd.edgeEffectiveness);
483 	ADD_FLOAT("fireStarter",        wd.fireStarter);
484 	ADD_FLOAT("size",               wd.size);
485 	ADD_FLOAT("sizeGrowth",         wd.sizeGrowth);
486 	ADD_FLOAT("collisionSize",      wd.collisionSize);
487 
488 	ADD_INT("salvoSize",    wd.salvosize);
489 	ADD_INT("projectiles",  wd.projectilespershot);
490 	ADD_FLOAT("salvoDelay", wd.salvodelay);
491 	ADD_FLOAT("reload",     wd.reload);
492 	ADD_FLOAT("beamtime",   wd.beamtime);
493 	ADD_BOOL("beamburst",   wd.beamburst);
494 
495 	ADD_BOOL("waterbounce",    wd.waterBounce);
496 	ADD_BOOL("groundbounce",   wd.groundBounce);
497 	ADD_FLOAT("groundslip",    wd.bounceSlip);
498 	ADD_FLOAT("bouncerebound", wd.bounceRebound);
499 	ADD_INT("numbounce",       wd.numBounce);
500 
501 	ADD_FLOAT("maxAngle", wd.maxAngle);
502 
503 	ADD_FLOAT("uptime", wd.uptime);
504 
505 	ADD_FLOAT("metalCost",  wd.metalcost);
506 	ADD_FLOAT("energyCost", wd.energycost);
507 
508 	ADD_BOOL("turret", wd.turret);
509 	ADD_BOOL("onlyForward", wd.onlyForward);
510 	ADD_BOOL("waterWeapon", wd.waterweapon);
511 	ADD_BOOL("tracks", wd.tracks);
512 	ADD_BOOL("paralyzer", wd.paralyzer);
513 
514 	ADD_BOOL("noAutoTarget",   wd.noAutoTarget);
515 	ADD_BOOL("manualFire",     wd.manualfire);
516 	ADD_INT("targetable",      wd.targetable);
517 	ADD_BOOL("stockpile",      wd.stockpile);
518 	ADD_INT("interceptor",     wd.interceptor);
519 	ADD_BOOL("interceptSolo",  wd.interceptSolo);
520 	ADD_FLOAT("coverageRange", wd.coverageRange);
521 
522 	ADD_FLOAT("stockpileTime", wd.stockpileTime);
523 
524 	ADD_FLOAT("intensity", wd.intensity);
525 	ADD_FLOAT("duration", wd.duration);
526 	ADD_INT("beamTTL", wd.beamLaserTTL);
527 
528 	ADD_BOOL("soundTrigger", wd.soundTrigger);
529 
530 	ADD_BOOL("selfExplode", wd.selfExplode);
531 	ADD_BOOL("gravityAffected", wd.gravityAffected);
532 	ADD_FLOAT("myGravity", wd.myGravity);
533 	ADD_BOOL("noExplode", wd.noExplode);
534 	ADD_FLOAT("startvelocity", wd.startvelocity);
535 	ADD_FLOAT("weaponAcceleration", wd.weaponacceleration);
536 	ADD_FLOAT("turnRate", wd.turnrate);
537 
538 	ADD_FLOAT("projectilespeed", wd.projectilespeed);
539 	ADD_FLOAT("explosionSpeed", wd.explosionSpeed);
540 
541 	ADD_FLOAT("wobble", wd.wobble);
542 	ADD_FLOAT("dance",  wd.dance);
543 
544 	ADD_FLOAT("trajectoryHeight", wd.trajectoryHeight);
545 
546 	ADD_BOOL("largeBeamLaser", wd.largeBeamLaser);
547 	ADD_BOOL("laserHardStop", wd.laserHardStop);
548 
549 	ADD_BOOL("isShield",                wd.isShield);
550 	ADD_BOOL("shieldRepulser",          wd.shieldRepulser);
551 	ADD_BOOL("smartShield",             wd.smartShield);
552 	ADD_BOOL("exteriorShield",          wd.exteriorShield);
553 	ADD_BOOL("visibleShield",           wd.visibleShield);
554 	ADD_BOOL("visibleShieldRepulse",    wd.visibleShieldRepulse);
555 	ADD_INT( "visibleShieldHitFrames",  wd.visibleShieldHitFrames);
556 	ADD_FLOAT("shieldEnergyUse",        wd.shieldEnergyUse);
557 	ADD_FLOAT("shieldRadius",           wd.shieldRadius);
558 	ADD_FLOAT("shieldForce",            wd.shieldForce);
559 	ADD_FLOAT("shieldMaxSpeed",         wd.shieldMaxSpeed);
560 	ADD_FLOAT("shieldPower",            wd.shieldPower);
561 	ADD_FLOAT("shieldPowerRegen",       wd.shieldPowerRegen);
562 	ADD_FLOAT("shieldPowerRegenEnergy", wd.shieldPowerRegenEnergy);
563 	ADD_INT(  "shieldRechargeDelay",    wd.shieldRechargeDelay);
564 	ADD_FLOAT("shieldGoodColorR",       wd.shieldGoodColor.x);
565 	ADD_FLOAT("shieldGoodColorG",       wd.shieldGoodColor.y);
566 	ADD_FLOAT("shieldGoodColorB",       wd.shieldGoodColor.z);
567 	ADD_FLOAT("shieldBadColorR",        wd.shieldBadColor.x);
568 	ADD_FLOAT("shieldBadColorG",        wd.shieldBadColor.y);
569 	ADD_FLOAT("shieldBadColorB",        wd.shieldBadColor.z);
570 	ADD_FLOAT("shieldAlpha",            wd.shieldAlpha);
571 
572 	ADD_INT("shieldInterceptType",      wd.shieldInterceptType);
573 	ADD_INT("interceptedByShieldType",  wd.interceptedByShieldType);
574 
575 	ADD_BOOL("avoidFriendly", wd.avoidFriendly);
576 	ADD_BOOL("avoidFeature",  wd.avoidFeature);
577 	ADD_BOOL("avoidNeutral",  wd.avoidNeutral);
578 
579 	ADD_FLOAT("targetBorder",       wd.targetBorder);
580 	ADD_FLOAT("cylinderTargeting", wd.cylinderTargeting);
581 	ADD_FLOAT("cylinderTargetting", wd.cylinderTargeting); // FIXME deprecated misspelling
582 	ADD_FLOAT("minIntensity",       wd.minIntensity);
583 	ADD_FLOAT("heightBoostFactor",  wd.heightBoostFactor);
584 	ADD_FLOAT("proximityPriority",  wd.proximityPriority);
585 
586 	ADD_BOOL("sweepFire", wd.sweepFire);
587 
588 	ADD_BOOL("canAttackGround", wd.canAttackGround);
589 
590 	return true;
591 }
592 
593 
594 /******************************************************************************/
595 /******************************************************************************/
596