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