Bug Summary

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')

Annotated Source Code

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/*
16Copyright (C) 2002-2011 UFO: Alien Invasion.
17
18This program is free software; you can redistribute it and/or
19modify it under the terms of the GNU General Public License
20as published by the Free Software Foundation; either version 2
21of the License, or (at your option) any later version.
22
23This program is distributed in the hope that it will be useful,
24but WITHOUT ANY WARRANTY; without even the implied warranty of
25MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26
27See the GNU General Public License for more details.
28
29You should have received a copy of the GNU General Public License
30along with this program; if not, write to the Free Software
31Foundation, 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 */
61static 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 */
75static 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 */
86typedef struct aiActor_s {
87 edict_t *ent; /**< Actual actor. */
88} aiActor_t;
89
90
91/*
92 * Current AI Actor.
93 */
94static edict_t *AIL_ent; /**< Actor currently running the Lua AI. */
95static player_t *AIL_player; /**< Player currently running the Lua AI. */
96
97
98/*
99 * Actor metatable.
100 */
101/* Internal functions. */
102static int actorL_register(lua_State *L);
103static int lua_isactor(lua_State *L, int index);
104static aiActor_t* lua_toactor(lua_State *L, int index);
105static aiActor_t* lua_pushactor(lua_State *L, aiActor_t *actor);
106/* Metatable functions. */
107static int actorL_tostring(lua_State *L);
108static int actorL_pos(lua_State *L);
109static int actorL_shoot(lua_State *L);
110static int actorL_face(lua_State *L);
111static int actorL_team(lua_State *L);
112/** Lua Actor metatable methods.
113 * http://www.lua.org/manual/5.1/manual.html#lua_CFunction
114 */
115static 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. */
129static int pos3L_register(lua_State *L);
130static int lua_ispos3(lua_State *L, int index);
131static pos3_t* lua_topos3(lua_State *L, int index);
132static pos3_t* lua_pushpos3(lua_State *L, pos3_t *pos);
133/* Metatable functions. */
134static int pos3L_tostring(lua_State *L);
135static int pos3L_goto(lua_State *L);
136static int pos3L_face(lua_State *L);
137/** Lua Pos3 metatable methods.
138 * http://www.lua.org/manual/5.1/manual.html#lua_CFunction
139 */
140static 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 */
151static int AIL_print(lua_State *L);
152static int AIL_see(lua_State *L);
153static int AIL_crouch(lua_State *L);
154static int AIL_isinjured(lua_State *L);
155static int AIL_TU(lua_State *L);
156static int AIL_HP(lua_State *L);
157static int AIL_morale(lua_State *L);
158static int AIL_reactionfire(lua_State *L);
159static int AIL_roundsleft(lua_State *L);
160static int AIL_canreload(lua_State *L);
161static int AIL_reload(lua_State *L);
162static int AIL_positionshoot(lua_State *L);
163static int AIL_positionhide(lua_State *L);
164static int AIL_positionherd(lua_State *L);
165static int AIL_distance(lua_State *L);
166/** Lua AI module methods.
167 * http://www.lua.org/manual/5.1/manual.html#lua_CFunction
168 */
169static 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 */
198static 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 */
222static 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 */
241static 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 */
253static 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 */
266static 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 */
283static 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 */
297static 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 */
357static 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 */
376static 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 */
400static 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 */
424static 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 */
443static 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 */
455static 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 */
468static 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 */
485static 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 */
507static 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 */
526static 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 */
570static 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 */
659static 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*/
677static 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 */
686static 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 */
695static 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 */
704static 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 */
713static 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 */
740static 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 */
759static 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 */
769static 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 */
797static 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)
1
Taking false branch
823 xl = 0;
824 yl = (int) ent->pos[1] - dist;
825 if (yl < 0)
2
Taking false branch
826 yl = 0;
827 xh = (int) ent->pos[0] + dist;
828 if (xh > PATHFINDING_WIDTH((4096 / 32) * 2))
3
Taking false branch
829 xl = PATHFINDING_WIDTH((4096 / 32) * 2);
830 yh = (int) ent->pos[1] + dist;
831 if (yh > PATHFINDING_WIDTH((4096 / 32) * 2))
4
Taking false branch
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]++)
5
Loop condition is true. Entering loop body
838 for (to[1] = yl; to[1] < yh; to[1]++)
6
Loop condition is true. Entering loop body
839 for (to[0] = xl; to[0] < xh; to[0]++) {
7
Loop condition is true. Entering loop body
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)
8
Taking false branch
845 continue;
846 /* Better spot (easier to get to). */
847 if (tu < min_tu) {
9
Taking true branch
848 if (G_ActorVis(check, ent, target->ent, true) > 0.3) {
10
Access to field 'ent' results in a dereference of a null pointer (loaded from variable 'target')
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 */
871static 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 */
909static 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 */
936static 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 */
960void 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 */
991int 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 */
1038static 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
1049void 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
1057void 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 */
1068void AIL_Cleanup (void)
1069{
1070 edict_t *ent = NULL__null;
1071
1072 while ((ent = G_EdictsGetNextActor(ent)))
1073 AIL_CleanupActor(ent);
1074}