UFO: Alien Invasion
Doxygen documentation generating
g_ai_lua.cpp
Go to the documentation of this file.
1 
15 /*
16 Copyright (C) 2002-2023 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 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM < 504
52 LUALIB_API int luaL_typeerror (lua_State *L, int narg, const char *tname) {
53  const char *msg = lua_pushfstring(L, "%s expected, got %s",
54  tname, luaL_typename(L, narg));
55  return luaL_argerror(L, narg, msg);
56 }
57 #endif
58 
59 #define POS3_METATABLE "pos3"
60 #define ACTOR_METATABLE "actor"
61 #define AI_METATABLE "ai"
63 static lua_State* ailState;
64 
67 #define luaL_dobuffer(L, b, n, s) \
68  (luaL_loadbuffer(L, b, n, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
69 #define AIL_invalidparameter(n) \
70  gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", n, __func__)
71 
73 typedef enum {
74  AILVT_ALL, /* Don't do vis checks (god's view) */
75  AILVT_SIGHT, /* Standard vis check */
76  AILVT_TEAM, /* Team vis check */
77  AILVT_DIST /* Check only vis distance */
78 } ailVisType_t;
79 
81 typedef enum {
82  AILSC_DIST, /* Sort by line distance */
83  AILSC_PATH, /* Sort by pathing cost */
84  AILSC_HP /* Sort by HP */
86 
88 typedef enum {
89  AILSP_FAST, /* Fastest to get to */
90  AILSP_NEAR, /* Nearest to target */
91  AILSP_FAR, /* Farthest from target (within weapon's range) */
92  AILSP_DMG /* Best expected damage */
94 
95 typedef enum {
96  AILPW_RAND, /* Wander randomly */
97  AILPW_CW, /* Move clockwise */
98  AILPW_CCW /* Move counter-clockwise */
100 /*
101  * Helper functions
102  */
103 
110 static const char* AIL_toTeamString (const int team)
111 {
112  const char* teamStr = gi.GetConstVariable("luaaiteam", team);
113  if (teamStr == nullptr)
115  return teamStr;
116 }
117 
125 static int AIL_toTeamInt (const char* team, const int param)
126 {
127  int teamInt = TEAM_DEFAULT;
128  if (!gi.GetConstIntFromNamespace("luaaiteam", team, &teamInt))
129  AIL_invalidparameter(param);
130  return teamInt;
131 }
132 
139 static ailVisType_t AIL_toVisInt (lua_State* L, const int index)
140 {
141  int visInt = AILVT_ALL;
142  if (lua_isstring(L, index)) {
143  const char* s = lua_tostring(L, index);
144  if (!gi.GetConstIntFromNamespace("luaaivis", s, &visInt))
146  } else
148  return static_cast<ailVisType_t> (visInt);
149 }
150 
157 static ailSortCritType_t AIL_toSortInt (lua_State* L, const int index)
158 {
159  int sortInt = AILSC_DIST;
160  if (lua_isstring(L, index)) {
161  const char* s = lua_tostring(L, index);
162  if (!gi.GetConstIntFromNamespace("luaaisort", s, &sortInt))
164  } else
166  return static_cast<ailSortCritType_t> (sortInt);
167 }
168 
175 static ailSortCritType_t AIL_toDistInt (lua_State* L, const int index)
176 {
177  int distInt = AILSC_DIST;
178  if (lua_isstring(L, index)) {
179  const char* s = lua_tostring(L, index);
180  if (!gi.GetConstIntFromNamespace("luaaidist", s, &distInt))
182  } else
184  return static_cast<ailSortCritType_t> (distInt);
185 }
186 
193 static ailShootPosType_t AIL_toShotPInt (lua_State* L, const int index)
194 {
195  int spInt = AILSP_FAST;
196  if (lua_isstring(L, index)) {
197  const char* s = lua_tostring(L, index);
198  if (!gi.GetConstIntFromNamespace("luaaishot", s, &spInt))
200  } else
202  return static_cast<ailShootPosType_t> (spInt);
203 }
204 
211 static ailWanderPosType AIL_toWanderPInt (lua_State* L, const int index)
212 {
213  int wpInt = AILPW_RAND;
214  if (lua_isstring(L, index)) {
215  const char* s = lua_tostring(L, index);
216  if (!gi.GetConstIntFromNamespace("luaaiwander", s, &wpInt))
218  } else
220  return static_cast<ailWanderPosType> (wpInt);
221 }
222 
226 typedef struct aiActor_s {
228 } aiActor_t;
229 
230 
231 /* Table sorting */
232 template<typename T>
233 struct AilSortTable {
234  T data;
235  float sortLookup;
236 };
237 
238 template<typename T>
239 bool operator< (AilSortTable<T> i, AilSortTable<T> j) {
240  return (i.sortLookup < j.sortLookup);
241 }
242 
243 /*
244  * Current AI Actor.
245  */
246 static Actor* AIL_ent;
247 static Player* AIL_player;
249 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)
250 {
251  int shotChecked = NONE;
252  float bestDmg = 0.0f;
253  bestShots = bestType = bestFd = NONE;
254  for (shoot_types_t shootType = ST_RIGHT; shootType < ST_NUM_SHOOT_TYPES; shootType++) {
255  const Item* item = AI_GetItemForShootType(shootType, AIL_ent);
256  if (item == nullptr)
257  continue;
258 
259  const fireDef_t* fdArray = item->getFiredefs();
260  if (fdArray == nullptr)
261  continue;
262 
263  for (fireDefIndex_t fdIdx = 0; fdIdx < item->ammoDef()->numFiredefs[fdArray->weapFdsIdx]; fdIdx++) {
264  const fireDef_t* fd = &fdArray[fdIdx];
265  const int time = G_ActorGetModifiedTimeForFiredef(AIL_ent, fd, false);
266  /* how many shoots can this actor do */
267  const int shots = tu / time;
268 
269  if (!shots)
270  continue;
271 
272  if (!AI_FighterCheckShoot(AIL_ent, &target, fd, dist))
273  continue;
274 
275  const int shotFlags = fd->gravity | (fd->launched << 1) | (fd->rolled << 2);
276  if (shotChecked != shotFlags) {
277  shotChecked = shotFlags;
278  if (!AI_CheckLineOfFire(AIL_ent, &target, fd, shots))
279  continue;
280  }
281 
282  /* Check if we can do the most damage here */
283  float dmg = AI_CalcShotDamage(AIL_ent, &target, fd, shootType) * shots;
284  if (dmg > bestDmg) {
285  bestDmg = dmg;
286  bestShots = shots;
287  bestFd = fdIdx;
288  bestType = shootType;
289  }
290  }
291  }
292 
293  return bestDmg;
294 }
295 
296 /*
297  * Actor metatable.
298  */
299 
300 /* Internal functions. */
301 static int actorL_register(lua_State* L);
302 static int lua_isactor(lua_State* L, int index);
303 static aiActor_t* lua_toactor(lua_State* L, int index);
304 static aiActor_t* lua_pushactor(lua_State* L, aiActor_t* actor);
305 
306 /* Metatable functions. */
307 static int actorL_tostring(lua_State* L);
308 static int actorL_pos(lua_State* L);
309 static int actorL_shoot(lua_State* L);
310 static int actorL_team(lua_State* L);
311 static int actorL_throwgrenade(lua_State* L);
312 static int actorL_TU(lua_State* L);
313 static int actorL_HP(lua_State* L);
314 static int actorL_morale(lua_State* L);
315 static int actorL_isinjured(lua_State* L);
316 static int actorL_isarmed(lua_State* L);
317 static int actorL_isdead(lua_State* L);
318 static int actorL_isvalidtarget(lua_State* L);
319 
321 static const luaL_Reg actorL_methods[] = {
322  {"__tostring", actorL_tostring},
323  {"pos", actorL_pos},
324  {"shoot", actorL_shoot},
325  {"team", actorL_team},
326  {"throwgrenade", actorL_throwgrenade},
327  {"TU", actorL_TU},
328  {"HP", actorL_HP},
329  {"morale", actorL_morale},
330  {"isinjured", actorL_isinjured},
331  {"isarmed", actorL_isarmed},
332  {"isdead", actorL_isdead},
333  {"isvalidtarget", actorL_isvalidtarget},
334  {nullptr, nullptr}
335 };
336 
341 /* Internal functions. */
342 static int pos3L_register(lua_State* L);
343 static int lua_ispos3(lua_State* L, int index);
344 static pos3_t* lua_topos3(lua_State* L, int index);
345 static pos3_t* lua_pushpos3(lua_State* L, pos3_t* pos);
346 
347 /* Metatable functions. */
348 static int pos3L_tostring(lua_State* L);
349 static int pos3L_goto(lua_State* L);
350 static int pos3L_face(lua_State* L);
351 static int pos3L_distance(lua_State* L);
352 
354 static const luaL_Reg pos3L_methods[] = {
355  {"__tostring", pos3L_tostring},
356  {"goto", pos3L_goto},
357  {"face", pos3L_face},
358  {"distance", pos3L_distance},
359  {nullptr, nullptr}
360 };
361 
362 
366 static int AIL_print(lua_State* L);
367 static int AIL_squad(lua_State* L);
368 static int AIL_select(lua_State* L);
369 static int AIL_see(lua_State* L);
370 static int AIL_crouch(lua_State* L);
371 static int AIL_reactionfire(lua_State* L);
372 static int AIL_roundsleft(lua_State* L);
373 static int AIL_canreload(lua_State* L);
374 static int AIL_reload(lua_State* L);
375 static int AIL_positionshoot(lua_State* L);
376 static int AIL_positionhide(lua_State* L);
377 static int AIL_positionherd(lua_State* L);
378 static int AIL_positionapproach(lua_State* L);
379 static int AIL_grabweapon(lua_State* L);
380 static int AIL_missiontargets(lua_State* L);
381 static int AIL_waypoints(lua_State* L);
382 static int AIL_positionmission(lua_State* L);
383 static int AIL_positionwander(lua_State* L);
384 static int AIL_findweapons(lua_State* L);
385 static int AIL_isfighter(lua_State* L);
386 static int AIL_setwaypoint(lua_State* L);
387 static int AIL_difficulty(lua_State* L);
388 static int AIL_positionflee(lua_State* L);
389 static int AIL_weapontype(lua_State* L);
390 static int AIL_actor(lua_State* L);
391 static int AIL_tusforshooting(lua_State* L);
392 static int AIL_class(lua_State* L);
393 static int AIL_hideneeded(lua_State* L);
394 
398 static const luaL_Reg AIL_methods[] = {
399  {"print", AIL_print},
400  {"squad", AIL_squad},
401  {"select", AIL_select},
402  {"see", AIL_see},
403  {"crouch", AIL_crouch},
404  {"reactionfire", AIL_reactionfire},
405  {"roundsleft", AIL_roundsleft},
406  {"canreload", AIL_canreload},
407  {"reload", AIL_reload},
408  {"positionshoot", AIL_positionshoot},
409  {"positionhide", AIL_positionhide},
410  {"positionherd", AIL_positionherd},
411  {"positionapproach", AIL_positionapproach},
412  {"grabweapon", AIL_grabweapon},
413  {"missiontargets", AIL_missiontargets},
414  {"waypoints", AIL_waypoints},
415  {"positionmission", AIL_positionmission},
416  {"positionwander", AIL_positionwander},
417  {"findweapons", AIL_findweapons},
418  {"isfighter", AIL_isfighter},
419  {"setwaypoint", AIL_setwaypoint},
420  {"difficulty", AIL_difficulty},
421  {"positionflee", AIL_positionflee},
422  {"weapontype", AIL_weapontype},
423  {"actor", AIL_actor},
424  {"tusforshooting", AIL_tusforshooting},
425  {"class", AIL_class},
426  {"hideneeded", AIL_hideneeded},
427  {nullptr, nullptr}
428 };
429 
430 
440 static int actorL_register (lua_State* L)
441 {
442  /* Create the metatable */
443  luaL_newmetatable(L, ACTOR_METATABLE);
444 
445  /* Create the access table */
446  lua_pushvalue(L, -1);
447  lua_setfield(L, -2, "__index");
448 
449  /* Register the values */
450  luaL_setfuncs(L, actorL_methods, 0);
451 
452  /* Clean up stack. */
453  lua_pop(L, 1);
454 
455  return 0; /* No error */
456 }
457 
464 static int lua_isactor (lua_State* L, int index)
465 {
466  if (lua_getmetatable(L, index) == 0)
467  return 0;
468  lua_getfield(L, LUA_REGISTRYINDEX, ACTOR_METATABLE);
469 
470  int ret = 0;
471  if (lua_rawequal(L, -1, -2)) /* does it have the correct metatable? */
472  ret = 1;
473 
474  lua_pop(L, 2); /* remove both metatables */
475  return ret;
476 }
477 
481 static aiActor_t* lua_toactor (lua_State* L, int index)
482 {
483  if (lua_isactor(L, index)) {
484  return (aiActor_t*) lua_touserdata(L, index);
485  }
486  luaL_typeerror(L, index, ACTOR_METATABLE);
487  return nullptr;
488 }
489 
493 static aiActor_t* lua_pushactor (lua_State* L, aiActor_t* actor)
494 {
495  aiActor_t* a = (aiActor_t*) lua_newuserdata(L, sizeof(aiActor_t));
496  *a = *actor;
497  luaL_getmetatable(L, ACTOR_METATABLE);
498  lua_setmetatable(L, -2);
499  return a;
500 }
501 
505 static int actorL_tostring (lua_State* L)
506 {
507  char buf[MAX_VAR];
508 
509  assert(lua_isactor(L, 1));
510 
511  const aiActor_t* target = lua_toactor(L, 1);
512  Com_sprintf(buf, sizeof(buf), "Actor( %s )", target->actor->chr.name);
513 
514  lua_pushstring(L, buf);
515  return 1;
516 }
517 
521 static int actorL_pos (lua_State* L)
522 {
523  assert(lua_isactor(L, 1));
524 
525  const aiActor_t* target = lua_toactor(L, 1);
526  lua_pushpos3(L, &target->actor->pos);
527  return 1;
528 }
529 
533 static int actorL_shoot (lua_State* L)
534 {
535  assert(lua_isactor(L, 1));
536 
537  /* Target */
538  const aiActor_t* target = lua_toactor(L, 1);
539 
540  /* Number of TU to spend shooting, fire mode will adjust to that. */
541  int tu = AIL_ent->getUsableTUs();
542  if (lua_gettop(L) > 1) {
543  assert(lua_isnumber(L, 2)); /* Must be a number. */
544 
545  tu = std::min(static_cast<int>(lua_tonumber(L, 2)), tu);
546  }
547 
548  const float dist = VectorDist(AIL_ent->origin, target->actor->origin);
549  shoot_types_t bestType = NONE;
550  fireDefIndex_t bestFd = NONE;
551  int bestShots = 0;
552  AIL_GetBestShot(*AIL_ent, *target->actor, tu, dist, bestType, bestFd, bestShots);
553 
554  /* Failure - no weapon. */
555  if (bestType == NONE) {
556  lua_pushboolean(L, 0);
557  return 1;
558  }
559 
560  bool shot = false;
561  while (bestShots > 0) {
562  if (G_IsDead(target->actor))
563  break;
564  bestShots--;
565  shot = G_ClientShoot(*AIL_player, AIL_ent, target->actor->pos, bestType, bestFd, nullptr, true, 0) || shot;
566  }
567 
568  /* Success? */
569  lua_pushboolean(L, shot);
570  return 1;
571 }
572 
576 static int actorL_team (lua_State* L)
577 {
578  assert(lua_isactor(L, 1));
579 
580  const aiActor_t* target = lua_toactor(L, 1);
581  assert(target != nullptr);
582  const char* team = AIL_toTeamString(target->actor->getTeam());
583  lua_pushstring(L, team);
584  return 1;
585 }
586 
590 static int actorL_throwgrenade(lua_State* L)
591 {
592  /* check parameter */
593  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
595  lua_pushboolean(L, 0);
596  return 1;
597  }
598  const aiActor_t* target = lua_toactor(L, 1);
599  assert(target != nullptr);
600 
601  /* Min number of enemies to use grenade */
602  int minNum = 0;
603  if (lua_gettop(L) > 1) {
604  if (!lua_isnumber(L, 2)) { /* Must be a number. */
606  lua_pushboolean(L, 0);
607  return 1;
608  }
609  minNum = static_cast<int>(lua_tonumber(L, 2));
610  }
611 
612  /* Number of TU to spend */
613  int tus = AIL_ent->getUsableTUs();
614  if (lua_gettop(L) > 2) {
615  if (!lua_isnumber(L, 3)) { /* Must be a number. */
617  lua_pushboolean(L, 0);
618  return 1;
619  }
620  tus = std::min(static_cast<int>(lua_tonumber(L, 3)), tus);
621  }
622 
623  /* Check that we have a free hand */
625  const Item* right = AIL_ent->getRightHandItem();
626  if (right)
627  hand = right->isHeldTwoHanded() || AIL_ent->getLeftHandItem() ? CID_MAX : CID_LEFT;
628  if (hand >= CID_MAX) {
629  lua_pushboolean(L, 0);
630  return 1;
631  }
632 
633  /* Check if we have a grenade */
634  Item* grenade = nullptr;
635  const invDef_t* fromCont = AI_SearchGrenade(AIL_ent, &grenade);
636  if (!fromCont || !grenade) {
637  lua_pushboolean(L, 0);
638  return 1;
639  }
640  /* Now check if we can use it */
641  const fireDef_t* fdArray = grenade->getFiredefs();
642  const int invMoveCost = fromCont->out + INVDEF(hand)->in;
643  const shoot_types_t shotType = hand == CID_RIGHT ? ST_RIGHT : ST_LEFT;
644  float dist = VectorDist(AIL_ent->origin, target->actor->origin);
645  const fireDef_t* bestFd = nullptr;
646  for (fireDefIndex_t fdIdx = 0; fdIdx < grenade->ammoDef()->numFiredefs[fdArray->weapFdsIdx]; fdIdx++) {
647  const fireDef_t* fd = &fdArray[fdIdx];
648  const int time = invMoveCost + G_ActorGetModifiedTimeForFiredef(AIL_ent, fd, false);
649  /* Enough TU? */
650  if (time > tus)
651  continue;
652  /* In range? */
653  if (!AI_FighterCheckShoot(AIL_ent, target->actor, fd, dist))
654  continue;
655  /* LOF? */
656  if (!AI_CheckLineOfFire(AIL_ent, target->actor, fd, 1))
657  continue;
658 
659  /* Select the first usable firemode */
660  bestFd = fd;
661  break;
662  }
663  if (!bestFd) {
664  lua_pushboolean(L, 0);
665  return 1;
666  }
667 
668  /* Finally check if we want to use it now */
669  if (bestFd->splrad > 0) {
670  Actor* check = nullptr;
671  int n = 0;
672  while ((check = G_EdictsGetNextLivingActor(check))) {
673  /* check for distance */
674  dist = VectorDist(target->actor->origin, check->origin);
675  dist = dist > UNIT_SIZE / 2 ? dist - UNIT_SIZE / 2 : 0;
676  if (dist > bestFd->splrad)
677  continue;
678 
679  if (!AI_IsHostile(AIL_ent, target->actor)) {
680  lua_pushboolean(L, 0);
681  return 1;
682  }
683  ++n;
684  }
685  /* Check there's large enough group of targets */
686  if (n < minNum) {
687  lua_pushboolean(L, 0);
688  return 1;
689  }
690  }
691 
692  /* Try to move the grenade to the free hand */
693  if(!G_ActorInvMove(AIL_ent, fromCont, grenade, INVDEF(hand), NONE, NONE, true)) {
694  lua_pushboolean(L, 0);
695  return 1;
696  }
697  /* All right use it! */
698  const bool result = G_ClientShoot(*AIL_player, AIL_ent, target->actor->pos, shotType, bestFd->fdIdx, nullptr, true, 0);
699 
700  lua_pushboolean(L, result);
701  return 1;
702 }
703 
707 static int actorL_TU (lua_State* L)
708 {
709  /* check parameter */
710  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
712  lua_pushboolean(L, 0);
713  return 1;
714  }
715  const aiActor_t* actor = lua_toactor(L, 1);
716  assert(actor != nullptr);
717 
718  lua_pushnumber(L, actor->actor->getUsableTUs());
719  return 1;
720 }
721 
725 static int actorL_HP (lua_State* L)
726 {
727  /* check parameter */
728  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
730  lua_pushboolean(L, 0);
731  return 1;
732  }
733  const aiActor_t* actor = lua_toactor(L, 1);
734  assert(actor != nullptr);
735 
736  lua_pushnumber(L, actor->actor->HP);
737  return 1;
738 }
739 
743 static int actorL_morale (lua_State* L)
744 {
745  /* check parameter */
746  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
748  lua_pushboolean(L, 0);
749  return 1;
750  }
751  const aiActor_t* actor = lua_toactor(L, 1);
752  assert(actor != nullptr);
753 
754  const char* morStat = "normal";
755  if (actor->actor->isPanicked())
756  morStat = "panic";
757  else if (actor->actor->isInsane())
758  morStat = "insane";
759  else if (actor->actor->isRaged())
760  morStat = "rage";
761  else if (actor->actor->getMorale() <= mor_brave->integer)
762  morStat = "cower";
763 
764  lua_pushstring(L, morStat);
765  return 1;
766 }
767 
771 static int actorL_isinjured (lua_State* L)
772 {
773  /* check parameter */
774  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
776  lua_pushboolean(L, 0);
777  return 1;
778  }
779  const aiActor_t* actor = lua_toactor(L, 1);
780  assert(actor != nullptr);
781 
782  lua_pushboolean(L, G_IsActorWounded(actor->actor, true)
783  || actor->actor->HP <= actor->actor->chr.maxHP * 0.5);
784  return 1;
785 }
786 
790 static int actorL_isarmed (lua_State* L)
791 {
792  /* check parameter */
793  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
795  lua_pushboolean(L, 0);
796  return 1;
797  }
798  const aiActor_t* actor = lua_toactor(L, 1);
799  assert(actor != nullptr);
800 
801  lua_pushboolean(L, actor->actor->getRightHandItem() ? 1 : 0);
802  lua_pushboolean(L, actor->actor->getLeftHandItem() ? 1 : 0);
803  return 2;
804 }
805 
809 static int actorL_isdead (lua_State* L)
810 {
811  /* check parameter */
812  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
814  lua_pushboolean(L, 0);
815  return 1;
816  }
817  const aiActor_t* actor = lua_toactor(L, 1);
818  assert(actor != nullptr);
819 
820  lua_pushboolean(L, actor->actor->isDead());
821  return 1;
822 }
823 
827 static int actorL_isvalidtarget (lua_State* L)
828 {
829  assert(lua_isactor(L, 1));
830 
831  const aiActor_t* target = lua_toactor(L, 1);
832  assert(target != nullptr);
833  lua_pushboolean(L, AI_IsHostile(AIL_ent, target->actor));
834  return 1;
835 }
836 
837 
847 static int pos3L_register (lua_State* L)
848 {
849  /* Create the metatable */
850  luaL_newmetatable(L, POS3_METATABLE);
851 
852  /* Create the access table */
853  lua_pushvalue(L, -1);
854  lua_setfield(L, -2, "__index");
855 
856  /* Register the values */
857  luaL_setfuncs(L, pos3L_methods, 0);
858 
859  /* Clean up the stack. */
860  lua_pop(L, 1);
861 
862  return 0; /* No error */
863 }
864 
871 static int lua_ispos3 (lua_State* L, int index)
872 {
873  if (lua_getmetatable(L, index) == 0)
874  return 0;
875  lua_getfield(L, LUA_REGISTRYINDEX, POS3_METATABLE);
876 
877  int ret = 0;
878  if (lua_rawequal(L, -1, -2)) /* does it have the correct metatable? */
879  ret = 1;
880 
881  lua_pop(L, 2); /* remove both metatables */
882  return ret;
883 }
884 
888 static pos3_t* lua_topos3 (lua_State* L, int index)
889 {
890  if (lua_ispos3(L, index)) {
891  return (pos3_t*) lua_touserdata(L, index);
892  }
893  luaL_typeerror(L, index, POS3_METATABLE);
894  return nullptr;
895 }
896 
900 static pos3_t* lua_pushpos3 (lua_State* L, pos3_t* pos)
901 {
902  pos3_t* p = (pos3_t*) lua_newuserdata(L, sizeof(pos3_t));
903  memcpy(p, pos, sizeof(*p));
904  luaL_getmetatable(L, POS3_METATABLE);
905  lua_setmetatable(L, -2);
906  return p;
907 }
908 
912 static int pos3L_tostring (lua_State* L)
913 {
914  char buf[MAX_VAR];
915 
916  assert(lua_ispos3(L, 1));
917 
918  const pos3_t* p = lua_topos3(L, 1);
919  Com_sprintf(buf, sizeof(buf), "Pos3( x=%d, y=%d, z=%d )", (*p)[0], (*p)[1], (*p)[2]);
920 
921  lua_pushstring(L, buf);
922  return 1;
923 }
924 
928 static int pos3L_goto (lua_State* L)
929 {
930  assert(lua_ispos3(L, 1));
931 
932  /* Calculate move table. */
934  gi.MoveStore(level.pathingMap);
935 
936  /* Move. */
937  const pos3_t* pos = lua_topos3(L, 1);
938  /* do the move */
939  for (;;) {
940  if (AIL_ent->isDead())
941  break;
942  G_ClientMove(*AIL_player, 0, AIL_ent, *pos);
943  if (AIL_ent->isSamePosAs(*pos))
944  break;
945  const pos_t length = G_ActorMoveLength(AIL_ent, level.pathingMap, *pos, false);
947  break;
948  }
949 
950  lua_pushboolean(L, AIL_ent->isSamePosAs(*pos));
951  return 1;
952 }
953 
957 static int pos3L_face (lua_State* L)
958 {
959  assert(lua_ispos3(L, 1));
960 
961  const pos3_t* pos = lua_topos3(L, 1);
963 
964  lua_pushboolean(L, 1);
965  return 1;
966 }
967 
971 static int pos3L_distance (lua_State* L)
972 {
973  assert(lua_ispos3(L, 1));
974 
975  pos3_t* pos = lua_topos3(L, 1);
976  assert(pos != nullptr);
977 
978  ailSortCritType_t distType = AILSC_DIST;
979  if (lua_gettop(L) > 1)
980  distType = AIL_toDistInt(L, 2);
981 
982  switch (distType) {
983  case AILSC_PATH:
984  /* Find a path to the target pos */
986  lua_pushnumber(L, ROUTING_NOT_REACHABLE);
987  return 1;
988  }
989  lua_pushnumber(L, G_ActorMoveLength(AIL_ent, level.pathingMap, *pos, false));
990  return 1;
991  case AILSC_DIST:
992  default:
993  vec3_t to;
994  PosToVec(*pos, to);
995  lua_pushnumber(L, VectorDist(AIL_ent->origin, to));
996  return 1;
997  }
998 }
999 
1003 /*
1004  * General functions.
1005  */
1006 
1010 static int AIL_print (lua_State* L)
1011 {
1012  const int n = lua_gettop(L); /* number of arguments */
1013 
1014  for (int i = 1; i <= n; i++) {
1015  const char* s;
1016  bool meta = false;
1017 
1018  lua_pushvalue(L, i); /* value to print */
1019  if (luaL_callmeta(L, -1, "__tostring")) {
1020  s = lua_tostring(L, -1);
1021  meta = true;
1022  } else {
1023  switch (lua_type(L, -1)) {
1024  case LUA_TNUMBER:
1025  case LUA_TSTRING:
1026  s = lua_tostring(L, -1);
1027  break;
1028  case LUA_TBOOLEAN:
1029  s = lua_toboolean(L, -1) ? "true" : "false";
1030  break;
1031  case LUA_TNIL:
1032  s = "nil";
1033  break;
1034 
1035  default:
1036  s = "unknown lua type";
1037  break;
1038  }
1039  }
1040  gi.DPrintf("%s%s", (i > 1) ? "\t" : "", s);
1041  lua_pop(L, 1); /* Pop the value */
1042  if (meta) /* Meta creates an additional string. */
1043  lua_pop(L, 1);
1044  }
1045 
1046  gi.DPrintf("\n");
1047  return 0;
1048 }
1049 
1050 /*
1051  * Player functions.
1052  */
1053 
1057 static int AIL_squad (lua_State* L)
1058 {
1059  if (g_ailua->integer < 2) {
1060  gi.DPrintf("Problem while running lua: attempt to get the player's team while not in team mode.");
1061  lua_pushnil(L);
1062  return 1;
1063  }
1064 
1065  /* New Lua table. */
1066  lua_newtable(L);
1067 
1068  int i = 1; /* LUA indexes starting from one */
1069  Actor* check = nullptr;
1070  while ((check = G_EdictsGetNextActor(check))) {
1071  if (check->getPlayerNum() != AIL_player->getNum())
1072  continue;
1073  lua_pushnumber(L, i++); /* index */
1074  aiActor_t target;
1075  target.actor = check;
1076  lua_pushactor(L, &target); /* value */
1077  lua_rawset(L, -3); /* store the value in the table */
1078  }
1079  return 1; /* Returns the table of actors. */
1080 }
1081 
1085 static int AIL_select (lua_State* L)
1086 {
1087  if (g_ailua->integer < 2) {
1088  gi.DPrintf("Problem while running lua: attempt to select the active AI actor while not in team mode.");
1089  lua_pushnil(L);
1090  } else if (lua_gettop(L) > 0 && lua_isactor(L, 1)) {
1091  aiActor_t* target = lua_toactor(L, 1);
1092  if (target->actor->getPlayerNum() == AIL_player->getNum())
1093  AIL_ent = target->actor;
1094  lua_pushboolean(L, AIL_ent == target->actor);
1095  } else {
1097  lua_pushboolean(L, false);
1098  }
1099  return 1;
1100 }
1101 
1102 /*
1103  * Actor functions
1104  */
1105 
1109 static int AIL_see (lua_State* L)
1110 {
1111  /* Defaults. */
1112  int team = TEAM_ALL;
1113  ailVisType_t vision = AILVT_ALL;
1114  ailSortCritType_t sortCrit = AILSC_DIST;
1115  bool invTeam = false;
1116 
1117  /* Handle parameters. */
1118  if ((lua_gettop(L) > 0)) {
1119  /* Get what to "see" with. */
1120  vision = AIL_toVisInt(L, 1);
1121 
1122  /* We now check for different teams. */
1123  if ((lua_gettop(L) > 1)) {
1124  if (lua_isstring(L, 2)) {
1125  const char* s = lua_tostring(L, 2);
1126  if (s[0] == '-' || s[0] == '~') {
1127  invTeam = true;
1128  ++s;
1129  }
1130  team = AIL_toTeamInt(s, 2);
1131  /* Trying to see no one? */
1132  if (team == TEAM_ALL && invTeam)
1134  } else
1136  }
1137 
1138  /* Sorting criteria */
1139  if ((lua_gettop(L) > 2)) {
1140  sortCrit = AIL_toSortInt(L, 3);
1141  }
1142  }
1143 
1144  int n = 0;
1145  Actor* check = nullptr;
1146  AilSortTable<Actor*> sortTable[MAX_EDICTS];
1147  /* Get visible things. */
1148  const int visDist = G_VisCheckDist(AIL_ent);
1149  /* We are about to check the team view, update it accordingly */
1150  if (vision == AILVT_TEAM)
1152  while ((check = G_EdictsGetNextLivingActor(check))) {
1153  if (AIL_ent == check)
1154  continue;
1155  const float distance = VectorDistSqr(AIL_ent->pos, check->pos);
1156  /* Check for team match if needed. */
1157  if ((team == TEAM_ALL || (check->getTeam() == team ? !invTeam : invTeam))
1158  && (vision == AILVT_ALL
1159  || (vision == AILVT_SIGHT && G_Vis(AIL_ent->getTeam(), AIL_ent, check, VT_NOFRUSTUM))
1160  || (vision == AILVT_TEAM && G_IsVisibleForTeam(check, AIL_ent->getTeam()))
1161  || (vision == AILVT_DIST && distance <= visDist * visDist))) {
1162  switch (sortCrit) {
1163  case AILSC_PATH:
1164  {
1166  if (G_FindPath(0, AIL_ent, AIL_ent->pos, check->pos, false, 0xFE))
1167  move = gi.MoveLength(level.pathingMap, check->pos, 0, false);
1168  sortTable[n].sortLookup = move;
1169  }
1170  break;
1171  case AILSC_HP:
1172  sortTable[n].sortLookup = check->HP;
1173  break;
1174  case AILSC_DIST:
1175  default:
1176  sortTable[n].sortLookup = VectorDistSqr(AIL_ent->pos, check->pos);
1177  break;
1178  }
1179  sortTable[n++].data = check;
1180  }
1181  }
1182 
1183  /* Sort by given criterion - lesser first. */
1184  std::sort(sortTable, sortTable + n);
1185 
1186  /* Now save it in a Lua table. */
1187  lua_newtable(L);
1188  for (int i = 0; i < n; i++) {
1189  lua_pushnumber(L, i + 1); /* index, starts with 1 */
1190  aiActor_t target;
1191  target.actor = sortTable[i].data;
1192  lua_pushactor(L, &target); /* value */
1193  lua_rawset(L, -3); /* store the value in the table */
1194  }
1195  return 1; /* Returns the table of actors. */
1196 }
1197 
1201 static int AIL_crouch (lua_State* L)
1202 {
1203  if (lua_gettop(L) > 0) {
1204  if (lua_isboolean(L, 1)) {
1205  const bool reqState = lua_toboolean(L, 1);
1206  const bool state = AIL_ent->isCrouched();
1207  if (reqState != state)
1209  } else
1211  }
1212 
1213  lua_pushboolean(L, AIL_ent->isCrouched());
1214  return 1;
1215 }
1216 
1220 static int AIL_reactionfire (lua_State* L)
1221 {
1222  if (lua_gettop(L) > 0) {
1223  int reactionState = 0;
1224 
1225  if (lua_isstring(L, 1)) {
1226  /* get reaction fire mode */
1227  const char* cmd = lua_tostring(L, 1);
1228  reactionState = Q_streq(cmd, "disable") ? ~STATE_REACTION : STATE_REACTION;
1229  }
1230 
1231  if (reactionState) {
1232  G_ClientStateChange(*AIL_player, AIL_ent, reactionState, true);
1233  } else {
1235  }
1236  }
1237 
1238  lua_pushboolean(L, AIL_ent->isReaction());
1239  return 1;
1240 }
1241 
1245 static int AIL_roundsleft (lua_State* L)
1246 {
1247  /* Right hand */
1248  const Item* rightHand = AIL_ent->getRightHandItem();
1249  if (rightHand && (rightHand->def()->ammo < 1 || rightHand->getAmmoLeft() > 0))
1250  lua_pushnumber(L, rightHand->getAmmoLeft());
1251  else
1252  /* Currently unusable */
1253  lua_pushnil(L);
1254 
1255  /* Left hand */
1256  const Item* leftHand = AIL_ent->getLeftHandItem();
1257  if (leftHand && (leftHand->def()->ammo < 1 || leftHand->getAmmoLeft() > 0))
1258  lua_pushnumber(L, leftHand->getAmmoLeft());
1259  else
1260  lua_pushnil(L);
1261  return 2;
1262 }
1263 
1267 static int AIL_canreload (lua_State* L)
1268 {
1269  lua_pushboolean(L, G_ClientCanReload(AIL_ent, CID_RIGHT));
1270  lua_pushboolean(L, G_ClientCanReload(AIL_ent, CID_LEFT));
1271  return 2;
1272 }
1273 
1277 static int AIL_reload (lua_State* L)
1278 {
1279  containerIndex_t container = CID_RIGHT; /* Default to right hand. */
1280 
1281  if (lua_gettop(L) > 0) {
1282  if (lua_isstring(L, 1)) {
1283  const char* s = lua_tostring(L, 1);
1284 
1285  if (Q_streq(s, "right")) {
1286  container = CID_RIGHT;
1287  } else if (Q_streq(s, "left")) {
1288  container = CID_LEFT;
1289  } else {
1291  return 0;
1292  }
1293  } else {
1295  return 0;
1296  }
1297  }
1298 
1299  AI_TryToReloadWeapon(AIL_ent, container);
1300  return 0;
1301 }
1302 
1306 static int AIL_grabweapon (lua_State* L)
1307 {
1308  lua_pushboolean(L, G_ClientGetWeaponFromInventory(AIL_ent));
1309  return 1;
1310 }
1311 
1315 static int AIL_positionshoot (lua_State* L)
1316 {
1317  /* We need a target. */
1318  assert(lua_isactor(L, 1));
1319  aiActor_t* target = lua_toactor(L, 1);
1320 
1321  /* Make things more simple. */
1322  Actor* actor = AIL_ent;
1323 
1324  /* Shooting strategy */
1325  ailShootPosType_t posType = AILSP_FAST;
1326  if ((lua_gettop(L) > 1))
1327  posType = AIL_toShotPInt(L, 2);
1328 
1329  /* Number of TU to spend shooting, to make sure we have enough tus to actually fire. */
1330  int tus = actor->getUsableTUs();
1331  if (lua_gettop(L) > 2) {
1332  assert(lua_isnumber(L, 3)); /* Must be a number. */
1333 
1334  tus = std::min(static_cast<int>(lua_tonumber(L, 3)), tus);
1335  }
1336 
1337  /* Don't shoot units under our control */
1338  if (!AI_IsHostile(actor, target->actor)) {
1339  lua_pushboolean(L, 0);
1340  return 1;
1341  }
1342 
1343  shoot_types_t shootType = ST_RIGHT;
1344  const Item* item = AI_GetItemForShootType(shootType, AIL_ent);
1345  if (item == nullptr) {
1346  shootType = ST_LEFT;
1347  item = AI_GetItemForShootType(shootType, AIL_ent);
1348  }
1349 
1350  /* Check for weapon. */
1351  if (item == nullptr) {
1352  lua_pushboolean(L, 0);
1353  return 1;
1354  }
1355  const fireDef_t* fd = item->getFastestFireDef();
1356  if (fd == nullptr) {
1357  lua_pushboolean(L, 0);
1358  return 1;
1359  }
1360 
1361  int fdTime = G_ActorGetModifiedTimeForFiredef(AIL_ent, fd, false);
1362  if (tus - fdTime <= 0) {
1363  lua_pushboolean(L, 0);
1364  return 1;
1365  }
1366 
1367  /* Calculate move table. */
1368  G_MoveCalc(0, actor, actor->pos, tus);
1369  gi.MoveStore(level.pathingMap);
1370 
1371  /* set borders */
1372  const int rad = (tus + 1) / TU_MOVE_STRAIGHT;
1373 
1374  pos3_t oldPos;
1375  vec3_t oldOrigin;
1376  VectorCopy(actor->pos, oldPos);
1377  VectorCopy(actor->origin, oldOrigin);
1378 
1379  /* evaluate moving to every possible location in the search area,
1380  * including combat considerations */
1381  float bestScore = 0.0f;
1382  pos3_t to, bestPos;
1383  VectorSet(bestPos, 0, 0, PATHFINDING_HEIGHT);
1384  AiAreaSearch searchArea(oldPos, rad);
1385  while (searchArea.getNext(to)) {
1386  actor->setOrigin(to);
1387  const pos_t move = G_ActorMoveLength(actor, level.pathingMap, to, true);
1388  if (move > tus || move == ROUTING_NOT_REACHABLE)
1389  continue;
1390  if (!AI_CheckPosition(actor, actor->pos))
1391  continue;
1392  /* Can we see the target? */
1393  if (!G_IsVisibleForTeam(target->actor, actor->getTeam()) && G_ActorVis(actor, target->actor, true) < ACTOR_VIS_10)
1394  continue;
1395 
1396  const float dist = VectorDist(actor->origin, target->actor->origin);
1397  int dummy = NONE;
1398  const float bestDmg = AIL_GetBestShot(*actor, *target->actor, tus - move, dist, dummy, dummy, dummy);
1399  if (dummy == NONE)
1400  continue;
1401 
1402  float score;
1403  switch (posType) {
1404  case AILSP_NEAR:
1405  score = -dist;
1406  break;
1407  case AILSP_FAR:
1408  score = dist;
1409  break;
1410  case AILSP_DMG:
1411  score = bestDmg;
1412  break;
1413  case AILSP_FAST:
1414  default:
1415  score = -move;
1416  break;
1417  }
1418  if (score > bestScore || bestPos[2] >= PATHFINDING_HEIGHT) {
1419  VectorCopy(to, bestPos);
1420  bestScore = score;
1421  }
1422  }
1423 
1424  VectorCopy(oldPos, actor->pos);
1425  VectorCopy(oldOrigin, actor->origin);
1426 
1427  /* No position found in range. */
1428  if (bestPos[2] >= PATHFINDING_HEIGHT) {
1429  lua_pushboolean(L, 0);
1430  return 1;
1431  }
1432 
1433  /* Return the spot. */
1434  lua_pushpos3(L, &bestPos);
1435  return 1;
1436 }
1437 
1443 static int AIL_positionhide (lua_State* L)
1444 {
1445  int hidingTeam = AI_GetHidingTeam(AIL_ent);
1446 
1447  /* parse parameter */
1448  if (lua_gettop(L)) {
1449  if (lua_isstring(L, 1)) {
1450  const char* s = lua_tostring(L, 1);
1451  bool invTeam = false;
1452  if (s[0] == '-' || s[0] == '~') {
1453  invTeam = true;
1454  ++s;
1455  }
1456  const int team = AIL_toTeamInt(s, 1);
1457  if (team == TEAM_ALL)
1459  else if (invTeam)
1460  hidingTeam = -team;
1461  else
1462  hidingTeam = team;
1463  } else {
1465  }
1466  }
1467 
1468  int tus = AIL_ent->getUsableTUs();
1469  /* parse parameter */
1470  if (lua_gettop(L) > 1) {
1471  if (lua_isnumber(L, 2)) {
1472  tus = std::min(static_cast<int>(lua_tonumber(L, 2)), tus);
1473  } else {
1475  }
1476  }
1477 
1478  pos3_t save;
1479  VectorCopy(AIL_ent->pos, save);
1480 
1481  if (AI_FindHidingLocation(hidingTeam, AIL_ent, AIL_ent->pos, tus)) {
1482  /* Return the spot. */
1483  lua_pushpos3(L, &AIL_ent->pos);
1484  } else {
1485  lua_pushboolean(L, 0);
1486  }
1487  AIL_ent->setOrigin(save);
1488  return 1;
1489 }
1490 
1499 static int AIL_positionherd (lua_State* L)
1500 {
1501  /* check parameter */
1502  if (!(lua_gettop(L) && lua_isactor(L, 1))) {
1504  lua_pushboolean(L, 0);
1505  return 1;
1506  }
1507  const aiActor_t* target = lua_toactor(L, 1);
1508 
1509  int tus = AIL_ent->getUsableTUs();
1510  /* parse parameter */
1511  if (lua_gettop(L) > 1) {
1512  if (lua_isnumber(L, 2)) {
1513  tus = std::min(static_cast<int>(lua_tonumber(L, 2)), tus);
1514  } else {
1516  }
1517  }
1518 
1519  bool inverse = false;
1520  if (lua_gettop(L) > 2) {
1521  if (lua_isboolean(L, 3))
1522  inverse = lua_toboolean(L, 3);
1523  else
1525  }
1526 
1527  pos3_t save;
1528  VectorCopy(AIL_ent->pos, save);
1529  if (AI_FindHerdLocation(AIL_ent, AIL_ent->pos, target->actor->origin, tus, inverse)) {
1530  lua_pushpos3(L, &AIL_ent->pos);
1531  } else {
1532  lua_pushboolean(L, 0);
1533  }
1534  AIL_ent->setOrigin(save);
1535  return 1;
1536 }
1537 
1541 static int AIL_positionapproach (lua_State* L)
1542 {
1543  /* check parameter */
1544  if (!(lua_gettop(L) && lua_ispos3(L, 1))) {
1546  lua_pushboolean(L, 0);
1547  return 1;
1548  }
1549 
1550  const pos3_t* target = lua_topos3(L, 1);
1551  assert(target != nullptr);
1552 
1553  int tus = AIL_ent->getUsableTUs();
1554  if (lua_gettop(L) > 1) {
1555  if (lua_isnumber(L, 2))
1556  tus = std::min(static_cast<int>(lua_tonumber(L, 2)), tus);
1557  else
1559  }
1560 
1561  bool hide = false;
1562  if (lua_gettop(L) > 2){
1563  if (lua_isboolean(L, 3))
1564  hide = lua_toboolean(L, 3);
1565  else
1567  }
1568 
1569  /* Find a path to the target actor */
1570  const int maxTUs = ROUTING_NOT_REACHABLE - 1;
1571  pos3_t to;
1572  VectorCopy(*target, to);
1573  byte crouchingState = AIL_ent->isCrouched() ? 1 : 0;
1574  if (!G_FindPath(0, AIL_ent, AIL_ent->pos, to, crouchingState, maxTUs)) {
1575  /* Not found */
1576  lua_pushboolean(L, 0);
1577  return 1;
1578  }
1579 
1580  /* Find the farthest we can go with current TUs */
1581  int dvec;
1582  while ((dvec = gi.MoveNext(level.pathingMap, to, crouchingState)) != ROUTING_UNREACHABLE) {
1583  /* Note: here we skip the first position so we don't try to walk into the target */
1584  PosSubDV(to, crouchingState, dvec);
1586  continue;
1587  if (!AI_CheckPosition(AIL_ent, to))
1588  continue;
1589  const byte length = G_ActorMoveLength(AIL_ent, level.pathingMap, to, false);
1590  if (length <= tus)
1591  break;
1592  /* We are going backwards to the origin. */
1593  }
1594 
1595  if (AIL_ent->isSamePosAs(to))
1596  lua_pushboolean(L, 0);
1597  else
1598  lua_pushpos3(L, &to);
1599  return 1;
1600 }
1601 
1605 static int AIL_missiontargets (lua_State* L)
1606 {
1607 
1608  /* Defaults. */
1609  int team = TEAM_ALL;
1610  ailVisType_t vision = AILVT_ALL;
1611  ailSortCritType_t sortCrit = AILSC_DIST;
1612  bool invTeam = false;
1613 
1614  /* Handle parameters. */
1615  if ((lua_gettop(L) > 0)) {
1616  /* Get what to "see" with. */
1617  vision = AIL_toVisInt(L, 1);
1618 
1619  /* We now check for different teams. */
1620  if ((lua_gettop(L) > 1)) {
1621  if (lua_isstring(L, 2)) {
1622  const char* s = lua_tostring(L, 2);
1623  if (s[0] == '-' || s[0] == '~') {
1624  invTeam = true;
1625  ++s;
1626  }
1627  team = AIL_toTeamInt(s, 2);
1628  /* Trying to see no one? */
1629  if (team == TEAM_ALL && invTeam)
1631  } else
1633  }
1634 
1635  /* Sorting criteria */
1636  if ((lua_gettop(L) > 2))
1637  sortCrit = AIL_toDistInt(L, 3);
1638  }
1639 
1640  int n = 0;
1641  AilSortTable<Edict*> sortTable[MAX_EDICTS];
1642  /* Get visible things. */
1643  const int visDist = G_VisCheckDist(AIL_ent);
1644  Edict* mission = nullptr;
1645  while ((mission = G_EdictsGetNextInUse(mission))) {
1646  if (mission->type != ET_MISSION)
1647  continue;
1648  const float distance = VectorDistSqr(AIL_ent->pos, mission->pos);
1649  /* Check for team match if needed. */
1650  if ((team == TEAM_ALL || (mission->getTeam() == team ? !invTeam : invTeam))
1651  && (vision == AILVT_ALL
1652  || (vision == AILVT_SIGHT && !G_TestLineWithEnts(AIL_ent->origin, mission->origin))
1653  || (vision == AILVT_DIST && distance <= visDist * visDist))) {
1654  switch (sortCrit) {
1655  case AILSC_PATH:
1656  {
1658  if (G_FindPath(0, AIL_ent, AIL_ent->pos, mission->pos, false, ROUTING_NOT_REACHABLE - 1))
1659  move = gi.MoveLength(level.pathingMap, mission->pos, 0, false);
1660  sortTable[n].sortLookup = move;
1661  }
1662  break;
1663  case AILSC_DIST:
1664  default:
1665  sortTable[n].sortLookup = VectorDistSqr(AIL_ent->pos, mission->pos);
1666  break;
1667  }
1668  sortTable[n++].data = mission;
1669  }
1670  }
1671 
1672  /* Sort by given criterion - lesser first. */
1673  std::sort(sortTable, sortTable + n);
1674 
1675  /* Now save it in a Lua table. */
1676  lua_newtable(L);
1677  for (int i = 0; i < n; i++) {
1678  lua_pushnumber(L, i + 1); /* index, starts with 1 */
1679  lua_pushpos3(L, &sortTable[i].data->pos); /* value */
1680  lua_rawset(L, -3); /* store the value in the table */
1681  }
1682  return 1; /* Returns the table of positions. */
1683 }
1684 
1688 static int AIL_waypoints (lua_State* L)
1689 {
1690  const float minEnemyDist = 160.0f;
1691  /* Min distance to waypoint */
1692  float minDist = 800.0f;
1693  if (lua_gettop(L) > 0) {
1694  if (lua_isnumber(L, 1))
1695  minDist = lua_tonumber(L, 1);
1696  else
1698  }
1699 
1700  /* Sorting criteria */
1701  ailSortCritType_t sortCrit = AILSC_DIST;
1702  if ((lua_gettop(L) > 1))
1703  sortCrit = AIL_toDistInt(L, 2);
1704 
1705  int n = 0;
1706  AilSortTable<Edict*> sortTable[MAX_EDICTS];
1707  for (Edict* checkPoint = level.ai_waypointList; checkPoint != nullptr; checkPoint = checkPoint->groupChain) {
1708  if (checkPoint->inuse)
1709  continue;
1710  if (checkPoint->getTeam() != AIL_ent->getTeam())
1711  continue;
1712  /* Don't walk to enemy ambush */
1713  Actor* check = nullptr;
1714  bool ambush = false;
1715  while ((check = G_EdictsGetNextLivingActorOfTeam(check, TEAM_ALIEN))) {
1716  const float dist = VectorDist(AIL_ent->origin, check->origin);
1717  /* @todo add visibility check here? */
1718  if (dist < minEnemyDist) {
1719  ambush = true;
1720  break;
1721  }
1722  }
1723  if (ambush)
1724  continue;
1725  switch (sortCrit) {
1726  case AILSC_PATH:
1727  {
1729  if (G_FindPath(0, AIL_ent, AIL_ent->pos, checkPoint->pos, false, ROUTING_NOT_REACHABLE - 1))
1730  move = gi.MoveLength(level.pathingMap, checkPoint->pos, 0, false);
1731  if (move < minDist * TU_MOVE_STRAIGHT)
1732  continue;
1733  if (checkPoint->count < AIL_ent->count) {
1734  sortTable[n].sortLookup = move;
1735  sortTable[++n].data = checkPoint;
1736  }
1737  }
1738  break;
1739  case AILSC_DIST:
1740  default:
1741  {
1742  const float dist = VectorDist(AIL_ent->origin, checkPoint->origin);
1743  if (dist < minDist * UNIT_SIZE)
1744  continue;
1745  if (checkPoint->count < AIL_ent->count) {
1746  sortTable[n].sortLookup = dist;
1747  sortTable[++n].data = checkPoint;
1748  }
1749  }
1750  break;
1751  }
1752  }
1753 
1754  /* Sort by distance */
1755  std::sort(sortTable, sortTable + n);
1756 
1757  /* Now save it in a Lua table. */
1758  lua_newtable(L);
1759  for (int i = 0; i < n; i++) {
1760  lua_pushnumber(L, i + 1); /* index, starts with 1 */
1761  lua_pushpos3(L, &sortTable[i].data->pos); /* value */
1762  lua_rawset(L, -3); /* store the value in the table */
1763  }
1764  return 1; /* Returns the table of positions. */
1765 }
1766 
1771 static int AIL_positionmission (lua_State* L)
1772 {
1773  /* check parameter */
1774  if (!(lua_gettop(L) && lua_ispos3(L, 1))) {
1776  lua_pushboolean(L, 0);
1777  return 1;
1778  }
1779  const pos3_t* target = lua_topos3(L, 1);
1780  int tus = AIL_ent->getUsableTUs();
1781  if (lua_gettop(L) > 1) {
1782  if (lua_isnumber(L, 2))
1783  tus = lua_tonumber(L, 2);
1784  else
1786  }
1787  G_MoveCalc(0, AIL_ent, AIL_ent->pos, tus);
1788  gi.MoveStore(level.pathingMap);
1789 
1790  pos3_t oldPos;
1792  int radius = 3;
1793  const Edict* const mission = G_GetEdictFromPos(*target, ET_MISSION);
1794  if (mission)
1795  radius = mission->radius;
1796  if (AI_FindMissionLocation(AIL_ent, *target, tus, radius))
1797  lua_pushpos3(L, &AIL_ent->pos);
1798  else
1799  lua_pushboolean(L, 0);
1800 
1802  return 1;
1803 }
1804 
1809 static int AIL_positionwander (lua_State* L)
1810 {
1811  /* Calculate move table. */
1813  gi.MoveStore(level.pathingMap);
1814 
1815  /* Set defaults */
1816  int radius = (AIL_ent->getUsableTUs() + 1) / TU_MOVE_STRAIGHT;
1817  pos3_t center;
1818  VectorCopy(AIL_ent->pos, center);
1819  int method = AILPW_RAND;
1820  int tus = AIL_ent->getUsableTUs();
1821 
1822  /* Check parameters */
1823  if (lua_gettop(L) > 0)
1824  method = AIL_toWanderPInt(L, 1);
1825  if (lua_gettop(L) > 1) {
1826  if (lua_isnumber(L, 2))
1827  radius = lua_tonumber(L, 2);
1828  else
1830  }
1831  if (lua_gettop(L) > 2) {
1832  if (lua_ispos3(L, 3))
1833  VectorCopy(*lua_topos3(L, 3), center);
1834  else
1836  }
1837 
1838  if (lua_gettop(L) > 3) {
1839  if (lua_isnumber(L, 4))
1840  tus = std::min(static_cast<int>(lua_tonumber(L, 4)), tus);
1841  else
1843  }
1844 
1845  vec3_t d;
1846  if (method > 0)
1847  VectorSubtract(AIL_ent->pos, center, d);
1848  const int cDir = method > 0 ? (VectorEmpty(d) ? AIL_ent->dir : AngleToDir(static_cast<int>(atan2(d[1], d[0]) * todeg))) : NONE;
1849  float bestScore = 0;
1850  pos3_t bestPos = {0, 0, PATHFINDING_HEIGHT};
1851  pos3_t pos;
1852  AiAreaSearch searchArea(center, radius);
1853  while (searchArea.getNext(pos)) {
1854  const pos_t move = G_ActorMoveLength(AIL_ent, level.pathingMap, pos, true);
1855  if (move >= ROUTING_NOT_REACHABLE || move > tus)
1856  continue;
1857  if (!AI_CheckPosition(AIL_ent, pos))
1858  continue;
1859  float score = 0.0f;
1860  switch (method) {
1861  case AILPW_RAND:
1862  score = rand();
1863  break;
1864  case AILPW_CW:
1865  case AILPW_CCW: {
1866  score = VectorDistSqr(center, pos);
1867  VectorSubtract(pos, center, d);
1868  int dir = AngleToDir(static_cast<int>(atan2(d[1], d[0]) * todeg));
1869  if (!(method == AILPW_CW && dir == dvright[cDir]) && !(method == AILPW_CCW && dir == dvleft[cDir]))
1870  for (int n = 1; n < 8; ++n) {
1871  dir = method == 1 ? dvleft[dir] : dvright[dir];
1872  score /= pow(n * 2.0f, 2);
1873  if ((method == 1 && dir == dvright[cDir]) || (method == 2 && dir == dvleft[cDir]))
1874  break;
1875  }
1876  }
1877  break;
1878  }
1879  if (score > bestScore) {
1880  bestScore = score;
1881  VectorCopy(pos, bestPos);
1882  }
1883  }
1884 
1885  if (bestPos[2] >= PATHFINDING_HEIGHT) {
1886  lua_pushboolean(L, 0);
1887  return 1;
1888  }
1889  lua_pushpos3(L, &bestPos);
1890  return 1;
1891 }
1892 
1896 static int AIL_findweapons (lua_State* L)
1897 {
1898  bool full = false;
1899  if (lua_gettop(L) > 0) {
1900  if (lua_isboolean(L, 1))
1901  full = lua_toboolean(L, 1);
1902  else
1904  }
1905 
1906  AilSortTable<Edict*> sortTable[MAX_EDICTS];
1907  int n = 0;
1908  Edict* check = nullptr;
1909  while ((check = G_EdictsGetNextInUse(check))) {
1910  if (check->type != ET_ITEM)
1911  continue;
1912  if(!AI_CheckPosition(AIL_ent, check->pos))
1913  continue;
1915  continue;
1916  const pos_t move = G_ActorMoveLength(AIL_ent, level.pathingMap, check->pos, false);
1917  if (full || move <= AIL_ent->getUsableTUs() - INVDEF(CID_FLOOR)->out - INVDEF(CID_RIGHT)->in) {
1918  for (const Item* item = check->getFloor(); item; item = item->getNext()) {
1920  if (item->isWeapon() && (item->getAmmoLeft() > 0 || item->def()->ammo <= 0)) {
1921  sortTable[n].data = check;
1922  sortTable[n++].sortLookup = move;
1923  break;
1924  }
1925  }
1926  }
1927  }
1928 
1929  /* Sort by distance */
1930  std::sort(sortTable, sortTable + n);
1931 
1932  /* Now save it in a Lua table. */
1933  lua_newtable(L);
1934  for (int i = 0; i < n; i++) {
1935  lua_pushnumber(L, i + 1); /* index, starts with 1 */
1936  lua_pushpos3(L, &sortTable[i].data->pos); /* value */
1937  lua_rawset(L, -3); /* store the value in the table */
1938  }
1939  return 1; /* Returns the table of positions. */
1940 }
1941 
1945 static int AIL_isfighter (lua_State* L)
1946 {
1947  const bool result = AIL_ent->chr.teamDef->weapons || AIL_ent->chr.teamDef->onlyWeapon;
1948  lua_pushboolean(L, result);
1949  return 1;
1950 }
1951 
1955 static int AIL_setwaypoint (lua_State* L)
1956 {
1957  /* No waypoint, reset the count value to restart the search */
1958  if (lua_gettop(L) < 1 || lua_isnil(L, 1)) {
1959  AIL_ent->count = 100;
1960  lua_pushboolean(L, 1);
1961  } else if (lua_ispos3(L, 1)){
1962  pos3_t pos;
1964  Edict* waypoint = G_GetEdictFromPos(pos, ET_CIVILIANTARGET);
1965  if (waypoint != nullptr) {
1966  AIL_ent->count = waypoint->count;
1967  lua_pushboolean(L, 1);
1968  } else
1969  lua_pushboolean(L, 0);
1970  } else
1971  lua_pushboolean(L, 0);
1972 
1973  return 1;
1974 }
1975 
1979 static int AIL_difficulty (lua_State* L)
1980 {
1981  lua_pushnumber(L, g_difficulty->value);
1982  return 1;
1983 }
1984 
1988 static int AIL_positionflee (lua_State* L)
1989 {
1990  int tus = AIL_ent->getUsableTUs();
1991  if (lua_gettop(L)) {
1992  if (lua_isnumber(L, 1))
1993  tus = std::min(static_cast<int>(lua_tonumber(L, 1)), tus);
1994  else
1996  }
1997 
1998  /* Calculate move table. */
2000  pos3_t oldPos;
2002 
2003  const int radius = (tus + 1) / TU_MOVE_STRAIGHT;
2004  float bestScore = -1;
2005  pos3_t bestPos = {0, 0, PATHFINDING_HEIGHT};
2006  AiAreaSearch searchArea(AIL_ent->pos, radius);
2007  while (searchArea.getNext(AIL_ent->pos)) {
2008  const pos_t move = G_ActorMoveLength(AIL_ent, level.pathingMap, AIL_ent->pos, false);
2009  if (move >= ROUTING_NOT_REACHABLE || move > tus)
2010  continue;
2012  continue;
2013  float minDistFoe = -1.0f, minDistFriend = -1.0f;
2014  Actor* check = nullptr;
2015  while ((check = G_EdictsGetNextLivingActor(check))) {
2016  const float dist = VectorDist(AIL_ent->origin, check->origin);
2017  if (check->isSameTeamAs(AIL_ent)) {
2018  if (dist < minDistFriend || minDistFriend < 0.0f)
2019  minDistFriend = dist;
2020  } else if (AI_IsHostile(AIL_ent, check) || AIL_ent->isPanicked()) {
2021  if (dist < minDistFoe || minDistFoe < 0.0f)
2022  minDistFoe = dist;
2023  }
2024  }
2025  float score = minDistFoe - (minDistFriend / GRID_WIDTH);
2026  /* Try to hide */
2027  AIL_ent->calcOrigin();
2029  score /= UNIT_SIZE;
2030  if (score > bestScore) {
2031  bestScore = score;
2032  VectorCopy(AIL_ent->pos, bestPos);
2033  }
2034  }
2036 
2037  if (bestPos[2] == PATHFINDING_HEIGHT) {
2038  lua_pushboolean(L, 0);
2039  } else {
2040  lua_pushpos3(L, &bestPos);
2041  }
2042 
2043  return 1;
2044 }
2045 
2049 static int AIL_weapontype (lua_State* L)
2050 {
2051  const Item* right = AIL_ent->getRightHandItem();
2052  const Item* left = AIL_ent->getLeftHandItem();
2053 
2054  lua_pushstring(L, right ? right->def()->type : "none");
2055  lua_pushstring(L, left ? left->def()->type : "none");
2056 
2057  return 2;
2058 }
2059 
2063 static int AIL_actor (lua_State* L)
2064 {
2065  aiActor_t actor = {AIL_ent};
2066  lua_pushactor(L, &actor);
2067  return 1;
2068 }
2072 static int AIL_tusforshooting (lua_State* L)
2073 {
2074  int bestTUs = 256;
2075  const Item* weapon = AIL_ent->getRightHandItem();
2076  if (weapon) {
2077  const fireDef_t* fd = weapon->getFastestFireDef();
2078  if (fd)
2079  bestTUs = fd->time;
2080  }
2081  weapon = AIL_ent->getLeftHandItem();
2082  if (weapon) {
2083  const fireDef_t* fd = weapon->getFastestFireDef();
2084  if (fd) {
2085  const int tus = weapon->getFastestFireDef()->time;
2086  if (tus < bestTUs)
2087  bestTUs = tus;
2088  }
2089  }
2090 
2091  lua_pushnumber(L, bestTUs);
2092  return 1;
2093 }
2094 
2098 static int AIL_class (lua_State* L)
2099 {
2100  lua_pushstring(L, AIL_ent->AI.subtype);
2101  return 1;
2102 }
2103 
2107 static int AIL_hideneeded (lua_State* L)
2108 {
2109  lua_pushboolean(L, AI_HideNeeded(AIL_ent));
2110  return 1;
2111 }
2112 
2118 void AIL_ActorThink (Player& player, Actor* actor)
2119 {
2120  /* Set the global player and edict */
2121  AIL_ent = actor;
2122  AIL_player = &player;
2123 
2124  /* Try to run the function. */
2125  lua_getglobal(ailState, actor->AI.type);
2126  if (lua_istable(ailState, -1)) {
2127  lua_getfield(ailState, -1, "think");
2128  if (lua_pcall(ailState, 0, 0, 0)) { /* error has occured */
2129  gi.DPrintf("Error while running Lua: %s\n",
2130  lua_isstring(ailState, -1) ? lua_tostring(ailState, -1) : "Unknown Error");
2131  }
2132  } else {
2133  gi.DPrintf("Error while running Lua: AI for %s not found!\n", actor->AI.type);
2134  }
2135 
2136  /* Cleanup */
2137  AIL_ent = nullptr;
2138  AIL_player = nullptr;
2139 }
2140 
2144 static const char* AIL_GetAIType (const int team)
2145 {
2146  const char* type;
2147  switch (team) {
2148  case TEAM_ALIEN:
2149  type = "alien";
2150  break;
2151  case TEAM_CIVILIAN:
2152  type = "civilian";
2153  break;
2154  case TEAM_PHALANX:
2155  default: /* Default to "soldier" AI for multiplayer teams */
2156  type = "soldier";
2157  break;
2158  }
2159  return type;
2160 }
2161 
2166 bool AIL_TeamThink (Player& player)
2167 {
2168  /* Set the global player */
2169  AIL_player = &player;
2170  AIL_ent = nullptr;
2171 
2172  bool thinkAgain = false;
2173  /* Try to run the function. */
2174  lua_getglobal(ailState, AIL_GetAIType(player.getTeam()));
2175  if (lua_istable(ailState, -1)) {
2176  lua_getfield(ailState, -1, "team_think");
2177  if (lua_pcall(ailState, 0, 1, 0)) { /* error has occured */
2178  gi.DPrintf("Error while running Lua: %s\n",
2179  lua_isstring(ailState, -1) ? lua_tostring(ailState, -1) : "Unknown Error");
2180  } else
2181  thinkAgain = lua_toboolean(ailState, -1);
2182  } else {
2183  gi.DPrintf("Error while running Lua: AI for %s not found!\n", AIL_toTeamString(player.getTeam()));
2184  }
2185 
2186  /* Cleanup */
2187  AIL_player = nullptr;
2188  AIL_ent = nullptr;
2189  return thinkAgain;
2190 }
2191 
2195 static lua_State* AIL_InitLua () {
2196  /* Create the Lua state */
2197  lua_State* newState = luaL_newstate();
2198 
2199  /* Register metatables. */
2200  actorL_register(newState);
2201  pos3L_register(newState);
2202 
2203  /* Register libraries. */
2204  lua_newtable(newState);
2205  lua_pushvalue(newState, -1);
2206  lua_setglobal(newState, AI_METATABLE);
2207  luaL_setfuncs(newState, AIL_methods, 0);
2208 
2209  return newState;
2210 }
2216 int AIL_InitActor (Actor* actor)
2217 {
2218  /* Prepare the AI */
2219  AI_t* AI = &actor->AI;
2220  Q_strncpyz(AI->type, AIL_GetAIType(actor->getTeam()), sizeof(AI->type));
2221  Q_strncpyz(AI->subtype, actor->chr.teamDef->id, sizeof(AI->subtype));
2222 
2223  /* Create the a new Lua state if needed */
2224  if (ailState == nullptr)
2225  ailState = AIL_InitLua();
2226 
2227  if (ailState == nullptr) {
2228  gi.DPrintf("Unable to create Lua state.\n");
2229  return -1;
2230  }
2231 
2232  /* Load the AI if needed */
2233  lua_getglobal(ailState, AI->type);
2234  if (!lua_istable(ailState, -1)) {
2235  char path[MAX_VAR];
2236  Com_sprintf(path, sizeof(path), "ai/%s.lua", AI->type);
2237  char* fbuf;
2238  const int size = gi.FS_LoadFile(path, (byte**) &fbuf);
2239  if (size == 0) {
2240  gi.DPrintf("Unable to load Lua file '%s'.\n", path);
2241  return -1;
2242  }
2243  if (luaL_dobuffer(ailState, fbuf, size, path)) {
2244  gi.DPrintf("Unable to parse Lua file '%s'\n", path);
2245  gi.DPrintf("%s\n", lua_isstring(ailState, -1) ? lua_tostring(ailState, -1) : "Unknown Error");
2246  gi.FS_FreeFile(fbuf);
2247  return -1;
2248  }
2249  lua_setglobal(ailState, AI->type);
2250  gi.FS_FreeFile(fbuf);
2251  } else {
2252  lua_pop(ailState, 1);
2253  }
2254 
2255  return 0;
2256 }
2257 
2258 void AIL_Init (void)
2259 {
2260  gi.RegisterConstInt("luaaiteam::phalanx", TEAM_PHALANX);
2261  gi.RegisterConstInt("luaaiteam::civilian", TEAM_CIVILIAN);
2262  gi.RegisterConstInt("luaaiteam::alien", TEAM_ALIEN);
2263  gi.RegisterConstInt("luaaiteam::all", TEAM_ALL);
2264 
2265  gi.RegisterConstInt("luaaivis::all", AILVT_ALL);
2266  gi.RegisterConstInt("luaaivis::sight", AILVT_SIGHT);
2267  gi.RegisterConstInt("luaaivis::team", AILVT_TEAM);
2268  gi.RegisterConstInt("luaaivis::extra", AILVT_DIST);
2269 
2270  gi.RegisterConstInt("luaaisort::dist", AILSC_DIST);
2271  gi.RegisterConstInt("luaaisort::path", AILSC_PATH);
2272  gi.RegisterConstInt("luaaisort::HP", AILSC_HP);
2273 
2274  gi.RegisterConstInt("luaaidist::dist", AILSC_DIST);
2275  gi.RegisterConstInt("luaaidist::path", AILSC_PATH);
2276 
2277  gi.RegisterConstInt("luaaishot::fastest", AILSP_FAST);
2278  gi.RegisterConstInt("luaaishot::nearest", AILSP_NEAR);
2279  gi.RegisterConstInt("luaaishot::farthest", AILSP_FAR);
2280  gi.RegisterConstInt("luaaishot::best_dam", AILSP_DMG);
2281 
2282  gi.RegisterConstInt("luaaiwander::rand", AILPW_RAND);
2283  gi.RegisterConstInt("luaaiwander::CW", AILPW_CW);
2284  gi.RegisterConstInt("luaaiwander::CCW", AILPW_CCW);
2285 
2286  ailState = nullptr;
2287 }
2288 
2289 void AIL_Shutdown (void)
2290 {
2291  gi.UnregisterConstVariable("luaaiteam::phalanx");
2292  gi.UnregisterConstVariable("luaaiteam::civilian");
2293  gi.UnregisterConstVariable("luaaiteam::alien");
2294  gi.UnregisterConstVariable("luaaiteam::all");
2295 
2296  gi.UnregisterConstVariable("luaaivis::all");
2297  gi.UnregisterConstVariable("luaaivis::sight");
2298  gi.UnregisterConstVariable("luaaivis::team");
2299  gi.UnregisterConstVariable("luaaivis::extra");
2300 
2301  gi.UnregisterConstVariable("luaaisort::dist");
2302  gi.UnregisterConstVariable("luaaisort::path");
2303  gi.UnregisterConstVariable("luaaisort::HP");
2304 
2305  gi.UnregisterConstVariable("luaaidist::dist");
2306  gi.UnregisterConstVariable("luaaidist::path");
2307 
2308  gi.UnregisterConstVariable("luaaishot::fastest");
2309  gi.UnregisterConstVariable("luaaishot::nearest");
2310  gi.UnregisterConstVariable("luaaishot::farthest");
2311  gi.UnregisterConstVariable("luaaishot::best_dam");
2312 
2313  gi.UnregisterConstVariable("luaaiwander::rand");
2314  gi.UnregisterConstVariable("luaaiwander::CW");
2315  gi.UnregisterConstVariable("luaaiwander::CCW");
2316 }
2317 
2321 void AIL_Cleanup (void)
2322 {
2323  lua_close(ailState);
2324  ailState = nullptr;
2325 }
static int AIL_tusforshooting(lua_State *L)
Returns the min TUs the actor needs to fire.
Definition: g_ai_lua.cpp:2072
byte dir
Definition: g_edict.h:86
static int AIL_squad(lua_State *L)
Returns a table with the actors in the current player&#39;s team.
Definition: g_ai_lua.cpp:1057
void AIL_Shutdown(void)
Definition: g_ai_lua.cpp:2289
static int actorL_team(lua_State *L)
Gets the actor&#39;s team.
Definition: g_ai_lua.cpp:576
int getMorale() const
Definition: g_edict.h:350
static Player * AIL_player
Definition: g_ai_lua.cpp:247
#define ST_RIGHT
The right hand should be used for shooting.
Definition: q_shared.h:211
static const luaL_Reg AIL_methods[]
Definition: g_ai_lua.cpp:398
const objDef_t * def(void) const
Definition: inv_shared.h:469
bool launched
Definition: inv_shared.h:137
Item * getNext() const
Definition: inv_shared.h:451
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:1688
#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:505
bool G_ClientGetWeaponFromInventory(Actor *actor)
Retrieve or collect a loaded weapon from any linked container for the actor&#39;s right hand...
Definition: g_client.cpp:568
static int actorL_shoot(lua_State *L)
Shoots the actor.
Definition: g_ai_lua.cpp:533
Item * getFloor() const
Definition: g_edict.h:262
#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:2118
#define AIL_invalidparameter(n)
Definition: g_ai_lua.cpp:69
static int actorL_isvalidtarget(lua_State *L)
Check if the actor is a valid target to attack.
Definition: g_ai_lua.cpp:827
bool rolled
Definition: inv_shared.h:138
#define VectorSet(v, x, y, z)
Definition: vector.h:59
ailWanderPosType
Definition: g_ai_lua.cpp:95
#define luaL_dobuffer(L, b, n, s)
Definition: g_ai_lua.cpp:67
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
#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
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:1109
Artificial intelligence of a character.
Definition: g_local.h:305
#define TEAM_ALIEN
Definition: q_shared.h:63
static lua_State * ailState
Definition: g_ai_lua.cpp:63
int getAmmoLeft() const
Definition: inv_shared.h:466
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:1315
static int AIL_reactionfire(lua_State *L)
Sets the actor&#39;s reaction fire mode.
Definition: g_ai_lua.cpp:1220
static int AIL_grabweapon(lua_State *L)
Actor tries to grab a weapon from inventory.
Definition: g_ai_lua.cpp:1306
static int AIL_positionapproach(lua_State *L)
Approach to a target actor.
Definition: g_ai_lua.cpp:1541
static int AIL_positionflee(lua_State *L)
Return a position to flee to.
Definition: g_ai_lua.cpp:1988
Misc utility functions for game module.
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
const fireDef_t * getFiredefs() const
Returns the firedefinitions for a given weapon/ammo.
Definition: inv_shared.cpp:576
Item * getRightHandItem() const
Definition: g_edict.h:249
void G_ClientStateChange(const Player &player, Actor *actor, int reqState, bool checkaction)
Changes the state of a player/soldier.
Definition: g_client.cpp:473
#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 gravity
Definition: inv_shared.h:136
static int actorL_register(lua_State *L)
Registers the actor metatable in the lua_State.
Definition: g_ai_lua.cpp:440
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
const char *IMPORT * GetConstVariable(const char *space, int value)
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
int integer
Definition: cvar.h:81
voidpf void uLong size
Definition: ioapi.h:42
#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:1896
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:743
QGL_EXTERN GLsizei const GLvoid * data
Definition: r_gl.h:89
static int actorL_TU(lua_State *L)
Gets the number of usable TU the actor has left.
Definition: g_ai_lua.cpp:707
#define GRID_WIDTH
absolute max - -GRID_WIDTH up tp +GRID_WIDTH
Definition: defines.h:290
void AIL_Init(void)
Definition: g_ai_lua.cpp:2258
#define TEAM_CIVILIAN
Definition: q_shared.h:61
int getPlayerNum() const
Definition: g_edict.h:234
static int AIL_canreload(lua_State *L)
Checks to see if the actor can reload.
Definition: g_ai_lua.cpp:1267
const teamDef_t * teamDef
Definition: chr_shared.h:413
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:139
const objDef_t * ammoDef(void) const
Definition: inv_shared.h:460
vec3_t origin
Definition: g_edict.h:53
Item * getLeftHandItem() const
Definition: g_edict.h:252
ailShootPosType_t
Shooting position types.
Definition: g_ai_lua.cpp:88
inventory definition for our menus
Definition: inv_shared.h:371
bool isCrouched() const
Definition: g_edict.h:361
#define POS3_METATABLE
Definition: g_ai_lua.cpp:59
bool isSameTeamAs(const Edict *other) const
Definition: g_edict.h:278
#define TU_MOVE_STRAIGHT
Definition: defines.h:74
const fireDef_t * getFastestFireDef() const
Definition: inv_shared.cpp:624
#define STATE_CROUCHED
Definition: q_shared.h:263
const byte dvleft[CORE_DIRECTIONS]
Definition: mathlib.cpp:119
bool getNext(pos3_t pos)
Get next position in the search area.
Definition: g_ai.cpp:79
#define VT_NOFRUSTUM
Definition: g_vis.h:55
Wrapper around edict.
Definition: g_ai_lua.cpp:226
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:60
static int AIL_roundsleft(lua_State *L)
Checks to see how many rounds the actor has left.
Definition: g_ai_lua.cpp:1245
char type[MAX_QPATH]
Definition: g_local.h:306
static int AIL_positionmission(lua_State *L)
Try to find a position nearby to the given position.
Definition: g_ai_lua.cpp:1771
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:1499
#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:2166
#define todeg
Definition: mathlib.h:51
bool weapons
Definition: chr_shared.h:335
int count
Definition: g_edict.h:135
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
Edict * groupChain
Definition: g_edict.h:167
static int AIL_missiontargets(lua_State *L)
Returns the positions of the available mission targets.
Definition: g_ai_lua.cpp:1605
const objDef_t * onlyWeapon
Definition: chr_shared.h:336
bool isDead() const
Definition: g_edict.h:362
static int actorL_HP(lua_State *L)
Gets the number of HP the actor has left.
Definition: g_ai_lua.cpp:725
#define CID_RIGHT
Definition: inv_shared.h:47
Edict * ai_waypointList
Definition: g_local.h:118
cvar_t * g_difficulty
Definition: g_main.cpp:125
game_import_t gi
Definition: g_main.cpp:39
char id[MAX_VAR]
Definition: chr_shared.h:309
#define PosSubDV(p, crouch, dv)
Definition: mathlib.h:254
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:493
#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
Definition: g_edict.h:45
character_t chr
Definition: g_edict.h:116
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:249
static int pos3L_face(lua_State *L)
Makes the actor face the position.
Definition: g_ai_lua.cpp:957
static int AIL_toTeamInt(const char *team, const int param)
Converts team string into int representation.
Definition: g_ai_lua.cpp:125
#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:2144
All parts of the main game logic that are combat related.
const invDef_t * AI_SearchGrenade(const Actor *actor, Item **ip)
Search the edict&#39;s inventory for a grenade or other one-use weapon.
Definition: g_ai.cpp:954
int32_t fireDefIndex_t
Definition: inv_shared.h:78
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:175
bool isHeldTwoHanded() const
Definition: inv_shared.h:476
#define TEAM_ALL
Definition: g_vis.h:32
int getTeam() const
Definition: g_edict.h:269
static int AIL_weapontype(lua_State *L)
Returns the type of the weapons in the actors hands.
Definition: g_ai_lua.cpp:2049
#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:481
#define VectorEmpty(a)
Definition: vector.h:73
static int actorL_pos(lua_State *L)
Gets the actors position.
Definition: g_ai_lua.cpp:521
#define CID_FLOOR
Definition: inv_shared.h:55
static Actor * AIL_ent
Definition: g_ai_lua.cpp:246
static int AIL_hideneeded(lua_State *L)
Check if the actor needs wants to hide.
Definition: g_ai_lua.cpp:2107
item instance data, with linked list capability
Definition: inv_shared.h:402
#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:900
int HP
Definition: g_edict.h:89
bool AI_IsHostile(const Actor *actor, const Edict *target)
Check if actor perceives target as hostile.
Definition: g_ai.cpp:933
#define INVDEF(containerID)
Definition: cl_shared.h:48
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:1809
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:81
QGL_EXTERN GLuint index
Definition: r_gl.h:110
bool isPanicked() const
Definition: g_edict.h:356
#define UNIT_SIZE
Definition: defines.h:121
static int pos3L_distance(lua_State *L)
Return the distance the position an the AI actor.
Definition: g_ai_lua.cpp:971
int ammo
Definition: inv_shared.h:293
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
int32_t containerIndex_t
Definition: inv_shared.h:46
fireDefIndex_t fdIdx
Definition: inv_shared.h:130
static int AIL_class(lua_State *L)
Returns the AI actor&#39;s class.
Definition: g_ai_lua.cpp:2098
AI_t AI
Definition: g_edict.h:171
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:157
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&#39;s builtin print.
Definition: g_ai_lua.cpp:1010
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:928
void calcOrigin()
Calculate the edict&#39;s origin vector from it&#39;s grid position.
Definition: g_edict.h:216
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
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
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:193
#define G_IsDead(ent)
Definition: g_actor.h:34
Actor * actor
Definition: g_ai_lua.cpp:227
Actor * G_EdictsGetNextActor(Actor *lastEnt)
Iterate through the actor entities (even the dead!)
Definition: g_edicts.cpp:231
Local definitions for game module.
weaponFireDefIndex_t weapFdsIdx
Definition: inv_shared.h:126
static int AIL_reload(lua_State *L)
Actor reloads his weapons.
Definition: g_ai_lua.cpp:1277
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:1979
static int AIL_actor(lua_State *L)
Returns the currently moving AI actor.
Definition: g_ai_lua.cpp:2063
#define CID_MAX
Definition: inv_shared.h:57
int radius
Definition: g_edict.h:123
fireDefIndex_t numFiredefs[MAX_WEAPONS_PER_OBJDEF]
Definition: inv_shared.h:315
functions to handle the storage and lifecycle of all edicts in the game module.
entity_type_t type
Definition: g_edict.h:81
char subtype[MAX_VAR]
Definition: g_local.h:307
An Edict of type Actor.
Definition: g_edict.h:348
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
bool isSamePosAs(const pos3_t cmpPos)
Check whether the edict is on the given position.
Definition: g_edict.h:286
static lua_State * AIL_InitLua()
Definition: g_ai_lua.cpp:2195
vec_t vec3_t[3]
Definition: ufotypes.h:39
static int pos3L_register(lua_State *L)
Registers the pos3 metatable in the lua_State.
Definition: g_ai_lua.cpp:847
int getUsableTUs() const
Calculates the amount of usable TUs. This is without the reserved TUs.
Definition: g_edict.h:400
const Item * AI_GetItemForShootType(shoot_types_t shootType, const Edict *ent)
Definition: g_ai.cpp:541
this is a fire definition for our weapons/ammo
Definition: inv_shared.h:110
static const luaL_Reg pos3L_methods[]
Definition: g_ai_lua.cpp:354
cvar_t * mor_brave
Definition: g_main.cpp:104
bool isReaction() const
Definition: g_edict.h:357
float value
Definition: cvar.h:80
bool isRaged() const
Definition: g_edict.h:358
char name[MAX_VAR]
Definition: chr_shared.h:390
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:211
float splrad
Definition: inv_shared.h:161
#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:464
void AIL_Cleanup(void)
Closes the LUA AI.
Definition: g_ai_lua.cpp:2321
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:871
ailVisType_t
vis check types
Definition: g_ai_lua.cpp:73
#define ROUTING_UNREACHABLE
Definition: defines.h:284
float sortLookup
Definition: g_ai_lua.cpp:235
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
const char * type
Definition: inv_shared.h:271
static int AIL_crouch(lua_State *L)
Requests a crouch state (with true/false) and returns current crouch state.
Definition: g_ai_lua.cpp:1201
bool G_TestLineWithEnts(const vec3_t start, const vec3_t end)
fast version of a line trace including entities
Definition: g_utils.cpp:237
#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:1443
bool isInsane() const
Definition: g_edict.h:359
static pos3_t * lua_topos3(lua_State *L, int index)
Returns the pos3 from the metatable at index.
Definition: g_ai_lua.cpp:888
static const char * AIL_toTeamString(const int team)
Converts integer team representation into string.
Definition: g_ai_lua.cpp:110
static int pos3L_tostring(lua_State *L)
Puts the pos3 information in a string.
Definition: g_ai_lua.cpp:912
int AIL_InitActor(Actor *actor)
Initializes the lua AI for an actor.
Definition: g_ai_lua.cpp:2216
#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:1945
#define AI_METATABLE
Definition: g_ai_lua.cpp:61
void setOrigin(const pos3_t newPos)
Set the edict&#39;s pos and origin vector to the given grid position.
Definition: g_edict.h:223
uint8_t byte
Definition: ufotypes.h:34
static int actorL_isarmed(lua_State *L)
Check if actor has weapons.
Definition: g_ai_lua.cpp:790
#define VectorDistSqr(a, b)
Definition: vector.h:68
pos3_t pos
Definition: g_edict.h:55
static int actorL_isinjured(lua_State *L)
Checks to see if the actor is seriously injured.
Definition: g_ai_lua.cpp:771
#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:1955
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:590
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:809
static const luaL_Reg actorL_methods[]
Definition: g_ai_lua.cpp:321
#define MAX_EDICTS
Definition: defines.h:99
static int AIL_select(lua_State *L)
Select an specific AI actor.
Definition: g_ai_lua.cpp:1085
pathing_t * pathingMap
Definition: g_local.h:106