UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
g_ai_lua.cpp
Go to the documentation of this file.
1 
15 /*
16 Copyright (C) 2002-2020 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 "../shared/cxx.h"
36 
37 #include "g_local.h"
38 #include "g_ai.h"
39 #include "g_actor.h"
40 #include "g_client.h"
41 #include "g_combat.h"
42 #include "g_edicts.h"
43 #include "g_health.h"
44 #include "g_move.h"
45 #include "g_utils.h"
46 #include "g_vis.h"
47 extern "C" {
48 #include <lauxlib.h>
49 }
50 
51 #define POS3_METATABLE "pos3"
52 #define ACTOR_METATABLE "actor"
53 #define AI_METATABLE "ai"
55 static lua_State* ailState;
56 
59 #define luaL_dobuffer(L, b, n, s) \
60  (luaL_loadbuffer(L, b, n, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
61 #define AIL_invalidparameter(n) \
62  gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", n, __func__)
63 
65 typedef enum {
66  AILVT_ALL, /* Don't do vis checks (god's view) */
67  AILVT_SIGHT, /* Standard vis check */
68  AILVT_TEAM, /* Team vis check */
69  AILVT_DIST /* Check only vis distance */
70 } ailVisType_t;
71 
73 typedef enum {
74  AILSC_DIST, /* Sort by line distance */
75  AILSC_PATH, /* Sort by pathing cost */
76  AILSC_HP /* Sort by HP */
78 
80 typedef enum {
81  AILSP_FAST, /* Fastest to get to */
82  AILSP_NEAR, /* Nearest to target */
83  AILSP_FAR, /* Farthest from target (within weapon's range) */
84  AILSP_DMG /* Best expected damage */
86 
87 typedef enum {
88  AILPW_RAND, /* Wander randomly */
89  AILPW_CW, /* Move clockwise */
90  AILPW_CCW /* Move counter-clockwise */
92 /*
93  * Helper functions
94  */
95 
102 static const char* AIL_toTeamString (const int team)
103 {
104  const char* teamStr = gi.GetConstVariable("luaaiteam", team);
105  if (teamStr == nullptr)
107  return teamStr;
108 }
109 
117 static int AIL_toTeamInt (const char* team, const int param)
118 {
119  int teamInt = TEAM_DEFAULT;
120  if (!gi.GetConstIntFromNamespace("luaaiteam", team, &teamInt))
121  AIL_invalidparameter(param);
122  return teamInt;
123 }
124 
131 static ailVisType_t AIL_toVisInt (lua_State* L, const int index)
132 {
133  int visInt = AILVT_ALL;
134  if (lua_isstring(L, index)) {
135  const char* s = lua_tostring(L, index);
136  if (!gi.GetConstIntFromNamespace("luaaivis", s, &visInt))
137  AIL_invalidparameter(index);
138  } else
139  AIL_invalidparameter(index);
140  return static_cast<ailVisType_t> (visInt);
141 }
142 
149 static ailSortCritType_t AIL_toSortInt (lua_State* L, const int index)
150 {
151  int sortInt = AILSC_DIST;
152  if (lua_isstring(L, index)) {
153  const char* s = lua_tostring(L, index);
154  if (!gi.GetConstIntFromNamespace("luaaisort", s, &sortInt))
155  AIL_invalidparameter(index);
156  } else
157  AIL_invalidparameter(index);
158  return static_cast<ailSortCritType_t> (sortInt);
159 }
160 
167 static ailSortCritType_t AIL_toDistInt (lua_State* L, const int index)
168 {
169  int distInt = AILSC_DIST;
170  if (lua_isstring(L, index)) {
171  const char* s = lua_tostring(L, index);
172  if (!gi.GetConstIntFromNamespace("luaaidist", s, &distInt))
173  AIL_invalidparameter(index);
174  } else
175  AIL_invalidparameter(index);
176  return static_cast<ailSortCritType_t> (distInt);
177 }
178 
185 static ailShootPosType_t AIL_toShotPInt (lua_State* L, const int index)
186 {
187  int spInt = AILSP_FAST;
188  if (lua_isstring(L, index)) {
189  const char* s = lua_tostring(L, index);
190  if (!gi.GetConstIntFromNamespace("luaaishot", s, &spInt))
191  AIL_invalidparameter(index);
192  } else
193  AIL_invalidparameter(index);
194  return static_cast<ailShootPosType_t> (spInt);
195 }
196 
203 static ailWanderPosType AIL_toWanderPInt (lua_State* L, const int index)
204 {
205  int wpInt = AILPW_RAND;
206  if (lua_isstring(L, index)) {
207  const char* s = lua_tostring(L, index);
208  if (!gi.GetConstIntFromNamespace("luaaiwander", s, &wpInt))
209  AIL_invalidparameter(index);
210  } else
211  AIL_invalidparameter(index);
212  return static_cast<ailWanderPosType> (wpInt);
213 }
214 
218 typedef struct aiActor_s {
220 } aiActor_t;
221 
222 
223 /* Table sorting */
224 template<typename T>
225 struct AilSortTable {
226  T data;
227  float sortLookup;
228 };
229 
230 template<typename T>
231 bool operator< (AilSortTable<T> i, AilSortTable<T> j) {
232  return (i.sortLookup < j.sortLookup);
233 }
234 
235 /*
236  * Current AI Actor.
237  */
238 static Actor* AIL_ent;
239 static Player* AIL_player;
241 static float AIL_GetBestShot(const Actor& shooter, const Actor& target, const int tu, const float dist, shoot_types_t& bestType, fireDefIndex_t& bestFd, int& bestShots)
242 {
243  int shotChecked = NONE;
244  float bestDmg = 0.0f;
245  bestShots = bestType = bestFd = NONE;
246  for (shoot_types_t shootType = ST_RIGHT; shootType < ST_NUM_SHOOT_TYPES; shootType++) {
247  const Item* item = AI_GetItemForShootType(shootType, AIL_ent);
248  if (item == nullptr)
249  continue;
250 
251  const fireDef_t* fdArray = item->getFiredefs();
252  if (fdArray == nullptr)
253  continue;
254 
255  for (fireDefIndex_t fdIdx = 0; fdIdx < item->ammoDef()->numFiredefs[fdArray->weapFdsIdx]; fdIdx++) {
256  const fireDef_t* fd = &fdArray[fdIdx];
257  const int time = G_ActorGetModifiedTimeForFiredef(AIL_ent, fd, false);
258  /* how many shoots can this actor do */
259  const int shots = tu / time;
260 
261  if (!shots)
262  continue;
263 
264  if (!AI_FighterCheckShoot(AIL_ent, &target, fd, dist))
265  continue;
266 
267  const int shotFlags = fd->gravity | (fd->launched << 1) | (fd->rolled << 2);
268  if (shotChecked != shotFlags) {
269  shotChecked = shotFlags;
270  if (!AI_CheckLineOfFire(AIL_ent, &target, fd, shots))
271  continue;
272  }
273 
274  /* Check if we can do the most damage here */
275  float dmg = AI_CalcShotDamage(AIL_ent, &target, fd, shootType) * shots;
276  if (dmg > bestDmg) {
277  bestDmg = dmg;
278  bestShots = shots;
279  bestFd = fdIdx;
280  bestType = shootType;
281  }
282  }
283  }
284 
285  return bestDmg;
286 }
287 
288 /*
289  * Actor metatable.
290  */
291 /* Internal functions. */
292 static int actorL_register(lua_State* L);
293 static int lua_isactor(lua_State* L, int index);
294 static aiActor_t* lua_toactor(lua_State* L, int index);
295 static aiActor_t* lua_pushactor(lua_State* L, aiActor_t* actor);
296 /* Metatable functions. */
297 static int actorL_tostring(lua_State* L);
298 static int actorL_pos(lua_State* L);
299 static int actorL_shoot(lua_State* L);
300 static int actorL_team(lua_State* L);
301 static int actorL_throwgrenade(lua_State* L);
302 static int actorL_TU(lua_State* L);
303 static int actorL_HP(lua_State* L);
304 static int actorL_morale(lua_State* L);
305 static int actorL_isinjured(lua_State* L);
306 static int actorL_isarmed(lua_State* L);
307 static int actorL_isdead(lua_State* L);
308 static int actorL_isvalidtarget(lua_State* L);
312 static const luaL_reg actorL_methods[] = {
313  {"__tostring", actorL_tostring},
314  {"pos", actorL_pos},
315  {"shoot", actorL_shoot},
316  {"team", actorL_team},
317  {"throwgrenade", actorL_throwgrenade},
318  {"TU", actorL_TU},
319  {"HP", actorL_HP},
320  {"morale", actorL_morale},
321  {"isinjured", actorL_isinjured},
322  {"isarmed", actorL_isarmed},
323  {"isdead", actorL_isdead},
324  {"isvalidtarget", actorL_isvalidtarget},
325  {nullptr, nullptr}
326 };
327 
331 /* Internal functions. */
332 static int pos3L_register(lua_State* L);
333 static int lua_ispos3(lua_State* L, int index);
334 static pos3_t* lua_topos3(lua_State* L, int index);
335 static pos3_t* lua_pushpos3(lua_State* L, pos3_t* pos);
336 /* Metatable functions. */
337 static int pos3L_tostring(lua_State* L);
338 static int pos3L_goto(lua_State* L);
339 static int pos3L_face(lua_State* L);
340 static int pos3L_distance(lua_State* L);
344 static const luaL_reg pos3L_methods[] = {
345  {"__tostring", pos3L_tostring},
346  {"goto", pos3L_goto},
347  {"face", pos3L_face},
348  {"distance", pos3L_distance},
349  {nullptr, nullptr}
350 };
351 
352 
356 static int AIL_print(lua_State* L);
357 static int AIL_squad(lua_State* L);
358 static int AIL_select(lua_State* L);
359 static int AIL_see(lua_State* L);
360 static int AIL_crouch(lua_State* L);
361 static int AIL_reactionfire(lua_State* L);
362 static int AIL_roundsleft(lua_State* L);
363 static int AIL_canreload(lua_State* L);
364 static int AIL_reload(lua_State* L);
365 static int AIL_positionshoot(lua_State* L);
366 static int AIL_positionhide(lua_State* L);
367 static int AIL_positionherd(lua_State* L);
368 static int AIL_positionapproach(lua_State* L);
369 static int AIL_grabweapon(lua_State* L);
370 static int AIL_missiontargets(lua_State* L);
371 static int AIL_waypoints(lua_State* L);
372 static int AIL_positionmission(lua_State* L);
373 static int AIL_positionwander(lua_State* L);
374 static int AIL_findweapons(lua_State* L);
375 static int AIL_isfighter(lua_State* L);
376 static int AIL_setwaypoint(lua_State* L);
377 static int AIL_difficulty(lua_State* L);
378 static int AIL_positionflee(lua_State* L);
379 static int AIL_weapontype(lua_State* L);
380 static int AIL_actor(lua_State* L);
381 static int AIL_tusforshooting(lua_State* L);
382 static int AIL_class(lua_State* L);
383 static int AIL_hideneeded(lua_State* L);
384 
388 static const luaL_reg AIL_methods[] = {
389  {"print", AIL_print},
390  {"squad", AIL_squad},
391  {"select", AIL_select},
392  {"see", AIL_see},
393  {"crouch", AIL_crouch},
394  {"reactionfire", AIL_reactionfire},
395  {"roundsleft", AIL_roundsleft},
396  {"canreload", AIL_canreload},
397  {"reload", AIL_reload},
398  {"positionshoot", AIL_positionshoot},
399  {"positionhide", AIL_positionhide},
400  {"positionherd", AIL_positionherd},
401  {"positionapproach", AIL_positionapproach},
402  {"grabweapon", AIL_grabweapon},
403  {"missiontargets", AIL_missiontargets},
404  {"waypoints", AIL_waypoints},
405  {"positionmission", AIL_positionmission},
406  {"positionwander", AIL_positionwander},
407  {"findweapons", AIL_findweapons},
408  {"isfighter", AIL_isfighter},
409  {"setwaypoint", AIL_setwaypoint},
410  {"difficulty", AIL_difficulty},
411  {"positionflee", AIL_positionflee},
412  {"weapontype", AIL_weapontype},
413  {"actor", AIL_actor},
414  {"tusforshooting", AIL_tusforshooting},
415  {"class", AIL_class},
416  {"hideneeded", AIL_hideneeded},
417  {nullptr, nullptr}
418 };
419 
420 
430 static int actorL_register (lua_State* L)
431 {
432  /* Create the metatable */
433  luaL_newmetatable(L, ACTOR_METATABLE);
434 
435  /* Create the access table */
436  lua_pushvalue(L, -1);
437  lua_setfield(L, -2, "__index");
438 
439  /* Register the values */
440  luaL_register(L, nullptr, actorL_methods);
441 
442  /* Clean up stack. */
443  lua_pop(L, 1);
444 
445  return 0; /* No error */
446 }
447 
454 static int lua_isactor (lua_State* L, int index)
455 {
456  if (lua_getmetatable(L, index) == 0)
457  return 0;
458  lua_getfield(L, LUA_REGISTRYINDEX, ACTOR_METATABLE);
459 
460  int ret = 0;
461  if (lua_rawequal(L, -1, -2)) /* does it have the correct metatable? */
462  ret = 1;
463 
464  lua_pop(L, 2); /* remove both metatables */
465  return ret;
466 }
467 
471 static aiActor_t* lua_toactor (lua_State* L, int index)
472 {
473  if (lua_isactor(L, index)) {
474  return (aiActor_t*) lua_touserdata(L, index);
475  }
476  luaL_typerror(L, index, ACTOR_METATABLE);
477  return nullptr;
478 }
479 
483 static aiActor_t* lua_pushactor (lua_State* L, aiActor_t* actor)
484 {
485  aiActor_t* a = (aiActor_t*) lua_newuserdata(L, sizeof(aiActor_t));
486  *a = *actor;
487  luaL_getmetatable(L, ACTOR_METATABLE);
488  lua_setmetatable(L, -2);
489  return a;
490 }
491 
495 static int actorL_tostring (lua_State* L)
496 {
497  char buf[MAX_VAR];
498 
499  assert(lua_isactor(L, 1));
500 
501  const aiActor_t* target = lua_toactor(L, 1);
502  Com_sprintf(buf, sizeof(buf), "Actor( %s )", target->actor->chr.name);
503 
504  lua_pushstring(L, buf);
505  return 1;
506 }
507 
511 static int actorL_pos (lua_State* L)
512 {
513  assert(lua_isactor(L, 1));
514 
515  const aiActor_t* target = lua_toactor(L, 1);
516  lua_pushpos3(L, &target->actor->pos);
517  return 1;
518 }
519 
523 static int actorL_shoot (lua_State* L)
524 {
525  assert(lua_isactor(L, 1));
526 
527  /* Target */
528  const aiActor_t* target = lua_toactor(L, 1);
529 
530  /* Number of TU to spend shooting, fire mode will adjust to that. */
531  int tu = AIL_ent->getUsableTUs();
532  if (lua_gettop(L) > 1) {
533  assert(lua_isnumber(L, 2)); /* Must be a number. */
534 
535  tu = std::min(static_cast<int>(lua_tonumber(L, 2)), tu);
536  }
537 
538  const float dist = VectorDist(AIL_ent->origin, target->actor->origin);
539  shoot_types_t bestType = NONE;
540  fireDefIndex_t bestFd = NONE;
541  int bestShots = 0;
542  AIL_GetBestShot(*AIL_ent, *target->actor, tu, dist, bestType, bestFd, bestShots);
543 
544  /* Failure - no weapon. */
545  if (bestType == NONE) {
546  lua_pushboolean(L, 0);
547  return 1;
548  }
549 
550  bool shot = false;
551  while (bestShots > 0) {
552  if (G_IsDead(target->actor))
553  break;
554  bestShots--;
555  shot = G_ClientShoot(*AIL_player, AIL_ent, target->actor->pos, bestType, bestFd, nullptr, true, 0) || shot;
556  }
557 
558  /* Success? */
559  lua_pushboolean(L, shot);
560  return 1;
561 }
562 
566 static int actorL_team (lua_State* L)
567 {
568  assert(lua_isactor(L, 1));
569 
570  const aiActor_t* target = lua_toactor(L, 1);
571  assert(target != nullptr);
572  const char* team = AIL_toTeamString(target->actor->getTeam());
573  lua_pushstring(L, team);
574  return 1;
575 }
576 
580 static int actorL_throwgrenade(lua_State* L)
581 {
582  /* check parameter */
583  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
585  lua_pushboolean(L, 0);
586  return 1;
587  }
588  const aiActor_t* target = lua_toactor(L, 1);
589  assert(target != nullptr);
590 
591  /* Min number of enemies to use grenade */
592  int minNum = 0;
593  if (lua_gettop(L) > 1) {
594  if (!lua_isnumber(L, 2)) { /* Must be a number. */
596  lua_pushboolean(L, 0);
597  return 1;
598  }
599  minNum = static_cast<int>(lua_tonumber(L, 2));
600  }
601 
602  /* Number of TU to spend */
603  int tus = AIL_ent->getUsableTUs();
604  if (lua_gettop(L) > 2) {
605  if (!lua_isnumber(L, 3)) { /* Must be a number. */
607  lua_pushboolean(L, 0);
608  return 1;
609  }
610  tus = std::min(static_cast<int>(lua_tonumber(L, 3)), tus);
611  }
612 
613  /* Check that we have a free hand */
615  const Item* right = AIL_ent->getRightHandItem();
616  if (right)
617  hand = right->isHeldTwoHanded() || AIL_ent->getLeftHandItem() ? CID_MAX : CID_LEFT;
618  if (hand >= CID_MAX) {
619  lua_pushboolean(L, 0);
620  return 1;
621  }
622 
623  /* Check if we have a grenade */
624  Item* grenade = nullptr;
625  const invDef_t* fromCont = AI_SearchGrenade(AIL_ent, &grenade);
626  if (!fromCont || !grenade) {
627  lua_pushboolean(L, 0);
628  return 1;
629  }
630  /* Now check if we can use it */
631  const fireDef_t* fdArray = grenade->getFiredefs();
632  const int invMoveCost = fromCont->out + INVDEF(hand)->in;
633  const shoot_types_t shotType = hand == CID_RIGHT ? ST_RIGHT : ST_LEFT;
634  float dist = VectorDist(AIL_ent->origin, target->actor->origin);
635  const fireDef_t* bestFd = nullptr;
636  for (fireDefIndex_t fdIdx = 0; fdIdx < grenade->ammoDef()->numFiredefs[fdArray->weapFdsIdx]; fdIdx++) {
637  const fireDef_t* fd = &fdArray[fdIdx];
638  const int time = invMoveCost + G_ActorGetModifiedTimeForFiredef(AIL_ent, fd, false);
639  /* Enough TU? */
640  if (time > tus)
641  continue;
642  /* In range? */
643  if (!AI_FighterCheckShoot(AIL_ent, target->actor, fd, dist))
644  continue;
645  /* LOF? */
646  if (!AI_CheckLineOfFire(AIL_ent, target->actor, fd, 1))
647  continue;
648 
649  /* Select the first usable firemode */
650  bestFd = fd;
651  break;
652  }
653  if (!bestFd) {
654  lua_pushboolean(L, 0);
655  return 1;
656  }
657 
658  /* Finally check if we want to use it now */
659  if (bestFd->splrad > 0) {
660  Actor* check = nullptr;
661  int n = 0;
662  while ((check = G_EdictsGetNextLivingActor(check))) {
663  /* check for distance */
664  dist = VectorDist(target->actor->origin, check->origin);
665  dist = dist > UNIT_SIZE / 2 ? dist - UNIT_SIZE / 2 : 0;
666  if (dist > bestFd->splrad)
667  continue;
668 
669  if (!AI_IsHostile(AIL_ent, target->actor)) {
670  lua_pushboolean(L, 0);
671  return 1;
672  }
673  ++n;
674  }
675  /* Check there's large enough group of targets */
676  if (n < minNum) {
677  lua_pushboolean(L, 0);
678  return 1;
679  }
680  }
681 
682  /* Try to move the grenade to the free hand */
683  if(!G_ActorInvMove(AIL_ent, fromCont, grenade, INVDEF(hand), NONE, NONE, true)) {
684  lua_pushboolean(L, 0);
685  return 1;
686  }
687  /* All right use it! */
688  const bool result = G_ClientShoot(*AIL_player, AIL_ent, target->actor->pos, shotType, bestFd->fdIdx, nullptr, true, 0);
689 
690  lua_pushboolean(L, result);
691  return 1;
692 }
693 
697 static int actorL_TU (lua_State* L)
698 {
699  /* check parameter */
700  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
702  lua_pushboolean(L, 0);
703  return 1;
704  }
705  const aiActor_t* actor = lua_toactor(L, 1);
706  assert(actor != nullptr);
707 
708  lua_pushnumber(L, actor->actor->getUsableTUs());
709  return 1;
710 }
711 
715 static int actorL_HP (lua_State* L)
716 {
717  /* check parameter */
718  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
720  lua_pushboolean(L, 0);
721  return 1;
722  }
723  const aiActor_t* actor = lua_toactor(L, 1);
724  assert(actor != nullptr);
725 
726  lua_pushnumber(L, actor->actor->HP);
727  return 1;
728 }
729 
733 static int actorL_morale (lua_State* L)
734 {
735  /* check parameter */
736  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
738  lua_pushboolean(L, 0);
739  return 1;
740  }
741  const aiActor_t* actor = lua_toactor(L, 1);
742  assert(actor != nullptr);
743 
744  const char* morStat = "normal";
745  if (actor->actor->isPanicked())
746  morStat = "panic";
747  else if (actor->actor->isInsane())
748  morStat = "insane";
749  else if (actor->actor->isRaged())
750  morStat = "rage";
751  else if (actor->actor->getMorale() <= mor_brave->integer)
752  morStat = "cower";
753 
754  lua_pushstring(L, morStat);
755  return 1;
756 }
757 
761 static int actorL_isinjured (lua_State* L)
762 {
763  /* check parameter */
764  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
766  lua_pushboolean(L, 0);
767  return 1;
768  }
769  const aiActor_t* actor = lua_toactor(L, 1);
770  assert(actor != nullptr);
771 
772  lua_pushboolean(L, G_IsActorWounded(actor->actor, true)
773  || actor->actor->HP <= actor->actor->chr.maxHP * 0.5);
774  return 1;
775 }
776 
780 static int actorL_isarmed (lua_State* L)
781 {
782  /* check parameter */
783  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
785  lua_pushboolean(L, 0);
786  return 1;
787  }
788  const aiActor_t* actor = lua_toactor(L, 1);
789  assert(actor != nullptr);
790 
791  lua_pushboolean(L, actor->actor->getRightHandItem() ? 1 : 0);
792  lua_pushboolean(L, actor->actor->getLeftHandItem() ? 1 : 0);
793  return 2;
794 }
795 
799 static int actorL_isdead (lua_State* L)
800 {
801  /* check parameter */
802  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
804  lua_pushboolean(L, 0);
805  return 1;
806  }
807  const aiActor_t* actor = lua_toactor(L, 1);
808  assert(actor != nullptr);
809 
810  lua_pushboolean(L, actor->actor->isDead());
811  return 1;
812 }
813 
817 static int actorL_isvalidtarget (lua_State* L)
818 {
819  assert(lua_isactor(L, 1));
820 
821  const aiActor_t* target = lua_toactor(L, 1);
822  assert(target != nullptr);
823  lua_pushboolean(L, AI_IsHostile(AIL_ent, target->actor));
824  return 1;
825 }
826 
827 
837 static int pos3L_register (lua_State* L)
838 {
839  /* Create the metatable */
840  luaL_newmetatable(L, POS3_METATABLE);
841 
842  /* Create the access table */
843  lua_pushvalue(L, -1);
844  lua_setfield(L, -2, "__index");
845 
846  /* Register the values */
847  luaL_register(L, nullptr, pos3L_methods);
848 
849  /* Clean up the stack. */
850  lua_pop(L, 1);
851 
852  return 0; /* No error */
853 }
854 
861 static int lua_ispos3 (lua_State* L, int index)
862 {
863  if (lua_getmetatable(L, index) == 0)
864  return 0;
865  lua_getfield(L, LUA_REGISTRYINDEX, POS3_METATABLE);
866 
867  int ret = 0;
868  if (lua_rawequal(L, -1, -2)) /* does it have the correct metatable? */
869  ret = 1;
870 
871  lua_pop(L, 2); /* remove both metatables */
872  return ret;
873 }
874 
878 static pos3_t* lua_topos3 (lua_State* L, int index)
879 {
880  if (lua_ispos3(L, index)) {
881  return (pos3_t*) lua_touserdata(L, index);
882  }
883  luaL_typerror(L, index, POS3_METATABLE);
884  return nullptr;
885 }
886 
890 static pos3_t* lua_pushpos3 (lua_State* L, pos3_t* pos)
891 {
892  pos3_t* p = (pos3_t*) lua_newuserdata(L, sizeof(pos3_t));
893  memcpy(p, pos, sizeof(*p));
894  luaL_getmetatable(L, POS3_METATABLE);
895  lua_setmetatable(L, -2);
896  return p;
897 }
898 
902 static int pos3L_tostring (lua_State* L)
903 {
904  char buf[MAX_VAR];
905 
906  assert(lua_ispos3(L, 1));
907 
908  const pos3_t* p = lua_topos3(L, 1);
909  Com_sprintf(buf, sizeof(buf), "Pos3( x=%d, y=%d, z=%d )", (*p)[0], (*p)[1], (*p)[2]);
910 
911  lua_pushstring(L, buf);
912  return 1;
913 }
914 
918 static int pos3L_goto (lua_State* L)
919 {
920  assert(lua_ispos3(L, 1));
921 
922  /* Calculate move table. */
923  G_MoveCalc(0, AIL_ent, AIL_ent->pos, AIL_ent->getUsableTUs());
924  gi.MoveStore(level.pathingMap);
925 
926  /* Move. */
927  const pos3_t* pos = lua_topos3(L, 1);
928  /* do the move */
929  for (;;) {
930  if (AIL_ent->isDead())
931  break;
932  G_ClientMove(*AIL_player, 0, AIL_ent, *pos);
933  if (AIL_ent->isSamePosAs(*pos))
934  break;
935  const pos_t length = G_ActorMoveLength(AIL_ent, level.pathingMap, *pos, false);
936  if (length > AIL_ent->getUsableTUs() || length >= ROUTING_NOT_REACHABLE)
937  break;
938  }
939 
940  lua_pushboolean(L, AIL_ent->isSamePosAs(*pos));
941  return 1;
942 }
943 
947 static int pos3L_face (lua_State* L)
948 {
949  assert(lua_ispos3(L, 1));
950 
951  const pos3_t* pos = lua_topos3(L, 1);
952  AI_TurnIntoDirection(AIL_ent, *pos);
953 
954  lua_pushboolean(L, 1);
955  return 1;
956 }
957 
961 static int pos3L_distance (lua_State* L)
962 {
963  assert(lua_ispos3(L, 1));
964 
965  pos3_t* pos = lua_topos3(L, 1);
966  assert(pos != nullptr);
967 
968  ailSortCritType_t distType = AILSC_DIST;
969  if (lua_gettop(L) > 1)
970  distType = AIL_toDistInt(L, 2);
971 
972  switch (distType) {
973  case AILSC_PATH:
974  /* Find a path to the target pos */
975  if (!G_FindPath(0, AIL_ent, AIL_ent->pos, *pos, AIL_ent->isCrouched(), ROUTING_NOT_REACHABLE - 1)) {
976  lua_pushnumber(L, ROUTING_NOT_REACHABLE);
977  return 1;
978  }
979  lua_pushnumber(L, G_ActorMoveLength(AIL_ent, level.pathingMap, *pos, false));
980  return 1;
981  case AILSC_DIST:
982  default:
983  vec3_t to;
984  PosToVec(*pos, to);
985  lua_pushnumber(L, VectorDist(AIL_ent->origin, to));
986  return 1;
987  }
988 }
989 
993 /*
994  * General functions.
995  */
996 
1000 static int AIL_print (lua_State* L)
1001 {
1002  const int n = lua_gettop(L); /* number of arguments */
1003 
1004  for (int i = 1; i <= n; i++) {
1005  const char* s;
1006  bool meta = false;
1007 
1008  lua_pushvalue(L, i); /* value to print */
1009  if (luaL_callmeta(L, -1, "__tostring")) {
1010  s = lua_tostring(L, -1);
1011  meta = true;
1012  } else {
1013  switch (lua_type(L, -1)) {
1014  case LUA_TNUMBER:
1015  case LUA_TSTRING:
1016  s = lua_tostring(L, -1);
1017  break;
1018  case LUA_TBOOLEAN:
1019  s = lua_toboolean(L, -1) ? "true" : "false";
1020  break;
1021  case LUA_TNIL:
1022  s = "nil";
1023  break;
1024 
1025  default:
1026  s = "unknown lua type";
1027  break;
1028  }
1029  }
1030  gi.DPrintf("%s%s", (i > 1) ? "\t" : "", s);
1031  lua_pop(L, 1); /* Pop the value */
1032  if (meta) /* Meta creates an additional string. */
1033  lua_pop(L, 1);
1034  }
1035 
1036  gi.DPrintf("\n");
1037  return 0;
1038 }
1039 
1040 /*
1041  * Player functions.
1042  */
1043 
1047 static int AIL_squad (lua_State* L)
1048 {
1049  if (g_ailua->integer < 2) {
1050  gi.DPrintf("Problem while running lua: attempt to get the player's team while not in team mode.");
1051  lua_pushnil(L);
1052  return 1;
1053  }
1054 
1055  /* New Lua table. */
1056  lua_newtable(L);
1057 
1058  int i = 1; /* LUA indexes starting from one */
1059  Actor* check = nullptr;
1060  while ((check = G_EdictsGetNextActor(check))) {
1061  if (check->getPlayerNum() != AIL_player->getNum())
1062  continue;
1063  lua_pushnumber(L, i++); /* index */
1064  aiActor_t target;
1065  target.actor = check;
1066  lua_pushactor(L, &target); /* value */
1067  lua_rawset(L, -3); /* store the value in the table */
1068  }
1069  return 1; /* Returns the table of actors. */
1070 }
1071 
1075 static int AIL_select (lua_State* L)
1076 {
1077  if (g_ailua->integer < 2) {
1078  gi.DPrintf("Problem while running lua: attempt to select the active AI actor while not in team mode.");
1079  lua_pushnil(L);
1080  } else if (lua_gettop(L) > 0 && lua_isactor(L, 1)) {
1081  aiActor_t* target = lua_toactor(L, 1);
1082  if (target->actor->getPlayerNum() == AIL_player->getNum())
1083  AIL_ent = target->actor;
1084  lua_pushboolean(L, AIL_ent == target->actor);
1085  } else {
1087  lua_pushboolean(L, false);
1088  }
1089  return 1;
1090 }
1091 
1092 /*
1093  * Actor functions
1094  */
1095 
1099 static int AIL_see (lua_State* L)
1100 {
1101  /* Defaults. */
1102  int team = TEAM_ALL;
1103  ailVisType_t vision = AILVT_ALL;
1104  ailSortCritType_t sortCrit = AILSC_DIST;
1105  bool invTeam = false;
1106 
1107  /* Handle parameters. */
1108  if ((lua_gettop(L) > 0)) {
1109  /* Get what to "see" with. */
1110  vision = AIL_toVisInt(L, 1);
1111 
1112  /* We now check for different teams. */
1113  if ((lua_gettop(L) > 1)) {
1114  if (lua_isstring(L, 2)) {
1115  const char* s = lua_tostring(L, 2);
1116  if (s[0] == '-' || s[0] == '~') {
1117  invTeam = true;
1118  ++s;
1119  }
1120  team = AIL_toTeamInt(s, 2);
1121  /* Trying to see no one? */
1122  if (team == TEAM_ALL && invTeam)
1124  } else
1126  }
1127 
1128  /* Sorting criteria */
1129  if ((lua_gettop(L) > 2)) {
1130  sortCrit = AIL_toSortInt(L, 3);
1131  }
1132  }
1133 
1134  int n = 0;
1135  Actor* check = nullptr;
1136  AilSortTable<Actor*> sortTable[MAX_EDICTS];
1137  /* Get visible things. */
1138  const int visDist = G_VisCheckDist(AIL_ent);
1139  /* We are about to check the team view, update it accordingly */
1140  if (vision == AILVT_TEAM)
1142  while ((check = G_EdictsGetNextLivingActor(check))) {
1143  if (AIL_ent == check)
1144  continue;
1145  const float distance = VectorDistSqr(AIL_ent->pos, check->pos);
1146  /* Check for team match if needed. */
1147  if ((team == TEAM_ALL || (check->getTeam() == team ? !invTeam : invTeam))
1148  && (vision == AILVT_ALL
1149  || (vision == AILVT_SIGHT && G_Vis(AIL_ent->getTeam(), AIL_ent, check, VT_NOFRUSTUM))
1150  || (vision == AILVT_TEAM && G_IsVisibleForTeam(check, AIL_ent->getTeam()))
1151  || (vision == AILVT_DIST && distance <= visDist * visDist))) {
1152  switch (sortCrit) {
1153  case AILSC_PATH:
1154  {
1156  if (G_FindPath(0, AIL_ent, AIL_ent->pos, check->pos, false, 0xFE))
1157  move = gi.MoveLength(level.pathingMap, check->pos, 0, false);
1158  sortTable[n].sortLookup = move;
1159  }
1160  break;
1161  case AILSC_HP:
1162  sortTable[n].sortLookup = check->HP;
1163  break;
1164  case AILSC_DIST:
1165  default:
1166  sortTable[n].sortLookup = VectorDistSqr(AIL_ent->pos, check->pos);
1167  break;
1168  }
1169  sortTable[n++].data = check;
1170  }
1171  }
1172 
1173  /* Sort by given criterion - lesser first. */
1174  std::sort(sortTable, sortTable + n);
1175 
1176  /* Now save it in a Lua table. */
1177  lua_newtable(L);
1178  for (int i = 0; i < n; i++) {
1179  lua_pushnumber(L, i + 1); /* index, starts with 1 */
1180  aiActor_t target;
1181  target.actor = sortTable[i].data;
1182  lua_pushactor(L, &target); /* value */
1183  lua_rawset(L, -3); /* store the value in the table */
1184  }
1185  return 1; /* Returns the table of actors. */
1186 }
1187 
1191 static int AIL_crouch (lua_State* L)
1192 {
1193  if (lua_gettop(L) > 0) {
1194  if (lua_isboolean(L, 1)) {
1195  const bool reqState = lua_toboolean(L, 1);
1196  const bool state = AIL_ent->isCrouched();
1197  if (reqState != state)
1198  G_ClientStateChange(*AIL_player, AIL_ent, STATE_CROUCHED, true);
1199  } else
1201  }
1202 
1203  lua_pushboolean(L, AIL_ent->isCrouched());
1204  return 1;
1205 }
1206 
1210 static int AIL_reactionfire (lua_State* L)
1211 {
1212  if (lua_gettop(L) > 0) {
1213  int reactionState = 0;
1214 
1215  if (lua_isstring(L, 1)) {
1216  /* get reaction fire mode */
1217  const char* cmd = lua_tostring(L, 1);
1218  reactionState = Q_streq(cmd, "disable") ? ~STATE_REACTION : STATE_REACTION;
1219  }
1220 
1221  if (reactionState) {
1222  G_ClientStateChange(*AIL_player, AIL_ent, reactionState, true);
1223  } else {
1225  }
1226  }
1227 
1228  lua_pushboolean(L, AIL_ent->isReaction());
1229  return 1;
1230 }
1231 
1235 static int AIL_roundsleft (lua_State* L)
1236 {
1237  /* Right hand */
1238  const Item* rightHand = AIL_ent->getRightHandItem();
1239  if (rightHand && (rightHand->def()->ammo < 1 || rightHand->getAmmoLeft() > 0))
1240  lua_pushnumber(L, rightHand->getAmmoLeft());
1241  else
1242  /* Currently unusable */
1243  lua_pushnil(L);
1244 
1245  /* Left hand */
1246  const Item* leftHand = AIL_ent->getLeftHandItem();
1247  if (leftHand && (leftHand->def()->ammo < 1 || leftHand->getAmmoLeft() > 0))
1248  lua_pushnumber(L, leftHand->getAmmoLeft());
1249  else
1250  lua_pushnil(L);
1251  return 2;
1252 }
1253 
1257 static int AIL_canreload (lua_State* L)
1258 {
1259  lua_pushboolean(L, G_ClientCanReload(AIL_ent, CID_RIGHT));
1260  lua_pushboolean(L, G_ClientCanReload(AIL_ent, CID_LEFT));
1261  return 2;
1262 }
1263 
1267 static int AIL_reload (lua_State* L)
1268 {
1269  containerIndex_t container = CID_RIGHT; /* Default to right hand. */
1270 
1271  if (lua_gettop(L) > 0) {
1272  if (lua_isstring(L, 1)) {
1273  const char* s = lua_tostring(L, 1);
1274 
1275  if (Q_streq(s, "right")) {
1276  container = CID_RIGHT;
1277  } else if (Q_streq(s, "left")) {
1278  container = CID_LEFT;
1279  } else {
1281  return 0;
1282  }
1283  } else {
1285  return 0;
1286  }
1287  }
1288 
1289  AI_TryToReloadWeapon(AIL_ent, container);
1290  return 0;
1291 }
1292 
1296 static int AIL_grabweapon (lua_State* L)
1297 {
1298  lua_pushboolean(L, G_ClientGetWeaponFromInventory(AIL_ent));
1299  return 1;
1300 }
1301 
1305 static int AIL_positionshoot (lua_State* L)
1306 {
1307  /* We need a target. */
1308  assert(lua_isactor(L, 1));
1309  aiActor_t* target = lua_toactor(L, 1);
1310 
1311  /* Make things more simple. */
1312  Actor* actor = AIL_ent;
1313 
1314  /* Shooting strategy */
1315  ailShootPosType_t posType = AILSP_FAST;
1316  if ((lua_gettop(L) > 1))
1317  posType = AIL_toShotPInt(L, 2);
1318 
1319  /* Number of TU to spend shooting, to make sure we have enough tus to actually fire. */
1320  int tus = actor->getUsableTUs();
1321  if (lua_gettop(L) > 2) {
1322  assert(lua_isnumber(L, 3)); /* Must be a number. */
1323 
1324  tus = std::min(static_cast<int>(lua_tonumber(L, 3)), tus);
1325  }
1326 
1327  /* Don't shoot units under our control */
1328  if (!AI_IsHostile(actor, target->actor)) {
1329  lua_pushboolean(L, 0);
1330  return 1;
1331  }
1332 
1333  shoot_types_t shootType = ST_RIGHT;
1334  const Item* item = AI_GetItemForShootType(shootType, AIL_ent);
1335  if (item == nullptr) {
1336  shootType = ST_LEFT;
1337  item = AI_GetItemForShootType(shootType, AIL_ent);
1338  }
1339 
1340  /* Check for weapon. */
1341  if (item == nullptr) {
1342  lua_pushboolean(L, 0);
1343  return 1;
1344  }
1345  const fireDef_t* fd = item->getFastestFireDef();
1346  if (fd == nullptr) {
1347  lua_pushboolean(L, 0);
1348  return 1;
1349  }
1350 
1351  int fdTime = G_ActorGetModifiedTimeForFiredef(AIL_ent, fd, false);
1352  if (tus - fdTime <= 0) {
1353  lua_pushboolean(L, 0);
1354  return 1;
1355  }
1356 
1357  /* Calculate move table. */
1358  G_MoveCalc(0, actor, actor->pos, tus);
1359  gi.MoveStore(level.pathingMap);
1360 
1361  /* set borders */
1362  const int rad = (tus + 1) / TU_MOVE_STRAIGHT;
1363 
1364  pos3_t oldPos;
1365  vec3_t oldOrigin;
1366  VectorCopy(actor->pos, oldPos);
1367  VectorCopy(actor->origin, oldOrigin);
1368 
1369  /* evaluate moving to every possible location in the search area,
1370  * including combat considerations */
1371  float bestScore = 0.0f;
1372  pos3_t to, bestPos;
1373  VectorSet(bestPos, 0, 0, PATHFINDING_HEIGHT);
1374  AiAreaSearch searchArea(oldPos, rad);
1375  while (searchArea.getNext(to)) {
1376  actor->setOrigin(to);
1377  const pos_t move = G_ActorMoveLength(actor, level.pathingMap, to, true);
1378  if (move > tus || move == ROUTING_NOT_REACHABLE)
1379  continue;
1380  if (!AI_CheckPosition(actor, actor->pos))
1381  continue;
1382  /* Can we see the target? */
1383  if (!G_IsVisibleForTeam(target->actor, actor->getTeam()) && G_ActorVis(actor, target->actor, true) < ACTOR_VIS_10)
1384  continue;
1385 
1386  const float dist = VectorDist(actor->origin, target->actor->origin);
1387  int dummy = NONE;
1388  const float bestDmg = AIL_GetBestShot(*actor, *target->actor, tus - move, dist, dummy, dummy, dummy);
1389  if (dummy == NONE)
1390  continue;
1391 
1392  float score;
1393  switch (posType) {
1394  case AILSP_NEAR:
1395  score = -dist;
1396  break;
1397  case AILSP_FAR:
1398  score = dist;
1399  break;
1400  case AILSP_DMG:
1401  score = bestDmg;
1402  break;
1403  case AILSP_FAST:
1404  default:
1405  score = -move;
1406  break;
1407  }
1408  if (score > bestScore || bestPos[2] >= PATHFINDING_HEIGHT) {
1409  VectorCopy(to, bestPos);
1410  bestScore = score;
1411  }
1412  }
1413 
1414  VectorCopy(oldPos, actor->pos);
1415  VectorCopy(oldOrigin, actor->origin);
1416 
1417  /* No position found in range. */
1418  if (bestPos[2] >= PATHFINDING_HEIGHT) {
1419  lua_pushboolean(L, 0);
1420  return 1;
1421  }
1422 
1423  /* Return the spot. */
1424  lua_pushpos3(L, &bestPos);
1425  return 1;
1426 }
1427 
1433 static int AIL_positionhide (lua_State* L)
1434 {
1435  int hidingTeam = AI_GetHidingTeam(AIL_ent);
1436 
1437  /* parse parameter */
1438  if (lua_gettop(L)) {
1439  if (lua_isstring(L, 1)) {
1440  const char* s = lua_tostring(L, 1);
1441  bool invTeam = false;
1442  if (s[0] == '-' || s[0] == '~') {
1443  invTeam = true;
1444  ++s;
1445  }
1446  const int team = AIL_toTeamInt(s, 1);
1447  if (team == TEAM_ALL)
1449  else if (invTeam)
1450  hidingTeam = -team;
1451  else
1452  hidingTeam = team;
1453  } else {
1455  }
1456  }
1457 
1458  int tus = AIL_ent->getUsableTUs();
1459  /* parse parameter */
1460  if (lua_gettop(L) > 1) {
1461  if (lua_isnumber(L, 2)) {
1462  tus = std::min(static_cast<int>(lua_tonumber(L, 2)), tus);
1463  } else {
1465  }
1466  }
1467 
1468  pos3_t save;
1469  VectorCopy(AIL_ent->pos, save);
1470 
1471  if (AI_FindHidingLocation(hidingTeam, AIL_ent, AIL_ent->pos, tus)) {
1472  /* Return the spot. */
1473  lua_pushpos3(L, &AIL_ent->pos);
1474  } else {
1475  lua_pushboolean(L, 0);
1476  }
1477  AIL_ent->setOrigin(save);
1478  return 1;
1479 }
1480 
1489 static int AIL_positionherd (lua_State* L)
1490 {
1491  /* check parameter */
1492  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
1494  lua_pushboolean(L, 0);
1495  return 1;
1496  }
1497  const aiActor_t* target = lua_toactor(L, 1);
1498 
1499  int tus = AIL_ent->getUsableTUs();
1500  /* parse parameter */
1501  if (lua_gettop(L) > 1) {
1502  if (lua_isnumber(L, 2)) {
1503  tus = std::min(static_cast<int>(lua_tonumber(L, 2)), tus);
1504  } else {
1506  }
1507  }
1508 
1509  bool inverse = false;
1510  if (lua_gettop(L) > 2) {
1511  if (lua_isboolean(L, 3))
1512  inverse = lua_toboolean(L, 3);
1513  else
1515  }
1516 
1517  pos3_t save;
1518  VectorCopy(AIL_ent->pos, save);
1519  if (AI_FindHerdLocation(AIL_ent, AIL_ent->pos, target->actor->origin, tus, inverse)) {
1520  lua_pushpos3(L, &AIL_ent->pos);
1521  } else {
1522  lua_pushboolean(L, 0);
1523  }
1524  AIL_ent->setOrigin(save);
1525  return 1;
1526 }
1527 
1531 static int AIL_positionapproach (lua_State* L)
1532 {
1533  /* check parameter */
1534  if (!(lua_gettop(L) && lua_ispos3(L, 1))) {
1536  lua_pushboolean(L, 0);
1537  return 1;
1538  }
1539 
1540  const pos3_t* target = lua_topos3(L, 1);
1541  assert(target != nullptr);
1542 
1543  int tus = AIL_ent->getUsableTUs();
1544  if (lua_gettop(L) > 1) {
1545  if (lua_isnumber(L, 2))
1546  tus = std::min(static_cast<int>(lua_tonumber(L, 2)), tus);
1547  else
1549  }
1550 
1551  bool hide = false;
1552  if (lua_gettop(L) > 2){
1553  if (lua_isboolean(L, 3))
1554  hide = lua_toboolean(L, 3);
1555  else
1557  }
1558 
1559  /* Find a path to the target actor */
1560  const int maxTUs = ROUTING_NOT_REACHABLE - 1;
1561  pos3_t to;
1562  VectorCopy(*target, to);
1563  byte crouchingState = AIL_ent->isCrouched() ? 1 : 0;
1564  if (!G_FindPath(0, AIL_ent, AIL_ent->pos, to, crouchingState, maxTUs)) {
1565  /* Not found */
1566  lua_pushboolean(L, 0);
1567  return 1;
1568  }
1569 
1570  /* Find the farthest we can go with current TUs */
1571  int dvec;
1572  while ((dvec = gi.MoveNext(level.pathingMap, to, crouchingState)) != ROUTING_UNREACHABLE) {
1573  /* Note: here we skip the first position so we don't try to walk into the target */
1574  PosSubDV(to, crouchingState, dvec);
1575  if (hide && (G_TestVis(AI_GetHidingTeam(AIL_ent), AIL_ent, VT_PERISHCHK | VT_NOFRUSTUM) & VS_YES))
1576  continue;
1577  if (!AI_CheckPosition(AIL_ent, to))
1578  continue;
1579  const byte length = G_ActorMoveLength(AIL_ent, level.pathingMap, to, false);
1580  if (length <= tus)
1581  break;
1582  /* We are going backwards to the origin. */
1583  }
1584 
1585  if (AIL_ent->isSamePosAs(to))
1586  lua_pushboolean(L, 0);
1587  else
1588  lua_pushpos3(L, &to);
1589  return 1;
1590 }
1591 
1595 static int AIL_missiontargets (lua_State* L)
1596 {
1597 
1598  /* Defaults. */
1599  int team = TEAM_ALL;
1600  ailVisType_t vision = AILVT_ALL;
1601  ailSortCritType_t sortCrit = AILSC_DIST;
1602  bool invTeam = false;
1603 
1604  /* Handle parameters. */
1605  if ((lua_gettop(L) > 0)) {
1606  /* Get what to "see" with. */
1607  vision = AIL_toVisInt(L, 1);
1608 
1609  /* We now check for different teams. */
1610  if ((lua_gettop(L) > 1)) {
1611  if (lua_isstring(L, 2)) {
1612  const char* s = lua_tostring(L, 2);
1613  if (s[0] == '-' || s[0] == '~') {
1614  invTeam = true;
1615  ++s;
1616  }
1617  team = AIL_toTeamInt(s, 2);
1618  /* Trying to see no one? */
1619  if (team == TEAM_ALL && invTeam)
1621  } else
1623  }
1624 
1625  /* Sorting criteria */
1626  if ((lua_gettop(L) > 2))
1627  sortCrit = AIL_toDistInt(L, 3);
1628  }
1629 
1630  int n = 0;
1631  AilSortTable<Edict*> sortTable[MAX_EDICTS];
1632  /* Get visible things. */
1633  const int visDist = G_VisCheckDist(AIL_ent);
1634  Edict* mission = nullptr;
1635  while ((mission = G_EdictsGetNextInUse(mission))) {
1636  if (mission->type != ET_MISSION)
1637  continue;
1638  const float distance = VectorDistSqr(AIL_ent->pos, mission->pos);
1639  /* Check for team match if needed. */
1640  if ((team == TEAM_ALL || (mission->getTeam() == team ? !invTeam : invTeam))
1641  && (vision == AILVT_ALL
1642  || (vision == AILVT_SIGHT && !G_TestLineWithEnts(AIL_ent->origin, mission->origin))
1643  || (vision == AILVT_DIST && distance <= visDist * visDist))) {
1644  switch (sortCrit) {
1645  case AILSC_PATH:
1646  {
1648  if (G_FindPath(0, AIL_ent, AIL_ent->pos, mission->pos, false, ROUTING_NOT_REACHABLE - 1))
1649  move = gi.MoveLength(level.pathingMap, mission->pos, 0, false);
1650  sortTable[n].sortLookup = move;
1651  }
1652  break;
1653  case AILSC_DIST:
1654  default:
1655  sortTable[n].sortLookup = VectorDistSqr(AIL_ent->pos, mission->pos);
1656  break;
1657  }
1658  sortTable[n++].data = mission;
1659  }
1660  }
1661 
1662  /* Sort by given criterion - lesser first. */
1663  std::sort(sortTable, sortTable + n);
1664 
1665  /* Now save it in a Lua table. */
1666  lua_newtable(L);
1667  for (int i = 0; i < n; i++) {
1668  lua_pushnumber(L, i + 1); /* index, starts with 1 */
1669  lua_pushpos3(L, &sortTable[i].data->pos); /* value */
1670  lua_rawset(L, -3); /* store the value in the table */
1671  }
1672  return 1; /* Returns the table of positions. */
1673 }
1674 
1678 static int AIL_waypoints (lua_State* L)
1679 {
1680  const float minEnemyDist = 160.0f;
1681  /* Min distance to waypoint */
1682  float minDist = 800.0f;
1683  if (lua_gettop(L) > 0) {
1684  if (lua_isnumber(L, 1))
1685  minDist = lua_tonumber(L, 1);
1686  else
1688  }
1689 
1690  /* Sorting criteria */
1691  ailSortCritType_t sortCrit = AILSC_DIST;
1692  if ((lua_gettop(L) > 1))
1693  sortCrit = AIL_toDistInt(L, 2);
1694 
1695  int n = 0;
1696  AilSortTable<Edict*> sortTable[MAX_EDICTS];
1697  for (Edict* checkPoint = level.ai_waypointList; checkPoint != nullptr; checkPoint = checkPoint->groupChain) {
1698  if (checkPoint->inuse)
1699  continue;
1700  if (checkPoint->getTeam() != AIL_ent->getTeam())
1701  continue;
1702  /* Don't walk to enemy ambush */
1703  Actor* check = nullptr;
1704  bool ambush = false;
1705  while ((check = G_EdictsGetNextLivingActorOfTeam(check, TEAM_ALIEN))) {
1706  const float dist = VectorDist(AIL_ent->origin, check->origin);
1707  /* @todo add visibility check here? */
1708  if (dist < minEnemyDist) {
1709  ambush = true;
1710  break;
1711  }
1712  }
1713  if (ambush)
1714  continue;
1715  switch (sortCrit) {
1716  case AILSC_PATH:
1717  {
1719  if (G_FindPath(0, AIL_ent, AIL_ent->pos, checkPoint->pos, false, ROUTING_NOT_REACHABLE - 1))
1720  move = gi.MoveLength(level.pathingMap, checkPoint->pos, 0, false);
1721  if (move < minDist * TU_MOVE_STRAIGHT)
1722  continue;
1723  if (checkPoint->count < AIL_ent->count) {
1724  sortTable[n].sortLookup = move;
1725  sortTable[++n].data = checkPoint;
1726  }
1727  }
1728  break;
1729  case AILSC_DIST:
1730  default:
1731  {
1732  const float dist = VectorDist(AIL_ent->origin, checkPoint->origin);
1733  if (dist < minDist * UNIT_SIZE)
1734  continue;
1735  if (checkPoint->count < AIL_ent->count) {
1736  sortTable[n].sortLookup = dist;
1737  sortTable[++n].data = checkPoint;
1738  }
1739  }
1740  break;
1741  }
1742  }
1743 
1744  /* Sort by distance */
1745  std::sort(sortTable, sortTable + n);
1746 
1747  /* Now save it in a Lua table. */
1748  lua_newtable(L);
1749  for (int i = 0; i < n; i++) {
1750  lua_pushnumber(L, i + 1); /* index, starts with 1 */
1751  lua_pushpos3(L, &sortTable[i].data->pos); /* value */
1752  lua_rawset(L, -3); /* store the value in the table */
1753  }
1754  return 1; /* Returns the table of positions. */
1755 }
1756 
1761 static int AIL_positionmission (lua_State* L)
1762 {
1763  /* check parameter */
1764  if (!(lua_gettop(L) && lua_ispos3(L, 1))) {
1766  lua_pushboolean(L, 0);
1767  return 1;
1768  }
1769  const pos3_t* target = lua_topos3(L, 1);
1770  int tus = AIL_ent->getUsableTUs();
1771  if (lua_gettop(L) > 1) {
1772  if (lua_isnumber(L, 2))
1773  tus = lua_tonumber(L, 2);
1774  else
1776  }
1777  G_MoveCalc(0, AIL_ent, AIL_ent->pos, tus);
1778  gi.MoveStore(level.pathingMap);
1779 
1780  pos3_t oldPos;
1781  VectorCopy(AIL_ent->pos, oldPos);
1782  int radius = 3;
1783  const Edict* const mission = G_GetEdictFromPos(*target, ET_MISSION);
1784  if (mission)
1785  radius = mission->radius;
1786  if (AI_FindMissionLocation(AIL_ent, *target, tus, radius))
1787  lua_pushpos3(L, &AIL_ent->pos);
1788  else
1789  lua_pushboolean(L, 0);
1790 
1791  AIL_ent->setOrigin(oldPos);
1792  return 1;
1793 }
1794 
1799 static int AIL_positionwander (lua_State* L)
1800 {
1801  /* Calculate move table. */
1802  G_MoveCalc(0, AIL_ent, AIL_ent->pos, AIL_ent->getUsableTUs());
1803  gi.MoveStore(level.pathingMap);
1804 
1805  /* Set defaults */
1806  int radius = (AIL_ent->getUsableTUs() + 1) / TU_MOVE_STRAIGHT;
1807  pos3_t center;
1808  VectorCopy(AIL_ent->pos, center);
1809  int method = AILPW_RAND;
1810  int tus = AIL_ent->getUsableTUs();
1811 
1812  /* Check parameters */
1813  if (lua_gettop(L) > 0)
1814  method = AIL_toWanderPInt(L, 1);
1815  if (lua_gettop(L) > 1) {
1816  if (lua_isnumber(L, 2))
1817  radius = lua_tonumber(L, 2);
1818  else
1820  }
1821  if (lua_gettop(L) > 2) {
1822  if (lua_ispos3(L, 3))
1823  VectorCopy(*lua_topos3(L, 3), center);
1824  else
1826  }
1827 
1828  if (lua_gettop(L) > 3) {
1829  if (lua_isnumber(L, 4))
1830  tus = std::min(static_cast<int>(lua_tonumber(L, 4)), tus);
1831  else
1833  }
1834 
1835  vec3_t d;
1836  if (method > 0)
1837  VectorSubtract(AIL_ent->pos, center, d);
1838  const int cDir = method > 0 ? (VectorEmpty(d) ? AIL_ent->dir : AngleToDir(static_cast<int>(atan2(d[1], d[0]) * todeg))) : NONE;
1839  float bestScore = 0;
1840  pos3_t bestPos = {0, 0, PATHFINDING_HEIGHT};
1841  pos3_t pos;
1842  AiAreaSearch searchArea(center, radius);
1843  while (searchArea.getNext(pos)) {
1844  const pos_t move = G_ActorMoveLength(AIL_ent, level.pathingMap, pos, true);
1845  if (move >= ROUTING_NOT_REACHABLE || move > tus)
1846  continue;
1847  if (!AI_CheckPosition(AIL_ent, pos))
1848  continue;
1849  float score = 0.0f;
1850  switch (method) {
1851  case AILPW_RAND:
1852  score = rand();
1853  break;
1854  case AILPW_CW:
1855  case AILPW_CCW: {
1856  score = VectorDistSqr(center, pos);
1857  VectorSubtract(pos, center, d);
1858  int dir = AngleToDir(static_cast<int>(atan2(d[1], d[0]) * todeg));
1859  if (!(method == AILPW_CW && dir == dvright[cDir]) && !(method == AILPW_CCW && dir == dvleft[cDir]))
1860  for (int n = 1; n < 8; ++n) {
1861  dir = method == 1 ? dvleft[dir] : dvright[dir];
1862  score /= pow(n * 2.0f, 2);
1863  if ((method == 1 && dir == dvright[cDir]) || (method == 2 && dir == dvleft[cDir]))
1864  break;
1865  }
1866  }
1867  break;
1868  }
1869  if (score > bestScore) {
1870  bestScore = score;
1871  VectorCopy(pos, bestPos);
1872  }
1873  }
1874 
1875  if (bestPos[2] >= PATHFINDING_HEIGHT) {
1876  lua_pushboolean(L, 0);
1877  return 1;
1878  }
1879  lua_pushpos3(L, &bestPos);
1880  return 1;
1881 }
1882 
1886 static int AIL_findweapons (lua_State* L)
1887 {
1888  bool full = false;
1889  if (lua_gettop(L) > 0) {
1890  if (lua_isboolean(L, 1))
1891  full = lua_toboolean(L, 1);
1892  else
1894  }
1895 
1896  AilSortTable<Edict*> sortTable[MAX_EDICTS];
1897  int n = 0;
1898  Edict* check = nullptr;
1899  while ((check = G_EdictsGetNextInUse(check))) {
1900  if (check->type != ET_ITEM)
1901  continue;
1902  if(!AI_CheckPosition(AIL_ent, check->pos))
1903  continue;
1904  if (!G_FindPath(0, AIL_ent, AIL_ent->pos, check->pos, AIL_ent->isCrouched(), ROUTING_NOT_REACHABLE - 1))
1905  continue;
1906  const pos_t move = G_ActorMoveLength(AIL_ent, level.pathingMap, check->pos, false);
1907  if (full || move <= AIL_ent->getUsableTUs() - INVDEF(CID_FLOOR)->out - INVDEF(CID_RIGHT)->in) {
1908  for (const Item* item = check->getFloor(); item; item = item->getNext()) {
1910  if (item->isWeapon() && (item->getAmmoLeft() > 0 || item->def()->ammo <= 0)) {
1911  sortTable[n].data = check;
1912  sortTable[n++].sortLookup = move;
1913  break;
1914  }
1915  }
1916  }
1917  }
1918 
1919  /* Sort by distance */
1920  std::sort(sortTable, sortTable + n);
1921 
1922  /* Now save it in a Lua table. */
1923  lua_newtable(L);
1924  for (int i = 0; i < n; i++) {
1925  lua_pushnumber(L, i + 1); /* index, starts with 1 */
1926  lua_pushpos3(L, &sortTable[i].data->pos); /* value */
1927  lua_rawset(L, -3); /* store the value in the table */
1928  }
1929  return 1; /* Returns the table of positions. */
1930 }
1931 
1935 static int AIL_isfighter (lua_State* L)
1936 {
1937  const bool result = AIL_ent->chr.teamDef->weapons || AIL_ent->chr.teamDef->onlyWeapon;
1938  lua_pushboolean(L, result);
1939  return 1;
1940 }
1941 
1945 static int AIL_setwaypoint (lua_State* L)
1946 {
1947  /* No waypoint, reset the count value to restart the search */
1948  if (lua_gettop(L) < 1 || lua_isnil(L, 1)) {
1949  AIL_ent->count = 100;
1950  lua_pushboolean(L, 1);
1951  } else if (lua_ispos3(L, 1)){
1952  pos3_t pos;
1954  Edict* waypoint = G_GetEdictFromPos(pos, ET_CIVILIANTARGET);
1955  if (waypoint != nullptr) {
1956  AIL_ent->count = waypoint->count;
1957  lua_pushboolean(L, 1);
1958  } else
1959  lua_pushboolean(L, 0);
1960  } else
1961  lua_pushboolean(L, 0);
1962 
1963  return 1;
1964 }
1965 
1969 static int AIL_difficulty (lua_State* L)
1970 {
1971  lua_pushnumber(L, g_difficulty->value);
1972  return 1;
1973 }
1974 
1978 static int AIL_positionflee (lua_State* L)
1979 {
1980  int tus = AIL_ent->getUsableTUs();
1981  if (lua_gettop(L)) {
1982  if (lua_isnumber(L, 1))
1983  tus = std::min(static_cast<int>(lua_tonumber(L, 1)), tus);
1984  else
1986  }
1987 
1988  /* Calculate move table. */
1989  G_MoveCalc(0, AIL_ent, AIL_ent->pos, AIL_ent->getUsableTUs());
1990  pos3_t oldPos;
1991  VectorCopy(AIL_ent->pos, oldPos);
1992 
1993  const int radius = (tus + 1) / TU_MOVE_STRAIGHT;
1994  float bestScore = -1;
1995  pos3_t bestPos = {0, 0, PATHFINDING_HEIGHT};
1996  AiAreaSearch searchArea(AIL_ent->pos, radius);
1997  while (searchArea.getNext(AIL_ent->pos)) {
1998  const pos_t move = G_ActorMoveLength(AIL_ent, level.pathingMap, AIL_ent->pos, false);
1999  if (move >= ROUTING_NOT_REACHABLE || move > tus)
2000  continue;
2001  if (!AI_CheckPosition(AIL_ent, AIL_ent->pos))
2002  continue;
2003  float minDistFoe = -1.0f, minDistFriend = -1.0f;
2004  Actor* check = nullptr;
2005  while ((check = G_EdictsGetNextLivingActor(check))) {
2006  const float dist = VectorDist(AIL_ent->origin, check->origin);
2007  if (check->isSameTeamAs(AIL_ent)) {
2008  if (dist < minDistFriend || minDistFriend < 0.0f)
2009  minDistFriend = dist;
2010  } else if (AI_IsHostile(AIL_ent, check) || AIL_ent->isPanicked()) {
2011  if (dist < minDistFoe || minDistFoe < 0.0f)
2012  minDistFoe = dist;
2013  }
2014  }
2015  float score = minDistFoe - (minDistFriend / GRID_WIDTH);
2016  /* Try to hide */
2017  AIL_ent->calcOrigin();
2018  if (G_TestVis(AI_GetHidingTeam(AIL_ent), AIL_ent, VT_PERISHCHK | VT_NOFRUSTUM) & VS_YES)
2019  score /= UNIT_SIZE;
2020  if (score > bestScore) {
2021  bestScore = score;
2022  VectorCopy(AIL_ent->pos, bestPos);
2023  }
2024  }
2025  AIL_ent->setOrigin(oldPos);
2026 
2027  if (bestPos[2] == PATHFINDING_HEIGHT) {
2028  lua_pushboolean(L, 0);
2029  } else {
2030  lua_pushpos3(L, &bestPos);
2031  }
2032 
2033  return 1;
2034 }
2035 
2039 static int AIL_weapontype (lua_State* L)
2040 {
2041  const Item* right = AIL_ent->getRightHandItem();
2042  const Item* left = AIL_ent->getLeftHandItem();
2043 
2044  lua_pushstring(L, right ? right->def()->type : "none");
2045  lua_pushstring(L, left ? left->def()->type : "none");
2046 
2047  return 2;
2048 }
2049 
2053 static int AIL_actor (lua_State* L)
2054 {
2055  aiActor_t actor = {AIL_ent};
2056  lua_pushactor(L, &actor);
2057  return 1;
2058 }
2062 static int AIL_tusforshooting (lua_State* L)
2063 {
2064  int bestTUs = 256;
2065  const Item* weapon = AIL_ent->getRightHandItem();
2066  if (weapon) {
2067  const fireDef_t* fd = weapon->getFastestFireDef();
2068  if (fd)
2069  bestTUs = fd->time;
2070  }
2071  weapon = AIL_ent->getLeftHandItem();
2072  if (weapon) {
2073  const fireDef_t* fd = weapon->getFastestFireDef();
2074  if (fd) {
2075  const int tus = weapon->getFastestFireDef()->time;
2076  if (tus < bestTUs)
2077  bestTUs = tus;
2078  }
2079  }
2080 
2081  lua_pushnumber(L, bestTUs);
2082  return 1;
2083 }
2084 
2088 static int AIL_class (lua_State* L)
2089 {
2090  lua_pushstring(L, AIL_ent->AI.subtype);
2091  return 1;
2092 }
2093 
2097 static int AIL_hideneeded (lua_State* L)
2098 {
2099  lua_pushboolean(L, AI_HideNeeded(AIL_ent));
2100  return 1;
2101 }
2102 
2108 void AIL_ActorThink (Player& player, Actor* actor)
2109 {
2110  /* Set the global player and edict */
2111  AIL_ent = actor;
2112  AIL_player = &player;
2113 
2114  /* Try to run the function. */
2115  lua_getglobal(ailState, actor->AI.type);
2116  if (lua_istable(ailState, -1)) {
2117  lua_getfield(ailState, -1, "think");
2118  if (lua_pcall(ailState, 0, 0, 0)) { /* error has occured */
2119  gi.DPrintf("Error while running Lua: %s\n",
2120  lua_isstring(ailState, -1) ? lua_tostring(ailState, -1) : "Unknown Error");
2121  }
2122  } else {
2123  gi.DPrintf("Error while running Lua: AI for %s not found!\n", actor->AI.type);
2124  }
2125 
2126  /* Cleanup */
2127  AIL_ent = nullptr;
2128  AIL_player = nullptr;
2129 }
2130 
2134 static const char* AIL_GetAIType (const int team)
2135 {
2136  const char* type;
2137  switch (team) {
2138  case TEAM_ALIEN:
2139  type = "alien";
2140  break;
2141  case TEAM_CIVILIAN:
2142  type = "civilian";
2143  break;
2144  case TEAM_PHALANX:
2145  default: /* Default to "soldier" AI for multiplayer teams */
2146  type = "soldier";
2147  break;
2148  }
2149  return type;
2150 }
2151 
2156 bool AIL_TeamThink (Player& player)
2157 {
2158  /* Set the global player */
2159  AIL_player = &player;
2160  AIL_ent = nullptr;
2161 
2162  bool thinkAgain = false;
2163  /* Try to run the function. */
2164  lua_getglobal(ailState, AIL_GetAIType(player.getTeam()));
2165  if (lua_istable(ailState, -1)) {
2166  lua_getfield(ailState, -1, "team_think");
2167  if (lua_pcall(ailState, 0, 1, 0)) { /* error has occured */
2168  gi.DPrintf("Error while running Lua: %s\n",
2169  lua_isstring(ailState, -1) ? lua_tostring(ailState, -1) : "Unknown Error");
2170  } else
2171  thinkAgain = lua_toboolean(ailState, -1);
2172  } else {
2173  gi.DPrintf("Error while running Lua: AI for %s not found!\n", AIL_toTeamString(player.getTeam()));
2174  }
2175 
2176  /* Cleanup */
2177  AIL_player = nullptr;
2178  AIL_ent = nullptr;
2179  return thinkAgain;
2180 }
2181 
2185 static lua_State* AIL_InitLua () {
2186  /* Create the Lua state */
2187  lua_State* newState = luaL_newstate();
2188 
2189  /* Register metatables. */
2190  actorL_register(newState);
2191  pos3L_register(newState);
2192 
2193  /* Register libraries. */
2194  luaL_register(newState, AI_METATABLE, AIL_methods);
2195 
2196  return newState;
2197 }
2203 int AIL_InitActor (Actor* actor)
2204 {
2205  /* Prepare the AI */
2206  AI_t* AI = &actor->AI;
2207  Q_strncpyz(AI->type, AIL_GetAIType(actor->getTeam()), sizeof(AI->type));
2208  Q_strncpyz(AI->subtype, actor->chr.teamDef->id, sizeof(AI->subtype));
2209 
2210  /* Create the a new Lua state if needed */
2211  if (ailState == nullptr)
2212  ailState = AIL_InitLua();
2213 
2214  if (ailState == nullptr) {
2215  gi.DPrintf("Unable to create Lua state.\n");
2216  return -1;
2217  }
2218 
2219  /* Load the AI if needed */
2220  lua_getglobal(ailState, AI->type);
2221  if (!lua_istable(ailState, -1)) {
2222  char path[MAX_VAR];
2223  Com_sprintf(path, sizeof(path), "ai/%s.lua", AI->type);
2224  char* fbuf;
2225  const int size = gi.FS_LoadFile(path, (byte**) &fbuf);
2226  if (size == 0) {
2227  gi.DPrintf("Unable to load Lua file '%s'.\n", path);
2228  return -1;
2229  }
2230  if (luaL_dobuffer(ailState, fbuf, size, path)) {
2231  gi.DPrintf("Unable to parse Lua file '%s'\n", path);
2232  gi.DPrintf("%s\n", lua_isstring(ailState, -1) ? lua_tostring(ailState, -1) : "Unknown Error");
2233  gi.FS_FreeFile(fbuf);
2234  return -1;
2235  }
2236  lua_setglobal(ailState, AI->type);
2237  gi.FS_FreeFile(fbuf);
2238  } else {
2239  lua_pop(ailState, 1);
2240  }
2241 
2242  return 0;
2243 }
2244 
2245 void AIL_Init (void)
2246 {
2247  gi.RegisterConstInt("luaaiteam::phalanx", TEAM_PHALANX);
2248  gi.RegisterConstInt("luaaiteam::civilian", TEAM_CIVILIAN);
2249  gi.RegisterConstInt("luaaiteam::alien", TEAM_ALIEN);
2250  gi.RegisterConstInt("luaaiteam::all", TEAM_ALL);
2251 
2252  gi.RegisterConstInt("luaaivis::all", AILVT_ALL);
2253  gi.RegisterConstInt("luaaivis::sight", AILVT_SIGHT);
2254  gi.RegisterConstInt("luaaivis::team", AILVT_TEAM);
2255  gi.RegisterConstInt("luaaivis::extra", AILVT_DIST);
2256 
2257  gi.RegisterConstInt("luaaisort::dist", AILSC_DIST);
2258  gi.RegisterConstInt("luaaisort::path", AILSC_PATH);
2259  gi.RegisterConstInt("luaaisort::HP", AILSC_HP);
2260 
2261  gi.RegisterConstInt("luaaidist::dist", AILSC_DIST);
2262  gi.RegisterConstInt("luaaidist::path", AILSC_PATH);
2263 
2264  gi.RegisterConstInt("luaaishot::fastest", AILSP_FAST);
2265  gi.RegisterConstInt("luaaishot::nearest", AILSP_NEAR);
2266  gi.RegisterConstInt("luaaishot::farthest", AILSP_FAR);
2267  gi.RegisterConstInt("luaaishot::best_dam", AILSP_DMG);
2268 
2269  gi.RegisterConstInt("luaaiwander::rand", AILPW_RAND);
2270  gi.RegisterConstInt("luaaiwander::CW", AILPW_CW);
2271  gi.RegisterConstInt("luaaiwander::CCW", AILPW_CCW);
2272 
2273  ailState = nullptr;
2274 }
2275 
2276 void AIL_Shutdown (void)
2277 {
2278  gi.UnregisterConstVariable("luaaiteam::phalanx");
2279  gi.UnregisterConstVariable("luaaiteam::civilian");
2280  gi.UnregisterConstVariable("luaaiteam::alien");
2281  gi.UnregisterConstVariable("luaaiteam::all");
2282 
2283  gi.UnregisterConstVariable("luaaivis::all");
2284  gi.UnregisterConstVariable("luaaivis::sight");
2285  gi.UnregisterConstVariable("luaaivis::team");
2286  gi.UnregisterConstVariable("luaaivis::extra");
2287 
2288  gi.UnregisterConstVariable("luaaisort::dist");
2289  gi.UnregisterConstVariable("luaaisort::path");
2290  gi.UnregisterConstVariable("luaaisort::HP");
2291 
2292  gi.UnregisterConstVariable("luaaidist::dist");
2293  gi.UnregisterConstVariable("luaaidist::path");
2294 
2295  gi.UnregisterConstVariable("luaaishot::fastest");
2296  gi.UnregisterConstVariable("luaaishot::nearest");
2297  gi.UnregisterConstVariable("luaaishot::farthest");
2298  gi.UnregisterConstVariable("luaaishot::best_dam");
2299 
2300  gi.UnregisterConstVariable("luaaiwander::rand");
2301  gi.UnregisterConstVariable("luaaiwander::CW");
2302  gi.UnregisterConstVariable("luaaiwander::CCW");
2303 }
2304 
2308 void AIL_Cleanup (void)
2309 {
2310  lua_close(ailState);
2311  ailState = nullptr;
2312 }
static int AIL_tusforshooting(lua_State *L)
Returns the min TUs the actor needs to fire.
Definition: g_ai_lua.cpp:2062
static int AIL_squad(lua_State *L)
Returns a table with the actors in the current player's team.
Definition: g_ai_lua.cpp:1047
void AIL_Shutdown(void)
Definition: g_ai_lua.cpp:2276
static int actorL_team(lua_State *L)
Gets the actor's team.
Definition: g_ai_lua.cpp:566
static Player * AIL_player
Definition: g_ai_lua.cpp:239
#define ST_RIGHT
The right hand should be used for shooting.
Definition: q_shared.h:211
const objDef_t * onlyWeapon
Definition: chr_shared.h:325
bool AI_HideNeeded(const Actor *actor)
Checks whether the given alien should try to hide because there are enemies close enough to shoot the...
Definition: g_ai.cpp:484
Edict * G_EdictsGetNextInUse(Edict *lastEnt)
Iterate through the entities that are in use.
Definition: g_edicts.cpp:166
float AI_CalcShotDamage(Actor *actor, const Actor *target, const fireDef_t *fd, shoot_types_t shotType)
Calculate estimated damage per single shoot.
Definition: g_ai.cpp:811
static int AIL_waypoints(lua_State *L)
Return the positions of the next waypoints.
Definition: g_ai_lua.cpp:1678
#define VectorCopy(src, dest)
Definition: vector.h:51
static int actorL_tostring(lua_State *L)
Pushes the actor as a string.
Definition: g_ai_lua.cpp:495
Item * getFloor() const
Definition: g_edict.h:262
bool G_ClientGetWeaponFromInventory(Actor *actor)
Retrieve or collect a loaded weapon from any linked container for the actor's right hand...
Definition: g_client.cpp:568
bool isSameTeamAs(const Edict *other) const
Definition: g_edict.h:278
static int actorL_shoot(lua_State *L)
Shoots the actor.
Definition: g_ai_lua.cpp:523
static const luaL_reg pos3L_methods[]
Definition: g_ai_lua.cpp:344
#define ACTOR_VIS_10
Definition: g_vis.h:63
void AIL_ActorThink(Player &player, Actor *actor)
The think function for the ai controlled players.
Definition: g_ai_lua.cpp:2108
#define AIL_invalidparameter(n)
Definition: g_ai_lua.cpp:61
static int actorL_isvalidtarget(lua_State *L)
Check if the actor is a valid target to attack.
Definition: g_ai_lua.cpp:817
#define VectorSet(v, x, y, z)
Definition: vector.h:59
ailWanderPosType
Definition: g_ai_lua.cpp:87
#define luaL_dobuffer(L, b, n, s)
Definition: g_ai_lua.cpp:59
Actor * G_EdictsGetNextLivingActor(Actor *lastEnt)
Iterate through the living actor entities.
Definition: g_edicts.cpp:196
void AI_TurnIntoDirection(Actor *actor, const pos3_t pos)
This function will turn the AI actor into the direction that is needed to walk to the given location...
Definition: g_ai.cpp:1557
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
char id[MAX_VAR]
Definition: chr_shared.h:298
#define TEAM_PHALANX
Definition: q_shared.h:62
bool AI_FighterCheckShoot(const Actor *actor, const Edict *check, const fireDef_t *fd, float dist)
Check whether the fighter should perform the shoot.
Definition: g_ai.cpp:364
void calcOrigin()
Calculate the edict's origin vector from it's grid position.
Definition: g_edict.h:216
bool AI_FindHidingLocation(int team, Actor *actor, const pos3_t from, int tuLeft)
Tries to search a hiding spot.
Definition: g_ai.cpp:606
static int AIL_see(lua_State *L)
Returns what the actor can see.
Definition: g_ai_lua.cpp:1099
const fireDef_t * getFastestFireDef() const
Definition: inv_shared.cpp:624
this is a fire definition for our weapons/ammo
Definition: inv_shared.h:110
#define TEAM_ALIEN
Definition: q_shared.h:63
bool isRaged() const
Definition: g_edict.h:358
static lua_State * ailState
Definition: g_ai_lua.cpp:55
int getAmmoLeft() const
Definition: inv_shared.h:466
const teamDef_t * teamDef
Definition: chr_shared.h:394
Edict * G_GetEdictFromPos(const pos3_t pos, const entity_type_t type)
Searches an edict of the given type at the given grid location.
Definition: g_utils.cpp:59
Artificial Intelligence functions.
static int AIL_positionshoot(lua_State *L)
Moves the actor into a position in which he can shoot his target.
Definition: g_ai_lua.cpp:1305
static int AIL_reactionfire(lua_State *L)
Sets the actor's reaction fire mode.
Definition: g_ai_lua.cpp:1210
static int AIL_grabweapon(lua_State *L)
Actor tries to grab a weapon from inventory.
Definition: g_ai_lua.cpp:1296
static int AIL_positionapproach(lua_State *L)
Approach to a target actor.
Definition: g_ai_lua.cpp:1531
static int AIL_positionflee(lua_State *L)
Return a position to flee to.
Definition: g_ai_lua.cpp:1978
Misc utility functions for game module.
weaponFireDefIndex_t weapFdsIdx
Definition: inv_shared.h:126
bool AI_CheckPosition(const Actor *const actor, const pos3_t pos)
Checks if the given position is safe to stand on.
Definition: g_ai.cpp:581
Edict * ai_waypointList
Definition: g_local.h:118
void G_ClientStateChange(const Player &player, Actor *actor, int reqState, bool checkaction)
Changes the state of a player/soldier.
Definition: g_client.cpp:473
static const luaL_reg actorL_methods[]
Definition: g_ai_lua.cpp:312
#define STATE_REACTION
Definition: q_shared.h:272
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
bool isPanicked() const
Definition: g_edict.h:356
bool isDead() const
Definition: g_edict.h:362
static int actorL_register(lua_State *L)
Registers the actor metatable in the lua_State.
Definition: g_ai_lua.cpp:430
character_t chr
Definition: g_edict.h:116
const fireDef_t * getFiredefs() const
Returns the firedefinitions for a given weapon/ammo.
Definition: inv_shared.cpp:576
void G_ClientMove(const Player &player, int visTeam, Actor *actor, const pos3_t to)
Generates the client events that are send over the netchannel to move an actor.
Definition: g_move.cpp:307
float value
Definition: cvar.h:80
const objDef_t * def(void) const
Definition: inv_shared.h:469
#define VectorDist(a, b)
Definition: vector.h:69
int AI_GetHidingTeam(const Edict *ent)
Returns the value for the vis check whenever an ai actor tries to hide. For aliens this is the invers...
Definition: g_ai.cpp:570
bool G_ClientCanReload(Actor *actor, containerIndex_t containerID)
Returns true if actor can reload weapon.
Definition: g_client.cpp:536
static int AIL_findweapons(lua_State *L)
Returns a table of the positions of nearby usable weapons on the floor.
Definition: g_ai_lua.cpp:1886
bool AI_FindMissionLocation(Actor *actor, const pos3_t to, int tus, int radius)
Try to go close to a mission edict.
Definition: g_ai.cpp:1423
static int oldPos
static int actorL_morale(lua_State *L)
Gets the current morale of the actor onto the stack.
Definition: g_ai_lua.cpp:733
static int actorL_TU(lua_State *L)
Gets the number of usable TU the actor has left.
Definition: g_ai_lua.cpp:697
#define GRID_WIDTH
absolute max - -GRID_WIDTH up tp +GRID_WIDTH
Definition: defines.h:290
void AIL_Init(void)
Definition: g_ai_lua.cpp:2245
#define TEAM_CIVILIAN
Definition: q_shared.h:61
static int AIL_canreload(lua_State *L)
Checks to see if the actor can reload.
Definition: g_ai_lua.cpp:1257
static ailVisType_t AIL_toVisInt(lua_State *L, const int index)
Return visibility mode int representation from the string representation in the lua stack...
Definition: g_ai_lua.cpp:131
byte dir
Definition: g_edict.h:86
ailShootPosType_t
Shooting position types.
Definition: g_ai_lua.cpp:80
Item * getNext() const
Definition: inv_shared.h:451
#define POS3_METATABLE
Definition: g_ai_lua.cpp:51
#define TU_MOVE_STRAIGHT
Definition: defines.h:74
const char * type
Definition: inv_shared.h:271
#define STATE_CROUCHED
Definition: q_shared.h:263
int integer
Definition: cvar.h:81
const byte dvleft[CORE_DIRECTIONS]
Definition: mathlib.cpp:119
#define VT_NOFRUSTUM
Definition: g_vis.h:55
voidpf void * buf
Definition: ioapi.h:42
float G_ActorVis(const Edict *ent, const Edict *check, bool full)
calculate how much check is "visible" by ent
Definition: g_vis.cpp:100
#define ACTOR_METATABLE
Definition: g_ai_lua.cpp:52
AiAreaSearch class, used to get an area of the map around a certain position for the AI to check poss...
Definition: g_ai.h:33
static int AIL_roundsleft(lua_State *L)
Checks to see how many rounds the actor has left.
Definition: g_ai_lua.cpp:1235
Item * getRightHandItem() const
Definition: g_edict.h:249
static int AIL_positionmission(lua_State *L)
Try to find a position nearby to the given position.
Definition: g_ai_lua.cpp:1761
cvar_t * g_ailua
Definition: g_main.cpp:112
int AngleToDir(int angle)
Returns the index of array directionAngles[DIRECTIONS] whose value is the closest to angle...
Definition: mathlib.cpp:130
static int AIL_positionherd(lua_State *L)
Determine the position where actor is closest to the target and with the target located between the a...
Definition: g_ai_lua.cpp:1489
int getTeam() const
Definition: g_edict.h:269
#define CID_LEFT
Definition: inv_shared.h:48
bool AIL_TeamThink(Player &player)
The team think function for the ai controlled players.
Definition: g_ai_lua.cpp:2156
int getUsableTUs() const
Calculates the amount of usable TUs. This is without the reserved TUs.
Definition: g_edict.h:400
item instance data, with linked list capability
Definition: inv_shared.h:402
#define todeg
Definition: mathlib.h:51
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
bool AI_CheckLineOfFire(const Actor *shooter, const Edict *target, const fireDef_t *fd, int shots)
Definition: g_ai.cpp:763
static int AIL_missiontargets(lua_State *L)
Returns the positions of the available mission targets.
Definition: g_ai_lua.cpp:1595
bool launched
Definition: inv_shared.h:137
static int actorL_HP(lua_State *L)
Gets the number of HP the actor has left.
Definition: g_ai_lua.cpp:715
#define CID_RIGHT
Definition: inv_shared.h:47
cvar_t * g_difficulty
Definition: g_main.cpp:125
GLsizei size
Definition: r_gl.h:152
fireDefIndex_t numFiredefs[MAX_WEAPONS_PER_OBJDEF]
Definition: inv_shared.h:315
bool gravity
Definition: inv_shared.h:136
game_import_t gi
Definition: g_main.cpp:39
#define PosSubDV(p, crouch, dv)
Definition: mathlib.h:254
float sortLookup
Definition: g_ai_lua.cpp:227
static aiActor_t * lua_pushactor(lua_State *L, aiActor_t *actor)
Pushes a actor as a metatable at the top of the stack.
Definition: g_ai_lua.cpp:483
#define MAX_VAR
Definition: shared.h:36
#define VT_PERISHCHK
Definition: g_vis.h:53
int32_t shoot_types_t
Available shoot types - also see the ST_ constants.
Definition: q_shared.h:206
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
int radius
Definition: g_edict.h:123
static float AIL_GetBestShot(const Actor &shooter, const Actor &target, const int tu, const float dist, shoot_types_t &bestType, fireDefIndex_t &bestFd, int &bestShots)
Definition: g_ai_lua.cpp:241
static int pos3L_face(lua_State *L)
Makes the actor face the position.
Definition: g_ai_lua.cpp:947
static int AIL_toTeamInt(const char *team, const int param)
Converts team string into int representation.
Definition: g_ai_lua.cpp:117
#define ST_LEFT
The left hand should be used for shooting.
Definition: q_shared.h:221
static const char * AIL_GetAIType(const int team)
Return the AI type for the given team (the lua file the team actors should run)
Definition: g_ai_lua.cpp:2134
All parts of the main game logic that are combat related.
const invDef_t * AI_SearchGrenade(const Actor *actor, Item **ip)
Search the edict's inventory for a grenade or other one-use weapon.
Definition: g_ai.cpp:954
const char *IMPORT * GetConstVariable(const char *space, int value)
int32_t fireDefIndex_t
Definition: inv_shared.h:78
bool isSamePosAs(const pos3_t cmpPos)
Check whether the edict is on the given position.
Definition: g_edict.h:286
int G_ActorGetModifiedTimeForFiredef(const Edict *const ent, const fireDef_t *const fd, const bool reaction)
Definition: g_actor.cpp:764
static ailSortCritType_t AIL_toDistInt(lua_State *L, const int index)
Return distance type int representation from the string representation in the lua stack...
Definition: g_ai_lua.cpp:167
#define TEAM_ALL
Definition: g_vis.h:32
static int AIL_weapontype(lua_State *L)
Returns the type of the weapons in the actors hands.
Definition: g_ai_lua.cpp:2039
pos3_t pos
Definition: g_edict.h:55
fireDefIndex_t fdIdx
Definition: inv_shared.h:130
#define PosToVec(p, v)
Pos boundary size is +/- 128 - to get into the positive area we add the possible max negative value a...
Definition: mathlib.h:110
static aiActor_t * lua_toactor(lua_State *L, int index)
Returns the actor from the metatable at index.
Definition: g_ai_lua.cpp:471
#define VectorEmpty(a)
Definition: vector.h:73
static int actorL_pos(lua_State *L)
Gets the actors position.
Definition: g_ai_lua.cpp:511
An Edict of type Actor.
Definition: g_edict.h:348
#define CID_FLOOR
Definition: inv_shared.h:55
static Actor * AIL_ent
Definition: g_ai_lua.cpp:238
static int AIL_hideneeded(lua_State *L)
Check if the actor needs wants to hide.
Definition: g_ai_lua.cpp:2097
bool isInsane() const
Definition: g_edict.h:359
#define TEAM_DEFAULT
Definition: defines.h:51
pos_t G_ActorMoveLength(const Actor *actor, const pathing_t *path, const pos3_t to, bool stored)
Return the needed TUs to walk to a given position.
Definition: g_move.cpp:270
static pos3_t * lua_pushpos3(lua_State *L, pos3_t *pos)
Pushes a pos3 as a metatable at the top of the stack.
Definition: g_ai_lua.cpp:890
bool AI_IsHostile(const Actor *actor, const Edict *target)
Check if actor perceives target as hostile.
Definition: g_ai.cpp:933
Wrapper around edict.
Definition: g_ai_lua.cpp:218
#define INVDEF(containerID)
Definition: cl_shared.h:47
char type[MAX_QPATH]
Definition: g_local.h:304
pos_t pos3_t[3]
Definition: ufotypes.h:58
static int AIL_positionwander(lua_State *L)
Return a new position to move to.
Definition: g_ai_lua.cpp:1799
bool G_ActorInvMove(Actor *actor, const invDef_t *fromContType, Item *fItem, const invDef_t *toContType, int tx, int ty, bool checkaction)
Moves an item inside an inventory. Floors are handled special.
Definition: g_actor.cpp:506
ailSortCritType_t
target sorting criteria (lowest first)
Definition: g_ai_lua.cpp:73
QGL_EXTERN GLuint index
Definition: r_gl.h:110
#define UNIT_SIZE
Definition: defines.h:121
void setOrigin(const pos3_t newPos)
Set the edict's pos and origin vector to the given grid position.
Definition: g_edict.h:223
static int pos3L_distance(lua_State *L)
Return the distance the position an the AI actor.
Definition: g_ai_lua.cpp:961
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
int count
Definition: g_edict.h:135
int32_t containerIndex_t
Definition: inv_shared.h:46
static int AIL_class(lua_State *L)
Returns the AI actor's class.
Definition: g_ai_lua.cpp:2088
int G_CheckVisTeamAll(const int team, const vischeckflags_t visFlags, const Edict *ent)
Do G_CheckVisTeam for all entities ent is the one that is looking at the others.
Definition: g_vis.cpp:376
bool G_FindPath(int team, const Edict *movingActor, const pos3_t from, const pos3_t targetPos, bool crouched, int maxTUs)
Definition: g_move.cpp:107
static ailSortCritType_t AIL_toSortInt(lua_State *L, const int index)
Return sort type int representation from the string representation in the lua stack.
Definition: g_ai_lua.cpp:149
int G_TestVis(const int team, Edict *check, const vischeckflags_t flags)
test if check is visible by team (or if visibility changed?)
Definition: g_vis.cpp:255
#define PATHFINDING_HEIGHT
15 max, adjusting above 8 will require a rewrite to the DV code
Definition: defines.h:294
static int AIL_print(lua_State *L)
Works more or less like Lua's builtin print.
Definition: g_ai_lua.cpp:1000
pathing_t * pathingMap
Definition: g_local.h:106
bool rolled
Definition: inv_shared.h:138
bool G_IsActorWounded(const Edict *ent, bool serious)
Definition: g_health.cpp:213
static int pos3L_goto(lua_State *L)
Makes the actor head to the position.
Definition: g_ai_lua.cpp:918
bool G_ClientShoot(const Player &player, Actor *actor, const pos3_t at, shoot_types_t shootType, fireDefIndex_t firemode, shot_mock_t *mock, bool allowReaction, int z_align)
Setup for shooting, either real or mock.
Definition: g_combat.cpp:1183
Actor * G_EdictsGetNextLivingActorOfTeam(Actor *lastEnt, const int team)
Iterate through the living actor entities of the given team.
Definition: g_edicts.cpp:216
#define VS_YES
Definition: g_vis.h:46
QGL_EXTERN GLint i
Definition: r_gl.h:113
const byte dvright[CORE_DIRECTIONS]
Definition: mathlib.cpp:116
struct aiActor_s aiActor_t
Wrapper around edict.
bool AI_FindHerdLocation(Actor *actor, const pos3_t from, const vec3_t target, int tu, bool inverse)
Tries to search a spot where actor will be more closer to the target and behind the target from enemy...
Definition: g_ai.cpp:659
int getPlayerNum() const
Definition: g_edict.h:234
static ailShootPosType_t AIL_toShotPInt(lua_State *L, const int index)
Return shooting position type int representation from the string representation in the lua stack...
Definition: g_ai_lua.cpp:185
#define G_IsDead(ent)
Definition: g_actor.h:34
bool isCrouched() const
Definition: g_edict.h:361
Actor * G_EdictsGetNextActor(Actor *lastEnt)
Iterate through the actor entities (even the dead!)
Definition: g_edicts.cpp:231
Local definitions for game module.
entity_type_t type
Definition: g_edict.h:81
static int AIL_reload(lua_State *L)
Actor reloads his weapons.
Definition: g_ai_lua.cpp:1267
static int AIL_difficulty(lua_State *L)
Return the difficulty number (in case we want different AI for different ones)
Definition: g_ai_lua.cpp:1969
int ammo
Definition: inv_shared.h:293
static int AIL_actor(lua_State *L)
Returns the currently moving AI actor.
Definition: g_ai_lua.cpp:2053
#define CID_MAX
Definition: inv_shared.h:57
functions to handle the storage and lifecycle of all edicts in the game module.
vec3_t origin
Definition: g_edict.h:53
bool G_Vis(const int team, const Edict *from, const Edict *check, const vischeckflags_t flags)
test if check is visible by from
Definition: g_vis.cpp:183
bool AI_TryToReloadWeapon(Actor *actor, containerIndex_t containerID)
if a weapon can be reloaded we attempt to do so if TUs permit, otherwise drop it
Definition: g_ai.cpp:1574
Actor * actor
Definition: g_ai_lua.cpp:219
bool isHeldTwoHanded() const
Definition: inv_shared.h:476
bool isReaction() const
Definition: g_edict.h:357
const objDef_t * ammoDef(void) const
Definition: inv_shared.h:460
static lua_State * AIL_InitLua()
Definition: g_ai_lua.cpp:2185
vec_t vec3_t[3]
Definition: ufotypes.h:39
inventory definition for our menus
Definition: inv_shared.h:371
static int pos3L_register(lua_State *L)
Registers the pos3 metatable in the lua_State.
Definition: g_ai_lua.cpp:837
float splrad
Definition: inv_shared.h:161
const Item * AI_GetItemForShootType(shoot_types_t shootType, const Edict *ent)
Definition: g_ai.cpp:541
static const luaL_reg AIL_methods[]
Definition: g_ai_lua.cpp:388
int getMorale() const
Definition: g_edict.h:350
Artificial intelligence of a character.
Definition: g_local.h:303
cvar_t * mor_brave
Definition: g_main.cpp:104
char name[MAX_VAR]
Definition: chr_shared.h:371
static ailWanderPosType AIL_toWanderPInt(lua_State *L, const int index)
Return wander position type int representation from the string representation in the lua stack...
Definition: g_ai_lua.cpp:203
#define G_IsVisibleForTeam(ent, team)
Definition: g_local.h:144
static int lua_isactor(lua_State *L, int index)
Checks to see if there is a actor metatable at index in the lua_State.
Definition: g_ai_lua.cpp:454
void AIL_Cleanup(void)
Closes the LUA AI.
Definition: g_ai_lua.cpp:2308
static int lua_ispos3(lua_State *L, int index)
Checks to see if there is a pos3 metatable at index in the lua_State.
Definition: g_ai_lua.cpp:861
ailVisType_t
vis check types
Definition: g_ai_lua.cpp:65
GLsizei const GLvoid * data
Definition: r_gl.h:152
#define ROUTING_UNREACHABLE
Definition: defines.h:284
void G_MoveCalc(int team, const Actor *movingActor, const pos3_t from, int distance)
Precalculates a move table for a given team and a given starting position. This will calculate a rout...
Definition: g_move.cpp:88
#define NONE
Definition: defines.h:68
#define Q_streq(a, b)
Definition: shared.h:136
AI_t AI
Definition: g_edict.h:171
static int AIL_crouch(lua_State *L)
Requests a crouch state (with true/false) and returns current crouch state.
Definition: g_ai_lua.cpp:1191
bool G_TestLineWithEnts(const vec3_t start, const vec3_t end)
fast version of a line trace including entities
Definition: g_utils.cpp:237
char subtype[MAX_VAR]
Definition: g_local.h:305
#define ST_NUM_SHOOT_TYPES
Amount of shoottypes available.
Definition: q_shared.h:236
static int AIL_positionhide(lua_State *L)
Moves the actor into a position in which he can hide.
Definition: g_ai_lua.cpp:1433
Definition: g_edict.h:45
static pos3_t * lua_topos3(lua_State *L, int index)
Returns the pos3 from the metatable at index.
Definition: g_ai_lua.cpp:878
static const char * AIL_toTeamString(const int team)
Converts integer team representation into string.
Definition: g_ai_lua.cpp:102
static int pos3L_tostring(lua_State *L)
Puts the pos3 information in a string.
Definition: g_ai_lua.cpp:902
int AIL_InitActor(Actor *actor)
Initializes the lua AI for an actor.
Definition: g_ai_lua.cpp:2203
#define ROUTING_NOT_REACHABLE
Definition: defines.h:283
static int AIL_isfighter(lua_State *L)
Whether the current AI actor is a fighter or not.
Definition: g_ai_lua.cpp:1935
#define AI_METATABLE
Definition: g_ai_lua.cpp:53
Item * getLeftHandItem() const
Definition: g_edict.h:252
bool weapons
Definition: chr_shared.h:324
uint8_t byte
Definition: ufotypes.h:34
static int actorL_isarmed(lua_State *L)
Check if actor has weapons.
Definition: g_ai_lua.cpp:780
#define VectorDistSqr(a, b)
Definition: vector.h:68
static int actorL_isinjured(lua_State *L)
Checks to see if the actor is seriously injured.
Definition: g_ai_lua.cpp:761
Edict * groupChain
Definition: g_edict.h:167
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
static int AIL_setwaypoint(lua_State *L)
Mark the current waypoint for a civ.
Definition: g_ai_lua.cpp:1945
bool getNext(pos3_t pos)
Get next position in the search area.
Definition: g_ai.cpp:79
int G_VisCheckDist(const Edict *const ent)
Definition: g_vis.cpp:163
static int actorL_throwgrenade(lua_State *L)
Throws a grenade to the actor.
Definition: g_ai_lua.cpp:580
Interface for g_client.cpp.
byte pos_t
Definition: ufotypes.h:57
level_locals_t level
Definition: g_main.cpp:38
static int actorL_isdead(lua_State *L)
Check if the actor is dead.
Definition: g_ai_lua.cpp:799
int HP
Definition: g_edict.h:89
#define MAX_EDICTS
Definition: defines.h:99
static int AIL_select(lua_State *L)
Select an specific AI actor.
Definition: g_ai_lua.cpp:1075