g_ai_lua.c

Go to the documentation of this file.
00001 
00015 /*
00016 Copyright (C) 2002-2010 UFO: Alien Invasion.
00017 
00018 This program is free software; you can redistribute it and/or
00019 modify it under the terms of the GNU General Public License
00020 as published by the Free Software Foundation; either version 2
00021 of the License, or (at your option) any later version.
00022 
00023 This program is distributed in the hope that it will be useful,
00024 but WITHOUT ANY WARRANTY; without even the implied warranty of
00025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00026 
00027 See the GNU General Public License for more details.
00028 
00029 You should have received a copy of the GNU General Public License
00030 along with this program; if not, write to the Free Software
00031 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00032 
00033 */
00034 
00035 #include "g_local.h"
00036 #include "g_ai.h"
00037 #include "lua/lauxlib.h"
00038 
00039 #define POS3_METATABLE  "pos3" 
00040 #define ACTOR_METATABLE "actor" 
00041 #define AI_METATABLE    "ai" 
00046 #define luaL_dobuffer(L, b, n, s) \
00047     (luaL_loadbuffer(L, b, n, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
00048 #define AIL_invalidparameter(n) \
00049     gi.DPrintf("AIL: Invalid parameter #%d in '%s'.\n", n, __func__)
00050 
00051 /*
00052  * Helper functions
00053  */
00054 
00061 static const char *AIL_toTeamString (const int team)
00062 {
00063     const char *teamStr = gi.GetConstVariable("luaaiteam", team);
00064     if (teamStr == NULL)
00065         AIL_invalidparameter(1);
00066     return teamStr;
00067 }
00068 
00075 static int AIL_toTeamInt (const char *team)
00076 {
00077     int teamInt = TEAM_DEFAULT;
00078     if (!gi.GetConstIntFromNamespace("luaaiteam", team, &teamInt))
00079         AIL_invalidparameter(1);
00080     return teamInt;
00081 }
00082 
00086 typedef struct aiActor_s {
00087     edict_t *ent; 
00088 } aiActor_t;
00089 
00090 
00091 /*
00092  * Current AI Actor.
00093  */
00094 static edict_t *AIL_ent; 
00095 static player_t *AIL_player; 
00098 /*
00099  * Actor metatable.
00100  */
00101 /* Internal functions. */
00102 static int actorL_register(lua_State *L);
00103 static int lua_isactor(lua_State *L, int index);
00104 static aiActor_t* lua_toactor(lua_State *L, int index);
00105 static aiActor_t* lua_pushactor(lua_State *L, aiActor_t *actor);
00106 /* Metatable functions. */
00107 static int actorL_tostring(lua_State *L);
00108 static int actorL_pos(lua_State *L);
00109 static int actorL_shoot(lua_State *L);
00110 static int actorL_face(lua_State *L);
00111 static int actorL_team(lua_State *L);
00115 static const luaL_reg actorL_methods[] = {
00116     {"__tostring", actorL_tostring},
00117     {"pos", actorL_pos},
00118     {"shoot", actorL_shoot},
00119     {"face", actorL_face},
00120     {"team", actorL_team},
00121     {NULL, NULL}
00122 };
00123 
00124 
00128 /* Internal functions. */
00129 static int pos3L_register(lua_State *L);
00130 static int lua_ispos3(lua_State *L, int index);
00131 static pos3_t* lua_topos3(lua_State *L, int index);
00132 static pos3_t* lua_pushpos3(lua_State *L, pos3_t *pos);
00133 /* Metatable functions. */
00134 static int pos3L_tostring(lua_State *L);
00135 static int pos3L_goto(lua_State *L);
00136 static int pos3L_face(lua_State *L);
00140 static const luaL_reg pos3L_methods[] = {
00141     {"__tostring", pos3L_tostring},
00142     {"goto", pos3L_goto},
00143     {"face", pos3L_face},
00144     {NULL, NULL}
00145 };
00146 
00147 
00151 static int AIL_print(lua_State *L);
00152 static int AIL_see(lua_State *L);
00153 static int AIL_crouch(lua_State *L);
00154 static int AIL_isinjured(lua_State *L);
00155 static int AIL_TU(lua_State *L);
00156 static int AIL_HP(lua_State *L);
00157 static int AIL_morale(lua_State *L);
00158 static int AIL_reactionfire(lua_State *L);
00159 static int AIL_roundsleft(lua_State *L);
00160 static int AIL_canreload(lua_State *L);
00161 static int AIL_reload(lua_State *L);
00162 static int AIL_positionshoot(lua_State *L);
00163 static int AIL_positionhide(lua_State *L);
00164 static int AIL_positionherd(lua_State *L);
00165 static int AIL_distance(lua_State *L);
00169 static const luaL_reg AIL_methods[] = {
00170     {"print", AIL_print},
00171     {"see", AIL_see},
00172     {"crouch", AIL_crouch},
00173     {"isinjured", AIL_isinjured},
00174     {"TU", AIL_TU},
00175     {"HP", AIL_HP},
00176     {"morale", AIL_morale},
00177     {"reactionfire", AIL_reactionfire},
00178     {"roundsleft", AIL_roundsleft},
00179     {"canreload", AIL_canreload},
00180     {"reload", AIL_reload},
00181     {"positionshoot", AIL_positionshoot},
00182     {"positionhide", AIL_positionhide},
00183     {"positionherd", AIL_positionherd},
00184     {"distance", AIL_distance},
00185     {NULL, NULL}
00186 };
00187 
00188 
00198 static int actorL_register (lua_State *L)
00199 {
00200     /* Create the metatable */
00201     luaL_newmetatable(L, ACTOR_METATABLE);
00202 
00203     /* Create the access table */
00204     lua_pushvalue(L, -1);
00205     lua_setfield(L, -2, "__index");
00206 
00207     /* Register the values */
00208     luaL_register(L, NULL, actorL_methods);
00209 
00210     /* Clean up stack. */
00211     lua_pop(L, 1);
00212 
00213     return 0; /* No error */
00214 }
00215 
00222 static int lua_isactor (lua_State *L, int index)
00223 {
00224     int ret;
00225 
00226     if (lua_getmetatable(L, index) == 0)
00227         return 0;
00228     lua_getfield(L, LUA_REGISTRYINDEX, ACTOR_METATABLE);
00229 
00230     ret = 0;
00231     if (lua_rawequal(L, -1, -2))  /* does it have the correct metatable? */
00232         ret = 1;
00233 
00234     lua_pop(L, 2);  /* remove both metatables */
00235     return ret;
00236 }
00237 
00241 static aiActor_t* lua_toactor (lua_State *L, int index)
00242 {
00243     if (lua_isactor(L, index)) {
00244         return (aiActor_t*) lua_touserdata(L, index);
00245     }
00246     luaL_typerror(L, index, ACTOR_METATABLE);
00247     return NULL;
00248 }
00249 
00253 static aiActor_t* lua_pushactor (lua_State *L, aiActor_t *actor)
00254 {
00255     aiActor_t *a;
00256     a = (aiActor_t*) lua_newuserdata(L, sizeof(*a));
00257     *a = *actor;
00258     luaL_getmetatable(L, ACTOR_METATABLE);
00259     lua_setmetatable(L, -2);
00260     return a;
00261 }
00262 
00266 static int actorL_tostring (lua_State *L)
00267 {
00268     aiActor_t *target;
00269     char buf[MAX_VAR];
00270 
00271     assert(lua_isactor(L, 1));
00272 
00273     target = lua_toactor(L, 1);
00274     Com_sprintf(buf, sizeof(buf), "Actor( %s )", target->ent->chr.name);
00275 
00276     lua_pushstring(L, buf);
00277     return 1;
00278 }
00279 
00283 static int actorL_pos (lua_State *L)
00284 {
00285     aiActor_t *target;
00286 
00287     assert(lua_isactor(L, 1));
00288 
00289     target = lua_toactor(L, 1);
00290     lua_pushpos3(L, &target->ent->pos);
00291     return 1;
00292 }
00293 
00297 static int actorL_shoot (lua_State *L)
00298 {
00299     int tu, shots;
00300     shoot_types_t shootType;
00301     aiActor_t *target;
00302     const item_t *item;
00303     const fireDef_t *fdArray;
00304     objDef_t *od;
00305 
00306     assert(lua_isactor(L, 1));
00307 
00308     /* Target */
00309     target = lua_toactor(L, 1);
00310 
00311     /* Number of TU to spend shooting, fire mode will adjust to that. */
00312     if (lua_gettop(L) > 1) {
00313         assert(lua_isnumber(L, 2)); /* Must be a number. */
00314 
00315         tu = (int) lua_tonumber(L, 2);
00316     } else {
00317         tu = AIL_ent->TU;
00318     }
00319 
00320     shootType = ST_RIGHT;
00321     item = AI_GetItemForShootType(shootType, AIL_ent);
00322     if (item == NULL) {
00323         shootType = ST_LEFT;
00324         item = AI_GetItemForShootType(shootType, AIL_ent);
00325     }
00326 
00327     /* Failure - no weapon. */
00328     if (item == NULL) {
00329         lua_pushboolean(L, 0);
00330         return 1;
00331     }
00332 
00334     fdArray = FIRESH_FiredefForWeapon(item);
00335     if (fdArray == NULL) {
00336         /* Failure - no weapon. */
00337         lua_pushboolean(L, 0);
00338         return 1;
00339     }
00340 
00341     if (!item->m)
00342         od = item->t;
00343     else
00344         od = item->m;
00345 
00346     shots = tu / fdArray->time;
00347 
00348     while (shots > 0) {
00349         shots--;
00351         G_ClientShoot(AIL_player, AIL_ent, target->ent->pos,
00352                 shootType, 0, NULL, qtrue, 0);
00353     }
00354 
00355     /* Success. */
00356     lua_pushboolean(L, 1);
00357     return 1;
00358 }
00359 
00363 static int actorL_face (lua_State *L)
00364 {
00365     aiActor_t *target;
00366 
00367     assert(lua_isactor(L, 1));
00368 
00369     /* Target */
00370     target = lua_toactor(L, 1);
00371 
00372     AI_TurnIntoDirection(AIL_ent, target->ent->pos);
00373 
00374     /* Success. */
00375     lua_pushboolean(L, 1);
00376     return 1;
00377 }
00378 
00382 static int actorL_team (lua_State *L)
00383 {
00384     const aiActor_t *target;
00385     const char *team;
00386 
00387     assert(lua_isactor(L, 1));
00388 
00389     target = lua_toactor(L, 1);
00390     assert(target != NULL);
00391     team = AIL_toTeamString(target->ent->team);
00392     lua_pushstring(L, team);
00393     return 1;
00394 }
00395 
00396 
00406 static int pos3L_register (lua_State *L)
00407 {
00408     /* Create the metatable */
00409     luaL_newmetatable(L, POS3_METATABLE);
00410 
00411     /* Create the access table */
00412     lua_pushvalue(L, -1);
00413     lua_setfield(L, -2, "__index");
00414 
00415     /* Register the values */
00416     luaL_register(L, NULL, pos3L_methods);
00417 
00418     /* Clean up the stack. */
00419     lua_pop(L, 1);
00420 
00421     return 0; /* No error */
00422 }
00423 
00430 static int lua_ispos3 (lua_State *L, int index)
00431 {
00432     int ret;
00433 
00434     if (lua_getmetatable(L, index) == 0)
00435         return 0;
00436     lua_getfield(L, LUA_REGISTRYINDEX, POS3_METATABLE);
00437 
00438     ret = 0;
00439     if (lua_rawequal(L, -1, -2))  /* does it have the correct metatable? */
00440         ret = 1;
00441 
00442     lua_pop(L, 2);  /* remove both metatables */
00443     return ret;
00444 }
00445 
00449 static pos3_t* lua_topos3 (lua_State *L, int index)
00450 {
00451     if (lua_ispos3(L, index)) {
00452         return (pos3_t*) lua_touserdata(L, index);
00453     }
00454     luaL_typerror(L, index, POS3_METATABLE);
00455     return NULL;
00456 }
00457 
00461 static pos3_t* lua_pushpos3 (lua_State *L, pos3_t *pos)
00462 {
00463     pos3_t *p;
00464     p = (pos3_t*) lua_newuserdata(L, sizeof(*p));
00465     memcpy(p, pos, sizeof(*p));
00466     luaL_getmetatable(L, POS3_METATABLE);
00467     lua_setmetatable(L, -2);
00468     return p;
00469 }
00470 
00474 static int pos3L_tostring (lua_State *L)
00475 {
00476     pos3_t *p;
00477     char buf[MAX_VAR];
00478 
00479     assert(lua_ispos3(L, 1));
00480 
00481     p = lua_topos3(L, 1);
00482     Com_sprintf(buf, sizeof(buf), "Pos3( x=%d, y=%d, z=%d )", (*p)[0], (*p)[1], (*p)[2]);
00483 
00484     lua_pushstring(L, buf);
00485     return 1;
00486 }
00487 
00491 static int pos3L_goto (lua_State *L)
00492 {
00493     pos3_t *pos;
00494     const byte crouchingState = G_IsCrouched(AIL_ent) ? 1 : 0;
00495 
00496     assert(lua_ispos3(L, 1));
00497 
00498     /* Calculate move table. */
00499     G_MoveCalc(0, AIL_ent, AIL_ent->pos, crouchingState, AIL_ent->TU);
00500     gi.MoveStore(&level.pathingMap);
00501 
00502     /* Move. */
00503     pos = lua_topos3(L, 1);
00504     G_ClientMove(AIL_player, 0, AIL_ent, *pos);
00505 
00506     lua_pushboolean(L, 1);
00507     return 1;
00508 }
00509 
00513 static int pos3L_face (lua_State *L)
00514 {
00515     pos3_t *pos;
00516 
00517     assert(lua_ispos3(L, 1));
00518 
00519     pos = lua_topos3(L, 1);
00520     AI_TurnIntoDirection(AIL_ent, *pos);
00521 
00522     lua_pushboolean(L, 1);
00523     return 1;
00524 }
00525 
00532 static int AIL_print (lua_State *L)
00533 {
00534     int i;
00535     const int n = lua_gettop(L);  /* number of arguments */
00536 
00537     for (i = 1; i <= n; i++) {
00538         const char *s;
00539         qboolean meta = qfalse;
00540 
00541         lua_pushvalue(L, i);   /* value to print */
00542         if (luaL_callmeta(L, 1, "__tostring")) {
00543             s = lua_tostring(L, -1);
00544             meta = qtrue;
00545         } else {
00546             switch (lua_type(L, -1)) {
00547             case LUA_TNUMBER:
00548             case LUA_TSTRING:
00549                 s = lua_tostring(L, -1);
00550                 break;
00551             case LUA_TBOOLEAN:
00552                 s = lua_toboolean(L, -1) ? "true" : "false";
00553                 break;
00554             case LUA_TNIL:
00555                 s = "nil";
00556                 break;
00557 
00558             default:
00559                 s = "unknown lua type";
00560                 break;
00561             }
00562         }
00563         gi.DPrintf("%s%s", (i > 1) ? "\t" : "", s);
00564         lua_pop(L, 1); /* Pop the value */
00565         if (meta) /* Meta creates an additional string. */
00566             lua_pop(L, 1);
00567     }
00568 
00569     gi.DPrintf("\n");
00570     return 0;
00571 }
00572 
00576 static int AIL_see (lua_State *L)
00577 {
00578     int vision, team;
00579     int i, j, k, n, cur;
00580     edict_t *check = NULL;
00581     aiActor_t target;
00582     edict_t *sorted[MAX_EDICTS], *unsorted[MAX_EDICTS];
00583     float distLookup[MAX_EDICTS];
00584 
00585     /* Defaults. */
00586     team = TEAM_ALL;
00587     vision = 0;
00588 
00589     /* Handle parameters. */
00590     if ((lua_gettop(L) > 0)) {
00591         /* Get what to "see" with. */
00592         if (lua_isstring(L, 1)) {
00593             const char *s = lua_tostring(L, 1);
00596             if (strcmp(s, "all") == 0)
00597                 vision = 0;
00598             else if (strcmp(s, "sight") == 0)
00599                 vision = 1;
00600             else if (strcmp(s, "psionic") == 0)
00601                 vision = 2;
00602             else if (strcmp(s, "infrared") == 0)
00603                 vision = 3;
00604             else
00605                 AIL_invalidparameter(1);
00606         } else
00607             AIL_invalidparameter(1);
00608 
00609         /* We now check for different teams. */
00610         if ((lua_gettop(L) > 1)) {
00611             if (lua_isstring(L, 2)) {
00612                 const char *s = lua_tostring(L, 2);
00613                 team = AIL_toTeamInt(s);
00614             } else
00615                 AIL_invalidparameter(2);
00616         }
00617     }
00618 
00619     n = 0;
00620     /* Get visible things. */
00621     while ((check = G_EdictsGetNextLivingActor(check))) {
00622         if (AIL_ent == check)
00623             continue;
00624         if (vision == 0 && (team == TEAM_ALL || check->team == team) /* Check for team match if needed. */
00625          && G_Vis(AIL_ent->team, AIL_ent, check, VT_NOFRUSTUM)) {
00626             distLookup[n] = VectorDistSqr(AIL_ent->pos, check->pos);
00627             unsorted[n++] = check;
00628         }
00629     }
00630 
00631     /* Sort by distance - nearest first. */
00632     for (i = 0; i < n; i++) { /* Until we fill sorted */
00633         cur = -1;
00634         for (j = 0; j < n; j++) { /* Check for closest */
00635             /* Is shorter then current minimum? */
00636             if (cur < 0 || distLookup[j] < distLookup[cur]) {
00637                 /* Check if not already in sorted. */
00638                 for (k = 0; k < i; k++)
00639                     if (sorted[k] == unsorted[j])
00640                         break;
00641 
00642                 /* Not already sorted and is new minimum. */
00643                 if (k == i)
00644                     cur = j;
00645             }
00646         }
00647 
00648         sorted[i] = unsorted[cur];
00649     }
00650 
00651     /* Now save it in a Lua table. */
00652     lua_newtable(L);
00653     for (i = 0; i < n; i++) {
00654         lua_pushnumber(L, i + 1); /* index, starts with 1 */
00655         target.ent = sorted[i];
00656         lua_pushactor(L, &target); /* value */
00657         lua_rawset(L, -3); /* store the value in the table */
00658     }
00659     return 1; /* Returns the table of actors. */
00660 }
00661 
00665 static int AIL_crouch (lua_State *L)
00666 {
00667     if (lua_gettop(L) > 0) {
00668         if (lua_isboolean(L, 1)) {
00669             const int state = lua_toboolean(L, 1);
00670             G_ClientStateChange(AIL_player, AIL_ent, STATE_CROUCHED,
00671                 (state) ? qtrue : qfalse);
00672         } else
00673             AIL_invalidparameter(1);
00674     }
00675 
00676     lua_pushboolean(L, G_IsCrouched(AIL_ent));
00677     return 1;
00678 }
00679 
00683 static int AIL_isinjured (lua_State *L)
00684 {
00685     lua_pushboolean(L, AIL_ent->HP != AIL_ent->chr.maxHP);
00686     return 1;
00687 }
00688 
00692 static int AIL_TU (lua_State *L)
00693 {
00694     lua_pushnumber(L, AIL_ent->TU);
00695     return 1;
00696 }
00697 
00701 static int AIL_HP (lua_State *L)
00702 {
00703     lua_pushnumber(L, AIL_ent->HP);
00704     return 1;
00705 }
00706 
00710 static int AIL_morale (lua_State *L)
00711 {
00712     lua_pushnumber(L, AIL_ent->morale);
00713     return 1;
00714 }
00715 
00719 static int AIL_reactionfire (lua_State *L)
00720 {
00721     int reactionState = 0;
00722     if (lua_gettop(L) > 0) {
00723 
00724         if (lua_isstring(L, 1)) {
00725             /* get reaction fire mode */
00726             const char* cmd = lua_tostring(L, 1);
00727             reactionState = !strcmp(cmd, "disable") ? ~STATE_REACTION
00728                 : !strcmp(cmd, "once") ? STATE_REACTION_ONCE
00729                 : !strcmp(cmd, "many") ? STATE_REACTION_MANY : 0;
00730         }
00731 
00732         if (reactionState && lua_gettop(L) > 1 && lua_isboolean(L, 2)) {
00733             const int state = lua_toboolean(L, 2);
00734             G_ClientStateChange(AIL_player, AIL_ent, reactionState,
00735                 (state) ? qtrue : qfalse);
00736         } else {
00737             AIL_invalidparameter(reactionState ? 2 : 1);
00738         }
00739     }
00740 
00741     lua_pushboolean(L, G_IsReaction(AIL_ent));
00742     return 1;
00743 }
00744 
00748 static int AIL_roundsleft (lua_State *L)
00749 {
00750     /* Right hand */
00751     if (RIGHT(AIL_ent) && RIGHT(AIL_ent)->item.t->reload)
00752         lua_pushnumber(L, RIGHT(AIL_ent)->item.a);
00753     else
00754         lua_pushnil(L);
00755 
00756     /* Left hand */
00757     if (LEFT(AIL_ent) && LEFT(AIL_ent)->item.t->reload)
00758         lua_pushnumber(L, LEFT(AIL_ent)->item.a);
00759     else
00760         lua_pushnil(L);
00761     return 2;
00762 }
00763 
00767 static int AIL_canreload (lua_State *L)
00768 {
00769     lua_pushboolean(L, G_ClientCanReload(AIL_ent, gi.csi->idRight));
00770     lua_pushboolean(L, G_ClientCanReload(AIL_ent, gi.csi->idLeft));
00771     return 2;
00772 }
00773 
00777 static int AIL_reload (lua_State *L)
00778 {
00779     containerIndex_t container;
00780 
00781     if (lua_gettop(L) > 0) {
00782         if (lua_isstring(L, 1)) {
00783             const char *s = lua_tostring(L, 1);
00784 
00785             if (!strcmp(s, "right"))
00786                 container = gi.csi->idRight;
00787             else if (!strcmp(s, "left"))
00788                 container = gi.csi->idLeft;
00789             else
00790                 return 0;
00791         } else {
00792             AIL_invalidparameter(1);
00793             return 0;
00794         }
00795     } else
00796         container = gi.csi->idRight; /* Default to right hand. */
00797 
00798     G_ActorReload(AIL_ent, INVDEF(container));
00799     return 0;
00800 }
00801 
00805 static int AIL_positionshoot (lua_State *L)
00806 {
00807     pos3_t to, bestPos;
00808     vec3_t check;
00809     edict_t *ent;
00810     int dist;
00811     int xl, yl, xh, yh;
00812     int min_tu;
00813     aiActor_t *target;
00814     const byte crouchingState = G_IsCrouched(AIL_ent) ? 1 : 0;
00815 
00816     /* We need a target. */
00817     assert(lua_isactor(L, 1));
00818     target = lua_toactor(L, 1);
00819 
00820     /* Make things more simple. */
00821     ent = AIL_ent;
00822     dist = ent->TU;
00823 
00824     /* Calculate move table. */
00825     G_MoveCalc(0, ent, ent->pos, crouchingState, ent->TU);
00826     gi.MoveStore(&level.pathingMap);
00827 
00828     /* set borders */
00829     xl = (int) ent->pos[0] - dist;
00830     if (xl < 0)
00831         xl = 0;
00832     yl = (int) ent->pos[1] - dist;
00833     if (yl < 0)
00834         yl = 0;
00835     xh = (int) ent->pos[0] + dist;
00836     if (xh > PATHFINDING_WIDTH)
00837         xl = PATHFINDING_WIDTH;
00838     yh = (int) ent->pos[1] + dist;
00839     if (yh > PATHFINDING_WIDTH)
00840         yh = PATHFINDING_WIDTH;
00841 
00842     /* evaluate moving to every possible location in the search area,
00843      * including combat considerations */
00844     min_tu = INT_MAX;
00845     for (to[2] = 0; to[2] < PATHFINDING_HEIGHT; to[2]++)
00846         for (to[1] = yl; to[1] < yh; to[1]++)
00847             for (to[0] = xl; to[0] < xh; to[0]++) {
00848                 pos_t tu;
00849                 /* Can we see the target? */
00850                 gi.GridPosToVec(gi.routingMap, ent->fieldSize, to, check);
00851                 tu = gi.MoveLength(&level.pathingMap, to, G_IsCrouched(ent) ? 1 : 0, qtrue);
00852                 if (tu > ent->TU || tu == ROUTING_NOT_REACHABLE)
00853                     continue;
00854                 /* Better spot (easier to get to). */
00855                 if (tu < min_tu) {
00856                     if (G_ActorVis(check, target->ent, qtrue) > 0.3) {
00857                         VectorCopy(to, bestPos);
00858                         min_tu = tu;
00859                     }
00860                 }
00861             }
00862 
00863     /* No position found in range. */
00864     if (min_tu > ent->TU) {
00865         lua_pushboolean(L, 0);
00866         return 1;
00867     }
00868 
00869     /* Return the spot. */
00870     lua_pushpos3(L, &bestPos);
00871     return 1;
00872 }
00873 
00879 static int AIL_positionhide (lua_State *L)
00880 {
00881     pos3_t save;
00882     int tus = AIL_ent->TU;
00883     int hidingTeam;
00884 
00885     VectorCopy(AIL_ent->pos, save);
00886 
00887     hidingTeam = AI_GetHidingTeam(AIL_ent);
00888 
00889     /* parse parameter */
00890     if (lua_gettop(L)) {
00891         if (lua_isstring(L, 1)) {
00892             const char* s = lua_tostring(L, 1);
00893             hidingTeam = AIL_toTeamInt(s);
00894             if (hidingTeam == TEAM_ALL)
00895                 AIL_invalidparameter(1);
00896         } else {
00897             AIL_invalidparameter(1);
00898         }
00899     }
00900 
00901     if (AI_FindHidingLocation(hidingTeam, AIL_ent, AIL_ent->pos, &tus)) {
00902         /* Return the spot. */
00903         lua_pushpos3(L, &AIL_ent->pos);
00904     } else {
00905         lua_pushboolean(L, 0);
00906     }
00907     G_EdictSetOrigin(AIL_ent, save);
00908     return 1;
00909 }
00910 
00917 static int AIL_positionherd (lua_State *L)
00918 {
00919     pos3_t save;
00920     aiActor_t* target;
00921         
00922     /* check parameter */
00923     if (!(lua_gettop(L) && lua_isactor(L, 1))) {
00924         AIL_invalidparameter(1);
00925         lua_pushboolean(L, 0);
00926         return 1;
00927     }
00928     
00929     VectorCopy(AIL_ent->pos, save);
00930     target = lua_toactor(L, 1);
00931     if (AI_FindHerdLocation(AIL_ent, AIL_ent->pos, target->ent->origin, AIL_ent->TU)) {
00932         lua_pushpos3(L, &AIL_ent->pos);
00933     } else {
00934         lua_pushboolean(L, 0);
00935     }
00936     G_EdictSetOrigin(AIL_ent, save);
00937     return 1;
00938 }
00939 
00944 static int AIL_distance (lua_State *L)
00945 {
00946     vec_t dist;
00947     aiActor_t* target;
00948     
00949     /* check parameter */
00950     assert(lua_gettop(L) && lua_isactor(L, 1));
00951     
00952     /* calculate distance */
00953     target = lua_toactor(L, 1);
00954     dist = VectorDist(AIL_ent->origin, target->ent->origin);
00955     lua_pushnumber(L, dist);
00956     return 1;
00957 }
00958 
00968 void AIL_ActorThink (player_t * player, edict_t * ent)
00969 {
00970     lua_State *L;
00971 
00972     /* The Lua State we will work with. */
00973     L = ent->AI.L;
00974 
00975     /* Set the global player and edict */
00976     AIL_ent = ent;
00977     AIL_player = player;
00978 
00979     /* Try to run the function. */
00980     lua_getglobal(L, "think");
00981     if (lua_pcall(L, 0, 0, 0)) { /* error has occured */
00982         gi.DPrintf("Error while running Lua: %s\n",
00983             lua_isstring(L, -1) ? lua_tostring(L, -1) : "Unknown Error");
00984     }
00985 
00986     /* Cleanup */
00987     AIL_ent = NULL;
00988     AIL_player = NULL;
00989 }
00990 
00991 
00999 int AIL_InitActor (edict_t * ent, char *type, char *subtype)
01000 {
01001     AI_t *AI;
01002     int size;
01003     char path[MAX_VAR];
01004     char *fbuf;
01005 
01006     /* Prepare the AI */
01007     AI = &ent->AI;
01008     Q_strncpyz(AI->type, type, sizeof(AI->type));
01009     Q_strncpyz(AI->subtype, subtype, sizeof(AI->type));
01010 
01011     /* Create the new Lua state */
01012     AI->L = luaL_newstate();
01013     if (AI->L == NULL) {
01014         gi.DPrintf("Unable to create Lua state.\n");
01015         return -1;
01016     }
01017 
01018     /* Register metatables. */
01019     actorL_register(AI->L);
01020     pos3L_register(AI->L);
01021 
01022     /* Register libraries. */
01023     luaL_register(AI->L, AI_METATABLE, AIL_methods);
01024 
01025     /* Load the AI */
01026     Com_sprintf(path, sizeof(path), "ai/%s.lua", type);
01027     size = gi.FS_LoadFile(path, (byte **) &fbuf);
01028     if (size == 0) {
01029         gi.DPrintf("Unable to load Lua file '%s'.\n", path);
01030         return -1;
01031     }
01032     if (luaL_dobuffer(AI->L, fbuf, size, path)) {
01033         gi.DPrintf("Unable to parse Lua file '%s'\n", path);
01034         gi.FS_FreeFile(fbuf);
01035         return -1;
01036     }
01037     gi.FS_FreeFile(fbuf);
01038 
01039     return 0;
01040 }
01041 
01046 static void AIL_CleanupActor (edict_t * ent)
01047 {
01048     AI_t *AI = &ent->AI;
01049 
01050     /* Cleanup. */
01051     if (AI->L != NULL) {
01052         lua_close(AI->L);
01053         AI->L = NULL;
01054     }
01055 }
01056 
01057 void AIL_Init (void)
01058 {
01059     gi.RegisterConstInt("luaaiteam::phalanx", TEAM_PHALANX);
01060     gi.RegisterConstInt("luaaiteam::civilian", TEAM_CIVILIAN);
01061     gi.RegisterConstInt("luaaiteam::alien", TEAM_ALIEN);
01062     gi.RegisterConstInt("luaaiteam::all", TEAM_ALL);
01063 }
01064 
01065 void AIL_Shutdown (void)
01066 {
01067     gi.UnregisterConstVariable("luaaiteam::phalanx");
01068     gi.UnregisterConstVariable("luaaiteam::civilian");
01069     gi.UnregisterConstVariable("luaaiteam::alien");
01070     gi.UnregisterConstVariable("luaaiteam::all");
01071 }
01072 
01076 void AIL_Cleanup (void)
01077 {
01078     edict_t *ent = NULL;
01079 
01080     while ((ent = G_EdictsGetNextActor(ent)))
01081         AIL_CleanupActor(ent);
01082 }

Generated by  doxygen 1.6.2