1 /*
2 LUA_MONSTERS.CPP
3 
4 	Copyright (C) 2008 by Gregory Smith
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 3 of the License, or
9 	(at your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	This license is contained in the file "COPYING",
17 	which is included with this source code; it is available online at
18 	http://www.gnu.org/licenses/gpl.html
19 
20 	Implements the Lua monster classes
21 */
22 
23 #include "lua_map.h"
24 #include "lua_monsters.h"
25 #include "lua_objects.h"
26 #include "lua_player.h"
27 #include "lua_projectiles.h"
28 #include "lua_templates.h"
29 
30 #include "dynamic_limits.h"
31 #include "map.h"
32 #include "monsters.h"
33 #include "player.h"
34 #include "projectiles.h"
35 
36 #include <boost/bind.hpp>
37 
38 #define DONT_REPEAT_DEFINITIONS
39 #include "projectile_definitions.h"
40 
41 #ifdef HAVE_LUA
42 
43 const float AngleConvert = 360/float(FULL_CIRCLE);
44 
45 char Lua_Projectile_Name[] = "projectile";
46 
Lua_Projectile_Delete(lua_State * L)47 int Lua_Projectile_Delete(lua_State* L)
48 {
49 	remove_projectile(Lua_Projectile::Index(L, 1));
50 	return 0;
51 }
52 
Lua_Projectile_Get_Damage_Scale(lua_State * L)53 static int Lua_Projectile_Get_Damage_Scale(lua_State *L)
54 {
55 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
56 	lua_pushnumber(L, (double) projectile->damage_scale / FIXED_ONE);
57 	return 1;
58 }
59 
Lua_Projectile_Get_Elevation(lua_State * L)60 static int Lua_Projectile_Get_Elevation(lua_State *L)
61 {
62 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
63 	double elevation = projectile->elevation * AngleConvert;
64 	if (elevation > 180) elevation -= 360.0;
65 	lua_pushnumber(L, elevation);
66 	return 1;
67 }
68 
Lua_Projectile_Get_Facing(lua_State * L)69 static int Lua_Projectile_Get_Facing(lua_State *L)
70 {
71 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
72 	object_data *object = get_object_data(projectile->object_index);
73 	lua_pushnumber(L, (double) object->facing * AngleConvert);
74 	return 1;
75 }
76 
Lua_Projectile_Get_Gravity(lua_State * L)77 static int Lua_Projectile_Get_Gravity(lua_State *L)
78 {
79 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
80 	lua_pushnumber(L, (double) projectile->gravity / WORLD_ONE);
81 	return 1;
82 }
83 
Lua_Projectile_Get_Owner(lua_State * L)84 static int Lua_Projectile_Get_Owner(lua_State *L)
85 {
86 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
87 	Lua_Monster::Push(L, projectile->owner_index);
88 	return 1;
89 }
90 
Lua_Projectile_Get_Polygon(lua_State * L)91 static int Lua_Projectile_Get_Polygon(lua_State *L)
92 {
93 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
94 	object_data *object = get_object_data(projectile->object_index);
95 	Lua_Polygon::Push(L, object->polygon);
96 	return 1;
97 }
98 
Lua_Projectile_Get_Target(lua_State * L)99 static int Lua_Projectile_Get_Target(lua_State *L)
100 {
101 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
102 	Lua_Monster::Push(L, projectile->target_index);
103 	return 1;
104 }
105 
Lua_Projectile_Get_Type(lua_State * L)106 static int Lua_Projectile_Get_Type(lua_State *L)
107 {
108 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
109 	Lua_ProjectileType::Push(L, projectile->type);
110 	return 1;
111 }
112 
Lua_Projectile_Get_X(lua_State * L)113 static int Lua_Projectile_Get_X(lua_State *L)
114 {
115 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
116 	object_data *object = get_object_data(projectile->object_index);
117 	lua_pushnumber(L, (double) object->location.x / WORLD_ONE);
118 	return 1;
119 }
120 
Lua_Projectile_Get_Y(lua_State * L)121 static int Lua_Projectile_Get_Y(lua_State *L)
122 {
123 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
124 	object_data *object = get_object_data(projectile->object_index);
125 	lua_pushnumber(L, (double) object->location.y / WORLD_ONE);
126 	return 1;
127 }
128 
Lua_Projectile_Get_Z(lua_State * L)129 static int Lua_Projectile_Get_Z(lua_State *L)
130 {
131 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
132 	object_data *object = get_object_data(projectile->object_index);
133 	lua_pushnumber(L, (double) object->location.z / WORLD_ONE);
134 	return 1;
135 }
136 
Lua_Projectile_Set_Damage_Scale(lua_State * L)137 static int Lua_Projectile_Set_Damage_Scale(lua_State *L)
138 {
139 	if (!lua_isnumber(L, 2))
140 		return luaL_error(L, "damage_scale: incorrect argument type");
141 
142 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
143 	projectile->damage_scale = static_cast<int>(lua_tonumber(L, 2) * FIXED_ONE);
144 	return 0;
145 }
146 
Lua_Projectile_Set_Elevation(lua_State * L)147 static int Lua_Projectile_Set_Elevation(lua_State *L)
148 {
149 	if (!lua_isnumber(L, 2))
150 		return luaL_error(L, "elevation: incorrect argument type");
151 
152 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
153 	double elevation = lua_tonumber(L, 2);
154 	if (elevation < 0.0) elevation += 360.0;
155 	projectile->elevation = static_cast<int>(elevation / AngleConvert);
156 	return 0;
157 }
158 
Lua_Projectile_Set_Facing(lua_State * L)159 static int Lua_Projectile_Set_Facing(lua_State *L)
160 {
161 	if (!lua_isnumber(L, 2))
162 		return luaL_error(L, "facing: incorrect argument type");
163 
164 	projectile_data* projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
165 	object_data* object = get_object_data(projectile->object_index);
166 	object->facing = static_cast<int>(lua_tonumber(L, 2) / AngleConvert);
167 	return 0;
168 }
169 
Lua_Projectile_Set_Gravity(lua_State * L)170 static int Lua_Projectile_Set_Gravity(lua_State *L)
171 {
172 	if (!lua_isnumber(L, 2))
173 		return luaL_error(L, "dz: incorrect argument type");
174 
175 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
176 	projectile->gravity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
177 	return 0;
178 }
179 
Lua_Projectile_Set_Owner(lua_State * L)180 static int Lua_Projectile_Set_Owner(lua_State *L)
181 {
182 	short monster_index = 0;
183 	if (lua_isnil(L, 2))
184 	{
185 		monster_index = NONE;
186 	}
187 	else if (lua_isnumber(L, 2))
188 	{
189 		monster_index = static_cast<int>(lua_tonumber(L, 2));
190 	}
191 	else if (Lua_Monster::Is(L, 2))
192 	{
193 		monster_index = Lua_Monster::Index(L, 2);
194 	}
195 	else if (Lua_Player::Is(L, 2))
196 	{
197 		player_data *player = get_player_data(Lua_Player::Index(L, 2));
198 		monster_index = player->monster_index;
199 	}
200 	else
201 	{
202 		return luaL_error(L, "owner: incorrect argument type");
203 	}
204 
205 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
206 	projectile->owner_index = monster_index;
207 	return 0;
208 }
209 
210 extern void add_object_to_polygon_object_list(short object_index, short polygon_index);
211 
Lua_Projectile_Set_Target(lua_State * L)212 static int Lua_Projectile_Set_Target(lua_State *L)
213 {
214 	short monster_index = 0;
215 	if (lua_isnil(L, 2))
216 	{
217 		monster_index = NONE;
218 	}
219 	else if (lua_isnumber(L, 2))
220 	{
221 		monster_index = static_cast<int>(lua_tonumber(L, 2));
222 	}
223 	else if (Lua_Monster::Is(L, 2))
224 	{
225 		monster_index = Lua_Monster::Index(L, 2);
226 	}
227 	else if (Lua_Player::Is(L, 2))
228 	{
229 		player_data *player = get_player_data(Lua_Player::Index(L, 2));
230 		monster_index = player->monster_index;
231 	}
232 	else
233 	{
234 		return luaL_error(L, "owner: incorrect argument type");
235 	}
236 
237 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
238 	projectile->target_index = monster_index;
239 	return 0;
240 }
241 
Lua_Projectile_Play_Sound(lua_State * L)242 int Lua_Projectile_Play_Sound(lua_State *L)
243 {
244 	short sound_code = Lua_Sound::ToIndex(L, 2);
245 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
246 	play_object_sound(projectile->object_index, sound_code);
247 	return 0;
248 }
249 
Lua_Projectile_Position(lua_State * L)250 int Lua_Projectile_Position(lua_State *L)
251 {
252 	if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
253 	{
254 		return luaL_error(L, "position: incorrect argument type");
255 	}
256 
257 	short polygon_index = 0;
258 	if (lua_isnumber(L, 5))
259 	{
260 		polygon_index = static_cast<int>(lua_tonumber(L, 5));
261 		if (!Lua_Polygon::Valid(polygon_index))
262 			return luaL_error(L, "position: invalid polygon index");
263 	}
264 	else if (Lua_Polygon::Is(L, 5))
265 	{
266 		polygon_index = Lua_Polygon::Index(L, 5);
267 	}
268 	else
269 		return luaL_error(L, "position: incorrect argument type");
270 
271 	projectile_data *projectile = get_projectile_data(Lua_Projectile::Index(L, 1));
272 	object_data *object = get_object_data(projectile->object_index);
273 	object->location.x = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
274 	object->location.y = static_cast<int>(lua_tonumber(L, 3) * WORLD_ONE);
275 	object->location.z = static_cast<int>(lua_tonumber(L, 4) * WORLD_ONE);
276 
277 	if (polygon_index != object->polygon)
278 	{
279 		remove_object_from_polygon_object_list(projectile->object_index);
280 		add_object_to_polygon_object_list(projectile->object_index, polygon_index);
281 	}
282 	return 0;
283 }
284 
285 const luaL_Reg Lua_Projectile_Get[] = {
286 	{"damage_scale", Lua_Projectile_Get_Damage_Scale},
287 	{"delete", L_TableFunction<Lua_Projectile_Delete>},
288 	{"dz", Lua_Projectile_Get_Gravity},
289 	{"elevation", Lua_Projectile_Get_Elevation},
290 	{"facing", Lua_Projectile_Get_Facing},
291 	{"play_sound", L_TableFunction<Lua_Projectile_Play_Sound>},
292 	{"position", L_TableFunction<Lua_Projectile_Position>},
293 	{"owner", Lua_Projectile_Get_Owner},
294 	{"pitch", Lua_Projectile_Get_Elevation},
295 	{"polygon", Lua_Projectile_Get_Polygon},
296 	{"target", Lua_Projectile_Get_Target},
297 	{"type", Lua_Projectile_Get_Type},
298 	{"x", Lua_Projectile_Get_X},
299 	{"y", Lua_Projectile_Get_Y},
300 	{"yaw", Lua_Projectile_Get_Facing},
301 	{"z", Lua_Projectile_Get_Z},
302 	{0, 0}
303 };
304 
305 const luaL_Reg Lua_Projectile_Set[] = {
306 	{"damage_scale", Lua_Projectile_Set_Damage_Scale},
307 	{"dz", Lua_Projectile_Set_Gravity},
308 	{"elevation", Lua_Projectile_Set_Elevation},
309 	{"facing", Lua_Projectile_Set_Facing},
310 	{"owner", Lua_Projectile_Set_Owner},
311 	{"pitch", Lua_Projectile_Set_Elevation},
312 	{"target", Lua_Projectile_Set_Target},
313 	{"yaw", Lua_Projectile_Set_Facing},
314 	{0, 0}
315 };
316 
317 char Lua_Projectiles_Name[] = "Projectiles";
318 
319 // Projectiles.new(x, y, z, polygon, type)
Lua_Projectiles_New_Projectile(lua_State * L)320 int Lua_Projectiles_New_Projectile(lua_State *L)
321 {
322 	if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3))
323 	{
324 		return luaL_error(L, "new: incorrect argument type");
325 	}
326 
327 	int polygon_index = 0;
328 	if (lua_isnumber(L, 4))
329 	{
330 		polygon_index = static_cast<int>(lua_tonumber(L, 4));
331 		if (!Lua_Polygon::Valid(polygon_index))
332 			return luaL_error(L, "new: invalid polygon index");
333 	}
334 	else if (Lua_Polygon::Is(L, 4))
335 	{
336 		polygon_index = Lua_Polygon::Index(L, 4);
337 	}
338 	else
339 		return luaL_error(L, "new: incorrect argument type");
340 
341 	world_point3d origin;
342 	origin.x = static_cast<int>(lua_tonumber(L, 1) * WORLD_ONE);
343 	origin.y = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
344 	origin.z = static_cast<int>(lua_tonumber(L, 3) * WORLD_ONE);
345 
346 	world_point3d vector;
347 	vector.x = WORLD_ONE;
348 	vector.y = 0;
349 	vector.z = 0;
350 
351 	short type = Lua_ProjectileType::ToIndex(L, 5);
352 
353 	short projectile_index = ::new_projectile(&origin, polygon_index, &vector, 0, type, NONE, NONE, NONE, FIXED_ONE);
354 	Lua_Projectile::Push(L, projectile_index);
355 	return 1;
356 }
357 
358 const luaL_Reg Lua_Projectiles_Methods[] = {
359 	{"new", L_TableFunction<Lua_Projectiles_New_Projectile>},
360 	{0, 0}
361 };
362 
Lua_Projectile_Valid(int32 index)363 bool Lua_Projectile_Valid(int32 index)
364 {
365 	if (index < 0 || index >= MAXIMUM_PROJECTILES_PER_MAP)
366 		return false;
367 
368 	projectile_data *projectile = GetMemberWithBounds(projectiles, index ,MAXIMUM_PROJECTILES_PER_MAP);
369 	return (SLOT_IS_USED(projectile));
370 }
371 
372 extern projectile_definition *get_projectile_definition(short type);
373 
374 char Lua_ProjectileTypeDamage_Name[] = "projectile_type_damage";
375 typedef L_Class<Lua_ProjectileTypeDamage_Name> Lua_ProjectileTypeDamage;
376 
Lua_ProjectileTypeDamage_Get_Type(lua_State * L)377 static int Lua_ProjectileTypeDamage_Get_Type(lua_State *L)
378 {
379 	projectile_definition *definition = get_projectile_definition(Lua_ProjectileTypeDamage::Index(L, 1));
380 	Lua_DamageType::Push(L, definition->damage.type);
381 	return 1;
382 }
383 
384 const luaL_Reg Lua_ProjectileTypeDamage_Get[] = {
385 	{"type", Lua_ProjectileTypeDamage_Get_Type},
386 	{0, 0}
387 };
388 
389 char Lua_ProjectileType_Name[] = "projectile_type";
390 
Lua_ProjectileType_Get_Damage(lua_State * L)391 static int Lua_ProjectileType_Get_Damage(lua_State *L)
392 {
393 	Lua_ProjectileTypeDamage::Push(L, Lua_ProjectileType::Index(L, 1));
394 	return 1;
395 }
396 
397 const luaL_Reg Lua_ProjectileType_Get[] = {
398 	{"damage", Lua_ProjectileType_Get_Damage},
399 	{0, 0}
400 };
401 
402 char Lua_ProjectileTypes_Name[] = "ProjectileTypes";
403 
Lua_ProjectileType_Valid(int32 index)404 static bool Lua_ProjectileType_Valid(int32 index)
405 {
406 	return (index >= 0 && index < NUMBER_OF_PROJECTILE_TYPES);
407 }
408 
409 static void compatibility(lua_State *L);
410 
Lua_Projectiles_register(lua_State * L)411 int Lua_Projectiles_register(lua_State *L)
412 {
413 	Lua_Projectile::Register(L, Lua_Projectile_Get, Lua_Projectile_Set);
414 	Lua_Projectile::Valid = Lua_Projectile_Valid;
415 
416 	Lua_Projectiles::Register(L, Lua_Projectiles_Methods);
417 	Lua_Projectiles::Length = boost::bind(get_dynamic_limit, (int) _dynamic_limit_projectiles);
418 
419 	Lua_ProjectileType::Register(L, Lua_ProjectileType_Get, 0, 0, Lua_ProjectileType_Mnemonics);
420 	Lua_ProjectileType::Valid = Lua_ProjectileType_Valid;
421 
422 	Lua_ProjectileTypeDamage::Register(L, Lua_ProjectileTypeDamage_Get);
423 
424 	Lua_ProjectileTypes::Register(L);
425 	Lua_ProjectileTypes::Length = Lua_ProjectileTypes::ConstantLength(NUMBER_OF_PROJECTILE_TYPES);
426 
427 	compatibility(L);
428 	return 0;
429 }
430 
431 const char *compatibility_script = ""
432 	"function get_projectile_angle(index) local elevation = Projectiles[index].elevation if elevation < 0.0 then elevation = elevation + 360 end return Projectiles[index].facing, elevation end\n"
433 	"function get_projectile_damage_type(index) return Projectiles[index].type.damage.type.index end\n"
434 	"function get_projectile_owner(index) if Projectiles[index].owner then return Projectiles[index].owner.index end end\n"
435 	"function get_projectile_position(index) return Projectiles[index].polygon.index, Projectiles[index].x, Projectiles[index].y, Projectiles[index].z end\n"
436 	"function get_projectile_target(index) if Projectiles[index].target then return Projectiles[index].target.index end end\n"
437 	"function get_projectile_type(index) return Projectiles[index].type.index end\n"
438 	"function projectile_index_valid(index) if Projectiles[index] then return true else return false end end\n"
439 	"function set_projectile_angle(index, yaw, pitch) Projectiles[index].facing = yaw Projectiles[index].elevation = pitch end\n"
440 	"function set_projectile_owner(index, owner) Projectiles[index].owner = owner end\n"
441 	"function set_projectile_position(index, polygon, x, y, z) Projectiles[index]:position(x, y, z, polygon) end\n"
442 	"function set_projectile_target(index, target) Projectiles[index].target = target end\n"
443 	;
444 
compatibility(lua_State * L)445 static void compatibility(lua_State *L)
446 {
447 	luaL_loadbuffer(L, compatibility_script, strlen(compatibility_script), "projectiles_compatibility");
448 	lua_pcall(L, 0, 0, 0);
449 }
450 #endif
451