File: | game/g_ai_lua.cpp |
Location: | line 848, column 33 |
Description: | Access to field 'ent' results in a dereference of a null pointer (loaded from variable 'target') |
1 | /** | ||
2 | * @file | ||
3 | * @brief Artificial Intelligence. | ||
4 | * | ||
5 | * @par | ||
6 | * You can find the reference lua manual at http://www.lua.org/manual/5.1/ | ||
7 | * | ||
8 | * @par -1 and -2 are pseudo indexes, they count backwards: | ||
9 | * @li -1 is top | ||
10 | * @li 1 is bottom | ||
11 | * @li -2 is under the top | ||
12 | * @li etc... | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | Copyright (C) 2002-2011 UFO: Alien Invasion. | ||
17 | |||
18 | This program is free software; you can redistribute it and/or | ||
19 | modify it under the terms of the GNU General Public License | ||
20 | as published by the Free Software Foundation; either version 2 | ||
21 | of the License, or (at your option) any later version. | ||
22 | |||
23 | This program is distributed in the hope that it will be useful, | ||
24 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
26 | |||
27 | See the GNU General Public License for more details. | ||
28 | |||
29 | You should have received a copy of the GNU General Public License | ||
30 | along with this program; if not, write to the Free Software | ||
31 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
32 | |||
33 | */ | ||
34 | |||
35 | #include "g_local.h" | ||
36 | #include "g_ai.h" | ||
37 | #include "lua/lauxlib.h" | ||
38 | |||
39 | #define POS3_METATABLE"pos3" "pos3" /**< Pos3 Lua Metatable name. */ | ||
40 | #define ACTOR_METATABLE"actor" "actor" /**< Actor Lua Metable name. */ | ||
41 | #define AI_METATABLE"ai" "ai" /**< AI Lua Metable name. */ | ||
42 | |||
43 | /** | ||
44 | * Provides an api like luaL_dostring for buffers. | ||
45 | */ | ||
46 | #define luaL_dobuffer(L, b, n, s)(luaL_loadbuffer(L, b, n, s) || lua_pcall(L, 0, (-1), 0)) \ | ||
47 | (luaL_loadbuffer(L, b, n, s) || lua_pcall(L, 0, LUA_MULTRET(-1), 0)) | ||
48 | #define AIL_invalidparameter(n)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", n, __func__ ) \ | ||
49 | gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", n, __func__) | ||
50 | |||
51 | /* | ||
52 | * Helper functions | ||
53 | */ | ||
54 | |||
55 | /** | ||
56 | * @brief Converts integer team representation into string | ||
57 | * @param team The team to convert to the string representation | ||
58 | * @return The team string | ||
59 | * @sa AIL_Init | ||
60 | */ | ||
61 | static const char *AIL_toTeamString (const int team) | ||
62 | { | ||
63 | const char *teamStr = gi.GetConstVariable("luaaiteam", team); | ||
64 | if (teamStr == NULL__null) | ||
65 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
66 | return teamStr; | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * @brief Converts team string into int representation | ||
71 | * @param team The team to convert (alien, phalanx, civilian, ...) | ||
72 | * @return The integer representation of the given team string | ||
73 | * @sa AIL_Init | ||
74 | */ | ||
75 | static int AIL_toTeamInt (const char *team) | ||
76 | { | ||
77 | int teamInt = TEAM_DEFAULT1; | ||
78 | if (!gi.GetConstIntFromNamespace("luaaiteam", team, &teamInt)) | ||
79 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
80 | return teamInt; | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * @brief Wrapper around edict. | ||
85 | */ | ||
86 | typedef struct aiActor_s { | ||
87 | edict_t *ent; /**< Actual actor. */ | ||
88 | } aiActor_t; | ||
89 | |||
90 | |||
91 | /* | ||
92 | * Current AI Actor. | ||
93 | */ | ||
94 | static edict_t *AIL_ent; /**< Actor currently running the Lua AI. */ | ||
95 | static player_t *AIL_player; /**< Player currently running the Lua AI. */ | ||
96 | |||
97 | |||
98 | /* | ||
99 | * Actor metatable. | ||
100 | */ | ||
101 | /* Internal functions. */ | ||
102 | static int actorL_register(lua_State *L); | ||
103 | static int lua_isactor(lua_State *L, int index); | ||
104 | static aiActor_t* lua_toactor(lua_State *L, int index); | ||
105 | static aiActor_t* lua_pushactor(lua_State *L, aiActor_t *actor); | ||
106 | /* Metatable functions. */ | ||
107 | static int actorL_tostring(lua_State *L); | ||
108 | static int actorL_pos(lua_State *L); | ||
109 | static int actorL_shoot(lua_State *L); | ||
110 | static int actorL_face(lua_State *L); | ||
111 | static int actorL_team(lua_State *L); | ||
112 | /** Lua Actor metatable methods. | ||
113 | * http://www.lua.org/manual/5.1/manual.html#lua_CFunction | ||
114 | */ | ||
115 | static const luaL_regluaL_Reg actorL_methods[] = { | ||
116 | {"__tostring", actorL_tostring}, | ||
117 | {"pos", actorL_pos}, | ||
118 | {"shoot", actorL_shoot}, | ||
119 | {"face", actorL_face}, | ||
120 | {"team", actorL_team}, | ||
121 | {NULL__null, NULL__null} | ||
122 | }; | ||
123 | |||
124 | |||
125 | /** | ||
126 | * pos3 metatable. | ||
127 | */ | ||
128 | /* Internal functions. */ | ||
129 | static int pos3L_register(lua_State *L); | ||
130 | static int lua_ispos3(lua_State *L, int index); | ||
131 | static pos3_t* lua_topos3(lua_State *L, int index); | ||
132 | static pos3_t* lua_pushpos3(lua_State *L, pos3_t *pos); | ||
133 | /* Metatable functions. */ | ||
134 | static int pos3L_tostring(lua_State *L); | ||
135 | static int pos3L_goto(lua_State *L); | ||
136 | static int pos3L_face(lua_State *L); | ||
137 | /** Lua Pos3 metatable methods. | ||
138 | * http://www.lua.org/manual/5.1/manual.html#lua_CFunction | ||
139 | */ | ||
140 | static const luaL_regluaL_Reg pos3L_methods[] = { | ||
141 | {"__tostring", pos3L_tostring}, | ||
142 | {"goto", pos3L_goto}, | ||
143 | {"face", pos3L_face}, | ||
144 | {NULL__null, NULL__null} | ||
145 | }; | ||
146 | |||
147 | |||
148 | /** | ||
149 | * General AI bindings. | ||
150 | */ | ||
151 | static int AIL_print(lua_State *L); | ||
152 | static int AIL_see(lua_State *L); | ||
153 | static int AIL_crouch(lua_State *L); | ||
154 | static int AIL_isinjured(lua_State *L); | ||
155 | static int AIL_TU(lua_State *L); | ||
156 | static int AIL_HP(lua_State *L); | ||
157 | static int AIL_morale(lua_State *L); | ||
158 | static int AIL_reactionfire(lua_State *L); | ||
159 | static int AIL_roundsleft(lua_State *L); | ||
160 | static int AIL_canreload(lua_State *L); | ||
161 | static int AIL_reload(lua_State *L); | ||
162 | static int AIL_positionshoot(lua_State *L); | ||
163 | static int AIL_positionhide(lua_State *L); | ||
164 | static int AIL_positionherd(lua_State *L); | ||
165 | static int AIL_distance(lua_State *L); | ||
166 | /** Lua AI module methods. | ||
167 | * http://www.lua.org/manual/5.1/manual.html#lua_CFunction | ||
168 | */ | ||
169 | static const luaL_regluaL_Reg AIL_methods[] = { | ||
170 | {"print", AIL_print}, | ||
171 | {"see", AIL_see}, | ||
172 | {"crouch", AIL_crouch}, | ||
173 | {"isinjured", AIL_isinjured}, | ||
174 | {"TU", AIL_TU}, | ||
175 | {"HP", AIL_HP}, | ||
176 | {"morale", AIL_morale}, | ||
177 | {"reactionfire", AIL_reactionfire}, | ||
178 | {"roundsleft", AIL_roundsleft}, | ||
179 | {"canreload", AIL_canreload}, | ||
180 | {"reload", AIL_reload}, | ||
181 | {"positionshoot", AIL_positionshoot}, | ||
182 | {"positionhide", AIL_positionhide}, | ||
183 | {"positionherd", AIL_positionherd}, | ||
184 | {"distance", AIL_distance}, | ||
185 | {NULL__null, NULL__null} | ||
186 | }; | ||
187 | |||
188 | |||
189 | /** | ||
190 | * A C T O R L | ||
191 | */ | ||
192 | |||
193 | /** | ||
194 | * @brief Registers the actor metatable in the lua_State. | ||
195 | * @param[in,out] L State to register the metatable in. | ||
196 | * @return 0 on success. | ||
197 | */ | ||
198 | static int actorL_register (lua_State *L) | ||
199 | { | ||
200 | /* Create the metatable */ | ||
201 | luaL_newmetatable(L, ACTOR_METATABLE"actor"); | ||
202 | |||
203 | /* Create the access table */ | ||
204 | lua_pushvalue(L, -1); | ||
205 | lua_setfield(L, -2, "__index"); | ||
206 | |||
207 | /* Register the values */ | ||
208 | luaL_register(L, NULL__null, actorL_methods); | ||
209 | |||
210 | /* Clean up stack. */ | ||
211 | lua_pop(L, 1)lua_settop(L, -(1)-1); | ||
212 | |||
213 | return 0; /* No error */ | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * @brief Checks to see if there is a actor metatable at index in the lua_State. | ||
218 | * @param[in,out] L Lua state to check. | ||
219 | * @param[in] index Index to check for a actor metatable. | ||
220 | * @return 1 if index has a actor metatable otherwise returns 0. | ||
221 | */ | ||
222 | static int lua_isactor (lua_State *L, int index) | ||
223 | { | ||
224 | int ret; | ||
225 | |||
226 | if (lua_getmetatable(L, index) == 0) | ||
227 | return 0; | ||
228 | lua_getfield(L, LUA_REGISTRYINDEX(-10000), ACTOR_METATABLE"actor"); | ||
229 | |||
230 | ret = 0; | ||
231 | if (lua_rawequal(L, -1, -2)) /* does it have the correct metatable? */ | ||
232 | ret = 1; | ||
233 | |||
234 | lua_pop(L, 2)lua_settop(L, -(2)-1); /* remove both metatables */ | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * @brief Returns the actor from the metatable at index. | ||
240 | */ | ||
241 | static aiActor_t* lua_toactor (lua_State *L, int index) | ||
242 | { | ||
243 | if (lua_isactor(L, index)) { | ||
244 | return (aiActor_t*) lua_touserdata(L, index); | ||
245 | } | ||
246 | luaL_typerror(L, index, ACTOR_METATABLE"actor"); | ||
247 | return NULL__null; | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * @brief Pushes a actor as a metatable at the top of the stack. | ||
252 | */ | ||
253 | static aiActor_t* lua_pushactor (lua_State *L, aiActor_t *actor) | ||
254 | { | ||
255 | aiActor_t *a; | ||
256 | a = (aiActor_t*) lua_newuserdata(L, sizeof(*a)); | ||
257 | *a = *actor; | ||
258 | luaL_getmetatable(L, ACTOR_METATABLE)(lua_getfield(L, (-10000), ("actor"))); | ||
259 | lua_setmetatable(L, -2); | ||
260 | return a; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * @brief Pushes the actor as a string. | ||
265 | */ | ||
266 | static int actorL_tostring (lua_State *L) | ||
267 | { | ||
268 | aiActor_t *target; | ||
269 | char buf[MAX_VAR64]; | ||
270 | |||
271 | assert(lua_isactor(L, 1))(__builtin_expect(!(lua_isactor(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 271, "lua_isactor(L, 1)") : (void) 0); | ||
272 | |||
273 | target = lua_toactor(L, 1); | ||
274 | Com_sprintf(buf, sizeof(buf), "Actor( %s )", target->ent->chr.name); | ||
275 | |||
276 | lua_pushstring(L, buf); | ||
277 | return 1; | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * @brief Gets the actors position. | ||
282 | */ | ||
283 | static int actorL_pos (lua_State *L) | ||
284 | { | ||
285 | aiActor_t *target; | ||
286 | |||
287 | assert(lua_isactor(L, 1))(__builtin_expect(!(lua_isactor(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 287, "lua_isactor(L, 1)") : (void) 0); | ||
288 | |||
289 | target = lua_toactor(L, 1); | ||
290 | lua_pushpos3(L, &target->ent->pos); | ||
291 | return 1; | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * @brief Shoots the actor. | ||
296 | */ | ||
297 | static int actorL_shoot (lua_State *L) | ||
298 | { | ||
299 | int tu, shots; | ||
300 | shoot_types_t shootType; | ||
301 | aiActor_t *target; | ||
302 | const item_t *item; | ||
303 | const fireDef_t *fdArray; | ||
304 | |||
305 | assert(lua_isactor(L, 1))(__builtin_expect(!(lua_isactor(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 305, "lua_isactor(L, 1)") : (void) 0); | ||
306 | |||
307 | /* Target */ | ||
308 | target = lua_toactor(L, 1); | ||
309 | |||
310 | /* Number of TU to spend shooting, fire mode will adjust to that. */ | ||
311 | if (lua_gettop(L) > 1) { | ||
312 | assert(lua_isnumber(L, 2))(__builtin_expect(!(lua_isnumber(L, 2)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 312, "lua_isnumber(L, 2)") : (void )0); /* Must be a number. */ | ||
313 | |||
314 | tu = (int) lua_tonumber(L, 2); | ||
315 | } else { | ||
316 | tu = AIL_ent->TU; | ||
317 | } | ||
318 | |||
319 | shootType = ST_RIGHT0; | ||
320 | item = AI_GetItemForShootType(shootType, AIL_ent); | ||
321 | if (item == NULL__null) { | ||
322 | shootType = ST_LEFT2; | ||
323 | item = AI_GetItemForShootType(shootType, AIL_ent); | ||
324 | } | ||
325 | |||
326 | /* Failure - no weapon. */ | ||
327 | if (item == NULL__null) { | ||
328 | lua_pushboolean(L, 0); | ||
329 | return 1; | ||
330 | } | ||
331 | |||
332 | /** @todo Choose fire mode based on TU available - currently the first one is used. */ | ||
333 | fdArray = FIRESH_FiredefForWeapon(item); | ||
334 | if (fdArray == NULL__null) { | ||
335 | /* Failure - no weapon. */ | ||
336 | lua_pushboolean(L, 0); | ||
337 | return 1; | ||
338 | } | ||
339 | |||
340 | shots = tu / fdArray->time; | ||
341 | |||
342 | while (shots > 0) { | ||
343 | shots--; | ||
344 | /** @todo actually handle fire modes */ | ||
345 | G_ClientShoot(AIL_player, AIL_ent, target->ent->pos, | ||
346 | shootType, 0, NULL__null, true, 0); | ||
347 | } | ||
348 | |||
349 | /* Success. */ | ||
350 | lua_pushboolean(L, 1); | ||
351 | return 1; | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * @brief Makes the actor face the position. | ||
356 | */ | ||
357 | static int actorL_face (lua_State *L) | ||
358 | { | ||
359 | aiActor_t *target; | ||
360 | |||
361 | assert(lua_isactor(L, 1))(__builtin_expect(!(lua_isactor(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 361, "lua_isactor(L, 1)") : (void) 0); | ||
362 | |||
363 | /* Target */ | ||
364 | target = lua_toactor(L, 1); | ||
365 | |||
366 | AI_TurnIntoDirection(AIL_ent, target->ent->pos); | ||
367 | |||
368 | /* Success. */ | ||
369 | lua_pushboolean(L, 1); | ||
370 | return 1; | ||
371 | } | ||
372 | |||
373 | /** | ||
374 | * @brief Gets the actor's team. | ||
375 | */ | ||
376 | static int actorL_team (lua_State *L) | ||
377 | { | ||
378 | const aiActor_t *target; | ||
379 | const char *team; | ||
380 | |||
381 | assert(lua_isactor(L, 1))(__builtin_expect(!(lua_isactor(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 381, "lua_isactor(L, 1)") : (void) 0); | ||
382 | |||
383 | target = lua_toactor(L, 1); | ||
384 | assert(target != NULL)(__builtin_expect(!(target != __null), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 384, "target != NULL") : (void)0); | ||
385 | team = AIL_toTeamString(target->ent->team); | ||
386 | lua_pushstring(L, team); | ||
387 | return 1; | ||
388 | } | ||
389 | |||
390 | |||
391 | /** | ||
392 | * P O S 3 L | ||
393 | */ | ||
394 | |||
395 | /** | ||
396 | * @brief Registers the pos3 metatable in the lua_State. | ||
397 | * @param[in] L State to register the metatable in. | ||
398 | * @return 0 on success. | ||
399 | */ | ||
400 | static int pos3L_register (lua_State *L) | ||
401 | { | ||
402 | /* Create the metatable */ | ||
403 | luaL_newmetatable(L, POS3_METATABLE"pos3"); | ||
404 | |||
405 | /* Create the access table */ | ||
406 | lua_pushvalue(L, -1); | ||
407 | lua_setfield(L, -2, "__index"); | ||
408 | |||
409 | /* Register the values */ | ||
410 | luaL_register(L, NULL__null, pos3L_methods); | ||
411 | |||
412 | /* Clean up the stack. */ | ||
413 | lua_pop(L, 1)lua_settop(L, -(1)-1); | ||
414 | |||
415 | return 0; /* No error */ | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * @brief Checks to see if there is a pos3 metatable at index in the lua_State. | ||
420 | * @param[in] L Lua state to check. | ||
421 | * @param[in] index Index to check for a pos3 metatable. | ||
422 | * @return 1 if index has a pos3 metatable otherwise returns 0. | ||
423 | */ | ||
424 | static int lua_ispos3 (lua_State *L, int index) | ||
425 | { | ||
426 | int ret; | ||
427 | |||
428 | if (lua_getmetatable(L, index) == 0) | ||
429 | return 0; | ||
430 | lua_getfield(L, LUA_REGISTRYINDEX(-10000), POS3_METATABLE"pos3"); | ||
431 | |||
432 | ret = 0; | ||
433 | if (lua_rawequal(L, -1, -2)) /* does it have the correct metatable? */ | ||
434 | ret = 1; | ||
435 | |||
436 | lua_pop(L, 2)lua_settop(L, -(2)-1); /* remove both metatables */ | ||
437 | return ret; | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * @brief Returns the pos3 from the metatable at index. | ||
442 | */ | ||
443 | static pos3_t* lua_topos3 (lua_State *L, int index) | ||
444 | { | ||
445 | if (lua_ispos3(L, index)) { | ||
446 | return (pos3_t*) lua_touserdata(L, index); | ||
447 | } | ||
448 | luaL_typerror(L, index, POS3_METATABLE"pos3"); | ||
449 | return NULL__null; | ||
450 | } | ||
451 | |||
452 | /** | ||
453 | * @brief Pushes a pos3 as a metatable at the top of the stack. | ||
454 | */ | ||
455 | static pos3_t* lua_pushpos3 (lua_State *L, pos3_t *pos) | ||
456 | { | ||
457 | pos3_t *p; | ||
458 | p = (pos3_t*) lua_newuserdata(L, sizeof(*p)); | ||
459 | memcpy(p, pos, sizeof(*p)); | ||
460 | luaL_getmetatable(L, POS3_METATABLE)(lua_getfield(L, (-10000), ("pos3"))); | ||
461 | lua_setmetatable(L, -2); | ||
462 | return p; | ||
463 | } | ||
464 | |||
465 | /** | ||
466 | * @brief Puts the pos3 information in a string. | ||
467 | */ | ||
468 | static int pos3L_tostring (lua_State *L) | ||
469 | { | ||
470 | pos3_t *p; | ||
471 | char buf[MAX_VAR64]; | ||
472 | |||
473 | assert(lua_ispos3(L, 1))(__builtin_expect(!(lua_ispos3(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 473, "lua_ispos3(L, 1)") : (void)0 ); | ||
474 | |||
475 | p = lua_topos3(L, 1); | ||
476 | Com_sprintf(buf, sizeof(buf), "Pos3( x=%d, y=%d, z=%d )", (*p)[0], (*p)[1], (*p)[2]); | ||
477 | |||
478 | lua_pushstring(L, buf); | ||
479 | return 1; | ||
480 | } | ||
481 | |||
482 | /** | ||
483 | * @brief Makes the actor head to the position. | ||
484 | */ | ||
485 | static int pos3L_goto (lua_State *L) | ||
486 | { | ||
487 | pos3_t *pos; | ||
488 | const byte crouchingState = G_IsCrouched(AIL_ent)((AIL_ent)->state & (0x0004)) ? 1 : 0; | ||
489 | |||
490 | assert(lua_ispos3(L, 1))(__builtin_expect(!(lua_ispos3(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 490, "lua_ispos3(L, 1)") : (void)0 ); | ||
491 | |||
492 | /* Calculate move table. */ | ||
493 | G_MoveCalc(0, AIL_ent, AIL_ent->pos, crouchingState, AIL_ent->TU); | ||
494 | gi.MoveStore(level.pathingMap); | ||
495 | |||
496 | /* Move. */ | ||
497 | pos = lua_topos3(L, 1); | ||
498 | G_ClientMove(AIL_player, 0, AIL_ent, *pos); | ||
499 | |||
500 | lua_pushboolean(L, 1); | ||
501 | return 1; | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * @brief Makes the actor face the position. | ||
506 | */ | ||
507 | static int pos3L_face (lua_State *L) | ||
508 | { | ||
509 | pos3_t *pos; | ||
510 | |||
511 | assert(lua_ispos3(L, 1))(__builtin_expect(!(lua_ispos3(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 511, "lua_ispos3(L, 1)") : (void)0 ); | ||
512 | |||
513 | pos = lua_topos3(L, 1); | ||
514 | AI_TurnIntoDirection(AIL_ent, *pos); | ||
515 | |||
516 | lua_pushboolean(L, 1); | ||
517 | return 1; | ||
518 | } | ||
519 | |||
520 | /** | ||
521 | * A I L | ||
522 | */ | ||
523 | /** | ||
524 | * @brief Works more or less like Lua's builtin print. | ||
525 | */ | ||
526 | static int AIL_print (lua_State *L) | ||
527 | { | ||
528 | int i; | ||
529 | const int n = lua_gettop(L); /* number of arguments */ | ||
530 | |||
531 | for (i = 1; i <= n; i++) { | ||
532 | const char *s; | ||
533 | bool meta = false; | ||
534 | |||
535 | lua_pushvalue(L, i); /* value to print */ | ||
536 | if (luaL_callmeta(L, 1, "__tostring")) { | ||
537 | s = lua_tostring(L, -1)lua_tolstring(L, (-1), __null); | ||
538 | meta = true; | ||
539 | } else { | ||
540 | switch (lua_type(L, -1)) { | ||
541 | case LUA_TNUMBER3: | ||
542 | case LUA_TSTRING4: | ||
543 | s = lua_tostring(L, -1)lua_tolstring(L, (-1), __null); | ||
544 | break; | ||
545 | case LUA_TBOOLEAN1: | ||
546 | s = lua_toboolean(L, -1) ? "true" : "false"; | ||
547 | break; | ||
548 | case LUA_TNIL0: | ||
549 | s = "nil"; | ||
550 | break; | ||
551 | |||
552 | default: | ||
553 | s = "unknown lua type"; | ||
554 | break; | ||
555 | } | ||
556 | } | ||
557 | gi.DPrintf("%s%s", (i > 1) ? "\t" : "", s); | ||
558 | lua_pop(L, 1)lua_settop(L, -(1)-1); /* Pop the value */ | ||
559 | if (meta) /* Meta creates an additional string. */ | ||
560 | lua_pop(L, 1)lua_settop(L, -(1)-1); | ||
561 | } | ||
562 | |||
563 | gi.DPrintf("\n"); | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * @brief Returns what the actor can see. | ||
569 | */ | ||
570 | static int AIL_see (lua_State *L) | ||
571 | { | ||
572 | int vision, team; | ||
573 | int i, j, k, n, cur; | ||
574 | edict_t *check = NULL__null; | ||
575 | aiActor_t target; | ||
576 | edict_t *sorted[MAX_EDICTS1024], *unsorted[MAX_EDICTS1024]; | ||
577 | float distLookup[MAX_EDICTS1024]; | ||
578 | |||
579 | /* Defaults. */ | ||
580 | team = TEAM_ALL0xFFFFFFFF; | ||
581 | vision = 0; | ||
582 | |||
583 | /* Handle parameters. */ | ||
584 | if ((lua_gettop(L) > 0)) { | ||
585 | /* Get what to "see" with. */ | ||
586 | if (lua_isstring(L, 1)) { | ||
587 | const char *s = lua_tostring(L, 1)lua_tolstring(L, (1), __null); | ||
588 | /** @todo Properly implement at edict level, get rid of magic numbers. | ||
589 | * These are only "placeholders". */ | ||
590 | if (Q_streq(s, "all")(strcmp(s, "all") == 0)) | ||
591 | vision = 0; | ||
592 | else if (Q_streq(s, "sight")(strcmp(s, "sight") == 0)) | ||
593 | vision = 1; | ||
594 | else if (Q_streq(s, "psionic")(strcmp(s, "psionic") == 0)) | ||
595 | vision = 2; | ||
596 | else if (Q_streq(s, "infrared")(strcmp(s, "infrared") == 0)) | ||
597 | vision = 3; | ||
598 | else | ||
599 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
600 | } else | ||
601 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
602 | |||
603 | /* We now check for different teams. */ | ||
604 | if ((lua_gettop(L) > 1)) { | ||
605 | if (lua_isstring(L, 2)) { | ||
606 | const char *s = lua_tostring(L, 2)lua_tolstring(L, (2), __null); | ||
607 | team = AIL_toTeamInt(s); | ||
608 | } else | ||
609 | AIL_invalidparameter(2)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 2, __func__ ); | ||
610 | } | ||
611 | } | ||
612 | |||
613 | n = 0; | ||
614 | /* Get visible things. */ | ||
615 | while ((check = G_EdictsGetNextLivingActor(check))) { | ||
616 | if (AIL_ent == check) | ||
617 | continue; | ||
618 | if (vision == 0 && (team == TEAM_ALL0xFFFFFFFF || check->team == team) /* Check for team match if needed. */ | ||
619 | && G_Vis(AIL_ent->team, AIL_ent, check, VT_NOFRUSTUM2)) { | ||
620 | distLookup[n] = VectorDistSqr(AIL_ent->pos, check->pos)(((check->pos)[0]-(AIL_ent->pos)[0])*((check->pos)[0 ]-(AIL_ent->pos)[0])+((check->pos)[1]-(AIL_ent->pos) [1])*((check->pos)[1]-(AIL_ent->pos)[1])+((check->pos )[2]-(AIL_ent->pos)[2])*((check->pos)[2]-(AIL_ent->pos )[2])); | ||
621 | unsorted[n++] = check; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | /* Sort by distance - nearest first. */ | ||
626 | for (i = 0; i < n; i++) { /* Until we fill sorted */ | ||
627 | cur = -1; | ||
628 | for (j = 0; j < n; j++) { /* Check for closest */ | ||
629 | /* Is shorter then current minimum? */ | ||
630 | if (cur < 0 || distLookup[j] < distLookup[cur]) { | ||
631 | /* Check if not already in sorted. */ | ||
632 | for (k = 0; k < i; k++) | ||
633 | if (sorted[k] == unsorted[j]) | ||
634 | break; | ||
635 | |||
636 | /* Not already sorted and is new minimum. */ | ||
637 | if (k == i) | ||
638 | cur = j; | ||
639 | } | ||
640 | } | ||
641 | |||
642 | sorted[i] = unsorted[cur]; | ||
643 | } | ||
644 | |||
645 | /* Now save it in a Lua table. */ | ||
646 | lua_newtable(L)lua_createtable(L, 0, 0); | ||
647 | for (i = 0; i < n; i++) { | ||
648 | lua_pushnumber(L, i + 1); /* index, starts with 1 */ | ||
649 | target.ent = sorted[i]; | ||
650 | lua_pushactor(L, &target); /* value */ | ||
651 | lua_rawset(L, -3); /* store the value in the table */ | ||
652 | } | ||
653 | return 1; /* Returns the table of actors. */ | ||
654 | } | ||
655 | |||
656 | /** | ||
657 | * @brief Toggles crouch state with true/false and returns current crouch state. | ||
658 | */ | ||
659 | static int AIL_crouch (lua_State *L) | ||
660 | { | ||
661 | if (lua_gettop(L) > 0) { | ||
662 | if (lua_isboolean(L, 1)(lua_type(L, (1)) == 1)) { | ||
663 | const int state = lua_toboolean(L, 1); | ||
664 | G_ClientStateChange(AIL_player, AIL_ent, STATE_CROUCHED0x0004, | ||
665 | (state) ? true : false); | ||
666 | } else | ||
667 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
668 | } | ||
669 | |||
670 | lua_pushboolean(L, G_IsCrouched(AIL_ent)((AIL_ent)->state & (0x0004))); | ||
671 | return 1; | ||
672 | } | ||
673 | |||
674 | /** | ||
675 | * @brief Checks to see if the actor is injured | ||
676 | */ | ||
677 | static int AIL_isinjured (lua_State *L) | ||
678 | { | ||
679 | lua_pushboolean(L, AIL_ent->HP != AIL_ent->chr.maxHP); | ||
680 | return 1; | ||
681 | } | ||
682 | |||
683 | /** | ||
684 | * @brief Gets the number of TU the actor has left. | ||
685 | */ | ||
686 | static int AIL_TU (lua_State *L) | ||
687 | { | ||
688 | lua_pushnumber(L, AIL_ent->TU); | ||
689 | return 1; | ||
690 | } | ||
691 | |||
692 | /** | ||
693 | * @brief Gets the number of HP the actor has left. | ||
694 | */ | ||
695 | static int AIL_HP (lua_State *L) | ||
696 | { | ||
697 | lua_pushnumber(L, AIL_ent->HP); | ||
698 | return 1; | ||
699 | } | ||
700 | |||
701 | /** | ||
702 | * @brief Gets the current morale of the actor onto the stack. | ||
703 | */ | ||
704 | static int AIL_morale (lua_State *L) | ||
705 | { | ||
706 | lua_pushnumber(L, AIL_ent->morale); | ||
707 | return 1; | ||
708 | } | ||
709 | |||
710 | /** | ||
711 | * @brief Sets the actor's reaction fire mode. | ||
712 | */ | ||
713 | static int AIL_reactionfire (lua_State *L) | ||
714 | { | ||
715 | int reactionState = 0; | ||
716 | if (lua_gettop(L) > 0) { | ||
717 | |||
718 | if (lua_isstring(L, 1)) { | ||
719 | /* get reaction fire mode */ | ||
720 | const char* cmd = lua_tostring(L, 1)lua_tolstring(L, (1), __null); | ||
721 | reactionState = Q_streq(cmd, "disable")(strcmp(cmd, "disable") == 0) ? ~STATE_REACTION0x0300 : STATE_REACTION0x0300; | ||
722 | } | ||
723 | |||
724 | if (reactionState && lua_gettop(L) > 1 && lua_isboolean(L, 2)(lua_type(L, (2)) == 1)) { | ||
725 | const int state = lua_toboolean(L, 2); | ||
726 | G_ClientStateChange(AIL_player, AIL_ent, reactionState, | ||
727 | (state) ? true : false); | ||
728 | } else { | ||
729 | AIL_invalidparameter(reactionState ? 2 : 1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", reactionState ? 2 : 1, __func__); | ||
730 | } | ||
731 | } | ||
732 | |||
733 | lua_pushboolean(L, G_IsReaction(AIL_ent)((AIL_ent)->state & (0x0300))); | ||
734 | return 1; | ||
735 | } | ||
736 | |||
737 | /** | ||
738 | * @brief Checks to see how many rounds the actor has left. | ||
739 | */ | ||
740 | static int AIL_roundsleft (lua_State *L) | ||
741 | { | ||
742 | /* Right hand */ | ||
743 | if (RIGHT(AIL_ent)(((AIL_ent)->chr.i.c[(gi.csi->idRight)])) && RIGHT(AIL_ent)(((AIL_ent)->chr.i.c[(gi.csi->idRight)]))->item.t->reload) | ||
744 | lua_pushnumber(L, RIGHT(AIL_ent)(((AIL_ent)->chr.i.c[(gi.csi->idRight)]))->item.a); | ||
745 | else | ||
746 | lua_pushnil(L); | ||
747 | |||
748 | /* Left hand */ | ||
749 | if (LEFT(AIL_ent)(((AIL_ent)->chr.i.c[(gi.csi->idLeft)])) && LEFT(AIL_ent)(((AIL_ent)->chr.i.c[(gi.csi->idLeft)]))->item.t->reload) | ||
750 | lua_pushnumber(L, LEFT(AIL_ent)(((AIL_ent)->chr.i.c[(gi.csi->idLeft)]))->item.a); | ||
751 | else | ||
752 | lua_pushnil(L); | ||
753 | return 2; | ||
754 | } | ||
755 | |||
756 | /** | ||
757 | * @brief Checks to see if the actor can reload. | ||
758 | */ | ||
759 | static int AIL_canreload (lua_State *L) | ||
760 | { | ||
761 | lua_pushboolean(L, G_ClientCanReload(AIL_ent, gi.csi->idRight)); | ||
762 | lua_pushboolean(L, G_ClientCanReload(AIL_ent, gi.csi->idLeft)); | ||
763 | return 2; | ||
764 | } | ||
765 | |||
766 | /** | ||
767 | * @brief Actor reloads his weapons. | ||
768 | */ | ||
769 | static int AIL_reload (lua_State *L) | ||
770 | { | ||
771 | containerIndex_t container; | ||
772 | |||
773 | if (lua_gettop(L) > 0) { | ||
774 | if (lua_isstring(L, 1)) { | ||
775 | const char *s = lua_tostring(L, 1)lua_tolstring(L, (1), __null); | ||
776 | |||
777 | if (Q_streq(s, "right")(strcmp(s, "right") == 0)) | ||
778 | container = gi.csi->idRight; | ||
779 | else if (Q_streq(s, "left")(strcmp(s, "left") == 0)) | ||
780 | container = gi.csi->idLeft; | ||
781 | else | ||
782 | return 0; | ||
783 | } else { | ||
784 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
785 | return 0; | ||
786 | } | ||
787 | } else | ||
788 | container = gi.csi->idRight; /* Default to right hand. */ | ||
789 | |||
790 | G_ActorReload(AIL_ent, INVDEF(container)(&gi.csi->ids[(container)])); | ||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | /** | ||
795 | * @brief Moves the actor into a position in which he can shoot his target. | ||
796 | */ | ||
797 | static int AIL_positionshoot (lua_State *L) | ||
798 | { | ||
799 | pos3_t to, bestPos; | ||
800 | vec3_t check; | ||
801 | edict_t *ent; | ||
802 | int dist; | ||
803 | int xl, yl, xh, yh; | ||
804 | int min_tu; | ||
805 | aiActor_t *target; | ||
806 | const byte crouchingState = G_IsCrouched(AIL_ent)((AIL_ent)->state & (0x0004)) ? 1 : 0; | ||
807 | |||
808 | /* We need a target. */ | ||
809 | assert(lua_isactor(L, 1))(__builtin_expect(!(lua_isactor(L, 1)), 0) ? __assert_rtn(__func__ , "src/game/g_ai_lua.cpp", 809, "lua_isactor(L, 1)") : (void) 0); | ||
810 | target = lua_toactor(L, 1); | ||
811 | |||
812 | /* Make things more simple. */ | ||
813 | ent = AIL_ent; | ||
814 | dist = ent->TU; | ||
815 | |||
816 | /* Calculate move table. */ | ||
817 | G_MoveCalc(0, ent, ent->pos, crouchingState, ent->TU); | ||
818 | gi.MoveStore(level.pathingMap); | ||
819 | |||
820 | /* set borders */ | ||
821 | xl = (int) ent->pos[0] - dist; | ||
822 | if (xl < 0) | ||
| |||
823 | xl = 0; | ||
824 | yl = (int) ent->pos[1] - dist; | ||
825 | if (yl < 0) | ||
| |||
826 | yl = 0; | ||
827 | xh = (int) ent->pos[0] + dist; | ||
828 | if (xh > PATHFINDING_WIDTH((4096 / 32) * 2)) | ||
| |||
829 | xl = PATHFINDING_WIDTH((4096 / 32) * 2); | ||
830 | yh = (int) ent->pos[1] + dist; | ||
831 | if (yh > PATHFINDING_WIDTH((4096 / 32) * 2)) | ||
| |||
832 | yh = PATHFINDING_WIDTH((4096 / 32) * 2); | ||
833 | |||
834 | /* evaluate moving to every possible location in the search area, | ||
835 | * including combat considerations */ | ||
836 | min_tu = INT_MAX2147483647; | ||
837 | for (to[2] = 0; to[2] < PATHFINDING_HEIGHT8; to[2]++) | ||
| |||
838 | for (to[1] = yl; to[1] < yh; to[1]++) | ||
| |||
839 | for (to[0] = xl; to[0] < xh; to[0]++) { | ||
| |||
840 | pos_t tu; | ||
841 | /* Can we see the target? */ | ||
842 | gi.GridPosToVec(gi.routingMap, ent->fieldSize, to, check); | ||
843 | tu = gi.MoveLength(level.pathingMap, to, G_IsCrouched(ent)((ent)->state & (0x0004)) ? 1 : 0, true); | ||
844 | if (tu > ent->TU || tu == ROUTING_NOT_REACHABLE0xFF) | ||
| |||
845 | continue; | ||
846 | /* Better spot (easier to get to). */ | ||
847 | if (tu < min_tu) { | ||
| |||
848 | if (G_ActorVis(check, ent, target->ent, true) > 0.3) { | ||
| |||
849 | VectorCopy(to, bestPos)((bestPos)[0]=(to)[0],(bestPos)[1]=(to)[1],(bestPos)[2]=(to)[ 2]); | ||
850 | min_tu = tu; | ||
851 | } | ||
852 | } | ||
853 | } | ||
854 | |||
855 | /* No position found in range. */ | ||
856 | if (min_tu > ent->TU) { | ||
857 | lua_pushboolean(L, 0); | ||
858 | return 1; | ||
859 | } | ||
860 | |||
861 | /* Return the spot. */ | ||
862 | lua_pushpos3(L, &bestPos); | ||
863 | return 1; | ||
864 | } | ||
865 | |||
866 | /** | ||
867 | * @brief Moves the actor into a position in which he can hide. | ||
868 | * @note @c team (parameter is passed through the lua stack) means that the AI tries to find | ||
869 | * a hide position from the @c team members, if parameter is empty - from any enemy | ||
870 | */ | ||
871 | static int AIL_positionhide (lua_State *L) | ||
872 | { | ||
873 | pos3_t save; | ||
874 | int tus = AIL_ent->TU; | ||
875 | int hidingTeam; | ||
876 | |||
877 | VectorCopy(AIL_ent->pos, save)((save)[0]=(AIL_ent->pos)[0],(save)[1]=(AIL_ent->pos)[1 ],(save)[2]=(AIL_ent->pos)[2]); | ||
878 | |||
879 | hidingTeam = AI_GetHidingTeam(AIL_ent); | ||
880 | |||
881 | /* parse parameter */ | ||
882 | if (lua_gettop(L)) { | ||
883 | if (lua_isstring(L, 1)) { | ||
884 | const char* s = lua_tostring(L, 1)lua_tolstring(L, (1), __null); | ||
885 | hidingTeam = AIL_toTeamInt(s); | ||
886 | if (hidingTeam == TEAM_ALL0xFFFFFFFF) | ||
887 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
888 | } else { | ||
889 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
890 | } | ||
891 | } | ||
892 | |||
893 | if (AI_FindHidingLocation(hidingTeam, AIL_ent, AIL_ent->pos, &tus)) { | ||
894 | /* Return the spot. */ | ||
895 | lua_pushpos3(L, &AIL_ent->pos); | ||
896 | } else { | ||
897 | lua_pushboolean(L, 0); | ||
898 | } | ||
899 | G_EdictSetOrigin(AIL_ent, save); | ||
900 | return 1; | ||
901 | } | ||
902 | |||
903 | /** | ||
904 | * @brief Determine the position where actor is more closer to the target and | ||
905 | * locate behind the target from enemy | ||
906 | * @note @c target (parameter is passed through the lua stack) The actor | ||
907 | * to which AI tries to become closer | ||
908 | */ | ||
909 | static int AIL_positionherd (lua_State *L) | ||
910 | { | ||
911 | pos3_t save; | ||
912 | aiActor_t* target; | ||
913 | |||
914 | /* check parameter */ | ||
915 | if (!(lua_gettop(L) && lua_isactor(L, 1))) { | ||
916 | AIL_invalidparameter(1)gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", 1, __func__ ); | ||
917 | lua_pushboolean(L, 0); | ||
918 | return 1; | ||
919 | } | ||
920 | |||
921 | VectorCopy(AIL_ent->pos, save)((save)[0]=(AIL_ent->pos)[0],(save)[1]=(AIL_ent->pos)[1 ],(save)[2]=(AIL_ent->pos)[2]); | ||
922 | target = lua_toactor(L, 1); | ||
923 | if (AI_FindHerdLocation(AIL_ent, AIL_ent->pos, target->ent->origin, AIL_ent->TU)) { | ||
924 | lua_pushpos3(L, &AIL_ent->pos); | ||
925 | } else { | ||
926 | lua_pushboolean(L, 0); | ||
927 | } | ||
928 | G_EdictSetOrigin(AIL_ent, save); | ||
929 | return 1; | ||
930 | } | ||
931 | |||
932 | /** | ||
933 | * @brief Returns distance between AI and target | ||
934 | * @note @c target (passed trough the lua stack) The target to which the distance is calculated | ||
935 | */ | ||
936 | static int AIL_distance (lua_State *L) | ||
937 | { | ||
938 | vec_t dist; | ||
939 | aiActor_t* target; | ||
940 | |||
941 | /* check parameter */ | ||
942 | assert(lua_gettop(L) && lua_isactor(L, 1))(__builtin_expect(!(lua_gettop(L) && lua_isactor(L, 1 )), 0) ? __assert_rtn(__func__, "src/game/g_ai_lua.cpp", 942, "lua_gettop(L) && lua_isactor(L, 1)") : (void)0); | ||
943 | |||
944 | /* calculate distance */ | ||
945 | target = lua_toactor(L, 1); | ||
946 | dist = VectorDist(AIL_ent->origin, target->ent->origin)(sqrt(((target->ent->origin)[0]-(AIL_ent->origin)[0] )*((target->ent->origin)[0]-(AIL_ent->origin)[0])+(( target->ent->origin)[1]-(AIL_ent->origin)[1])*((target ->ent->origin)[1]-(AIL_ent->origin)[1])+((target-> ent->origin)[2]-(AIL_ent->origin)[2])*((target->ent-> origin)[2]-(AIL_ent->origin)[2]))); | ||
947 | lua_pushnumber(L, dist); | ||
948 | return 1; | ||
949 | } | ||
950 | |||
951 | /** | ||
952 | * @brief The think function for the ai controlled aliens | ||
953 | * @param[in] player | ||
954 | * @param[in] ent | ||
955 | * @sa AI_FighterCalcBestAction | ||
956 | * @sa AI_CivilianCalcBestAction | ||
957 | * @sa G_ClientMove | ||
958 | * @sa G_ClientShoot | ||
959 | */ | ||
960 | void AIL_ActorThink (player_t * player, edict_t * ent) | ||
961 | { | ||
962 | lua_State *L; | ||
963 | |||
964 | /* The Lua State we will work with. */ | ||
965 | L = ent->AI.L; | ||
966 | |||
967 | /* Set the global player and edict */ | ||
968 | AIL_ent = ent; | ||
969 | AIL_player = player; | ||
970 | |||
971 | /* Try to run the function. */ | ||
972 | lua_getglobal(L, "think")lua_getfield(L, (-10002), ("think")); | ||
973 | if (lua_pcall(L, 0, 0, 0)) { /* error has occured */ | ||
974 | gi.DPrintf("Error while running Lua: %s\n", | ||
975 | lua_isstring(L, -1) ? lua_tostring(L, -1)lua_tolstring(L, (-1), __null) : "Unknown Error"); | ||
976 | } | ||
977 | |||
978 | /* Cleanup */ | ||
979 | AIL_ent = NULL__null; | ||
980 | AIL_player = NULL__null; | ||
981 | } | ||
982 | |||
983 | |||
984 | /** | ||
985 | * @brief Initializes the AI. | ||
986 | * @param[in] ent Pointer to actor to initialize AI for. | ||
987 | * @param[in] type Type of AI (Lua file name without .lua). | ||
988 | * @param[in] subtype Subtype of the AI. | ||
989 | * @return 0 on success. | ||
990 | */ | ||
991 | int AIL_InitActor (edict_t * ent, const char *type, const char *subtype) | ||
992 | { | ||
993 | AI_t *AI; | ||
994 | int size; | ||
995 | char path[MAX_VAR64]; | ||
996 | char *fbuf; | ||
997 | |||
998 | /* Prepare the AI */ | ||
999 | AI = &ent->AI; | ||
1000 | Q_strncpyz(AI->type, type, sizeof(AI->type))Q_strncpyzDebug( AI->type, type, sizeof(AI->type), "src/game/g_ai_lua.cpp" , 1000 ); | ||
1001 | Q_strncpyz(AI->subtype, subtype, sizeof(AI->type))Q_strncpyzDebug( AI->subtype, subtype, sizeof(AI->type) , "src/game/g_ai_lua.cpp", 1001 ); | ||
1002 | |||
1003 | /* Create the new Lua state */ | ||
1004 | AI->L = luaL_newstate(); | ||
1005 | if (AI->L == NULL__null) { | ||
1006 | gi.DPrintf("Unable to create Lua state.\n"); | ||
1007 | return -1; | ||
1008 | } | ||
1009 | |||
1010 | /* Register metatables. */ | ||
1011 | actorL_register(AI->L); | ||
1012 | pos3L_register(AI->L); | ||
1013 | |||
1014 | /* Register libraries. */ | ||
1015 | luaL_register(AI->L, AI_METATABLE"ai", AIL_methods); | ||
1016 | |||
1017 | /* Load the AI */ | ||
1018 | Com_sprintf(path, sizeof(path), "ai/%s.lua", type); | ||
1019 | size = gi.FS_LoadFile(path, (byte **) &fbuf); | ||
1020 | if (size == 0) { | ||
1021 | gi.DPrintf("Unable to load Lua file '%s'.\n", path); | ||
1022 | return -1; | ||
1023 | } | ||
1024 | if (luaL_dobuffer(AI->L, fbuf, size, path)(luaL_loadbuffer(AI->L, fbuf, size, path) || lua_pcall(AI-> L, 0, (-1), 0))) { | ||
1025 | gi.DPrintf("Unable to parse Lua file '%s'\n", path); | ||
1026 | gi.FS_FreeFile(fbuf); | ||
1027 | return -1; | ||
1028 | } | ||
1029 | gi.FS_FreeFile(fbuf); | ||
1030 | |||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | /** | ||
1035 | * @brief Cleans up the AI part of the actor. | ||
1036 | * @param[in] ent Pointer to actor to cleanup AI. | ||
1037 | */ | ||
1038 | static void AIL_CleanupActor (edict_t * ent) | ||
1039 | { | ||
1040 | AI_t *AI = &ent->AI; | ||
1041 | |||
1042 | /* Cleanup. */ | ||
1043 | if (AI->L != NULL__null) { | ||
1044 | lua_close(AI->L); | ||
1045 | AI->L = NULL__null; | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | void AIL_Init (void) | ||
1050 | { | ||
1051 | gi.RegisterConstInt("luaaiteam::phalanx", TEAM_PHALANX1); | ||
1052 | gi.RegisterConstInt("luaaiteam::civilian", TEAM_CIVILIAN0); | ||
1053 | gi.RegisterConstInt("luaaiteam::alien", TEAM_ALIEN7); | ||
1054 | gi.RegisterConstInt("luaaiteam::all", TEAM_ALL0xFFFFFFFF); | ||
1055 | } | ||
1056 | |||
1057 | void AIL_Shutdown (void) | ||
1058 | { | ||
1059 | gi.UnregisterConstVariable("luaaiteam::phalanx"); | ||
1060 | gi.UnregisterConstVariable("luaaiteam::civilian"); | ||
1061 | gi.UnregisterConstVariable("luaaiteam::alien"); | ||
1062 | gi.UnregisterConstVariable("luaaiteam::all"); | ||
1063 | } | ||
1064 | |||
1065 | /** | ||
1066 | * @brief Purges all the AI from the entities. | ||
1067 | */ | ||
1068 | void AIL_Cleanup (void) | ||
1069 | { | ||
1070 | edict_t *ent = NULL__null; | ||
1071 | |||
1072 | while ((ent = G_EdictsGetNextActor(ent))) | ||
1073 | AIL_CleanupActor(ent); | ||
1074 | } |