814 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			814 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <math.h>
 | |
| 
 | |
| #include "lua.h"
 | |
| #include "lauxlib.h"
 | |
| 
 | |
| #include "llua.h"
 | |
| #include "lluadef.h"
 | |
| #include "hook.h"
 | |
| #include "mission.h"
 | |
| #include "log.h"
 | |
| #include "lephisto.h"
 | |
| #include "rng.h"
 | |
| #include "space.h"
 | |
| #include "toolkit.h"
 | |
| #include "land.h"
 | |
| #include "pilot.h"
 | |
| #include "player.h"
 | |
| #include "ltime.h"
 | |
| #include "xml.h"
 | |
| #include "misn_lua.h"
 | |
| 
 | |
| /* Similar to lua vars, but with less variety. */
 | |
| #define MISN_VAR_NIL    0
 | |
| #define MISN_VAR_NUM    1
 | |
| #define MISN_VAR_BOOL   2
 | |
| #define MISN_VAR_STR    3
 | |
| typedef struct misn_var_ {
 | |
|   char* name;
 | |
|   char type;
 | |
|   union {
 | |
|     double num;
 | |
|     char* str;
 | |
|     int b;
 | |
|   } d;
 | |
| } misn_var;
 | |
| 
 | |
| /* Variable stack. */
 | |
| static misn_var* var_stack = NULL;
 | |
| static int var_nstack = 0;
 | |
| static int var_mstack = 0;
 | |
| 
 | |
| /* Current mission. */
 | |
| static Mission* cur_mission = NULL;
 | |
| static int misn_delete = 0; /* If 1 delete current mission. */
 | |
| 
 | |
| /* Static. */
 | |
| static int var_add(misn_var* var);
 | |
| static void var_free(misn_var* var);
 | |
| static unsigned int  hook_generic(lua_State* L, char* stack);
 | |
| /* Extern. */
 | |
| int misn_run(Mission* misn, char* func);
 | |
| int var_save(xmlTextWriterPtr writer);
 | |
| int var_load(xmlNodePtr parent);
 | |
| /* External. */
 | |
| extern void mission_sysMark(void);
 | |
| 
 | |
| /* -- Libraries. -- */
 | |
| 
 | |
| /* Mission. */
 | |
| static int misn_setTitle(lua_State* L);
 | |
| static int misn_setDesc(lua_State* L);
 | |
| static int misn_setReward(lua_State* L);
 | |
| static int misn_setMarker(lua_State* L);
 | |
| static int misn_factions(lua_State* L);
 | |
| static int misn_accept(lua_State* L);
 | |
| static int misn_finish(lua_State* L);
 | |
| static const luaL_reg misn_methods[] = {
 | |
|   { "setTitle",     misn_setTitle   },
 | |
|   { "setDesc",      misn_setDesc    },
 | |
|   { "setReward",    misn_setReward  },
 | |
|   { "setMarker",    misn_setMarker  },
 | |
|   { "factions",     misn_factions   },
 | |
|   { "accept",       misn_accept     },
 | |
|   { "finish",       misn_finish     },
 | |
|   { 0, 0 }
 | |
| };
 | |
| 
 | |
| /* Var. */
 | |
| static int var_peek(lua_State* L);
 | |
| static int var_pop(lua_State* L);
 | |
| static int var_push(lua_State* L);
 | |
| static const luaL_reg var_methods[] = {
 | |
|   { "peek", var_peek },
 | |
|   { "pop",  var_pop},
 | |
|   { "push", var_push},
 | |
|   {0, 0}
 | |
| };
 | |
| 
 | |
| /* Only conditional. */
 | |
| static const luaL_reg var_cond_methods[] = {
 | |
|   { "peek", var_peek },
 | |
|   {0, 0 }
 | |
| };
 | |
| 
 | |
| /* Player. */
 | |
| static int player_getname(lua_State* L);
 | |
| static int player_shipname(lua_State* L);
 | |
| static int player_freeSpace(lua_State* L);
 | |
| static int player_addCargo(lua_State* L);
 | |
| static int player_rmCargo(lua_State* L);
 | |
| static int player_pay(lua_State* L);
 | |
| static int player_msg(lua_State* L);
 | |
| static int player_modFaction(lua_State* L);
 | |
| static int player_getFaction(lua_State* L);
 | |
| static const luaL_reg player_methods[] = {
 | |
|   { "name",         player_getname    },
 | |
|   { "ship",         player_shipname   },
 | |
|   { "freeCargo",    player_freeSpace  },
 | |
|   { "addCargo",     player_addCargo   },
 | |
|   { "rmCargo",      player_rmCargo    },
 | |
|   { "pay",          player_pay        },
 | |
|   { "msg",          player_msg        },
 | |
|   { "modFaction",   player_modFaction },
 | |
|   { "getFaction",   player_getFaction },
 | |
|   { 0, 0 }
 | |
| };
 | |
| 
 | |
| /* Hooks. */
 | |
| static int hook_land(lua_State* L);
 | |
| static int hook_takeoff(lua_State* L);
 | |
| static int hook_time(lua_State* L);
 | |
| static int hook_enter(lua_State* L);
 | |
| static int hook_pilotDeath(lua_State* L);
 | |
| static const luaL_reg hook_methods[] = {
 | |
|   { "land",       hook_land       },
 | |
|   { "takeoff",    hook_takeoff    },
 | |
|   { "time",       hook_time       },
 | |
|   { "enter",      hook_enter      },
 | |
|   { "pilotDeath", hook_pilotDeath },
 | |
|   { 0, 0 }
 | |
| };
 | |
| 
 | |
| /* Pilots. */
 | |
| static int pilot_addFleet(lua_State* L);
 | |
| static int pilot_rename(lua_State* L);
 | |
| static const luaL_reg pilot_methods[] = {
 | |
|   { "add",  pilot_addFleet },
 | |
|   { "rename", pilot_rename },
 | |
|   { 0, 0 }
 | |
| };
 | |
| 
 | |
| /* Register all the libaries. */
 | |
| int misn_loadLibs(lua_State* L) {
 | |
|   lua_loadLephisto(L);
 | |
|   lua_loadMisn(L);
 | |
|   lua_loadVar(L, 0);
 | |
|   lua_loadSpace(L, 0);
 | |
|   lua_loadTime(L, 0);
 | |
|   lua_loadPlayer(L);
 | |
|   lua_loadRnd(L);
 | |
|   lua_loadTk(L);
 | |
|   lua_loadHook(L);
 | |
|   lua_loadPilot(L);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int misn_loadCondLibs(lua_State* L) {
 | |
|   lua_loadTime(L, 1);
 | |
|   lua_loadVar(L, 1);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Individual libarary loading. */
 | |
| int lua_loadMisn(lua_State* L) {
 | |
|   luaL_register(L, "misn",      misn_methods);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int lua_loadVar(lua_State* L, int readonly) {
 | |
|   if(readonly == 0)
 | |
|     luaL_register(L, "var", var_methods);
 | |
|   else
 | |
|     luaL_register(L, "var", var_cond_methods);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int lua_loadPlayer(lua_State* L) {
 | |
|   luaL_register(L, "player",    player_methods);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int lua_loadHook(lua_State* L) {
 | |
|   luaL_register(L, "hook",      hook_methods);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| int lua_loadPilot(lua_State* L) {
 | |
|   luaL_register(L, "pilot", pilot_methods);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Run a mission function. */
 | |
| /* */
 | |
| /* -1 on error, 1 on misn.finish() call and 0 normally. */
 | |
| int misn_run(Mission* misn, char* func) {
 | |
|   int i, ret;
 | |
|   char* err;
 | |
| 
 | |
|   cur_mission = misn;
 | |
|   misn_delete = 0;
 | |
| 
 | |
|   lua_getglobal(misn->L, func);
 | |
|   if((ret = lua_pcall(misn->L, 0, 0, 0))) {
 | |
|     /* Did an oops. */
 | |
|     err = (lua_isstring(misn->L, -1)) ? (char*) lua_tostring(misn->L, -1) : NULL;
 | |
|     if(strcmp(err, "Mission Done"))
 | |
|       WARN("Mission '%s' -> '%s' : %s",
 | |
|           cur_mission->data->name, func, (err) ? err : "Unknown Error");
 | |
|     else ret = 1;
 | |
|   }
 | |
| 
 | |
|   /* Mission is finished. */
 | |
|   if(misn_delete) {
 | |
|     mission_cleanup(cur_mission);
 | |
|     for(i = 0; i < MISSION_MAX; i++)
 | |
|       if(cur_mission == &player_missions[i]) {
 | |
|         memmove(&player_missions[i], &player_missions[i+1],
 | |
|             sizeof(Mission) * (MISSION_MAX-i-1));
 | |
|         break;
 | |
|       }
 | |
|   }
 | |
|   cur_mission = NULL;
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /* Save the mission variables. */
 | |
| int var_save(xmlTextWriterPtr writer) {
 | |
|   int i;
 | |
| 
 | |
|   xmlw_startElem(writer, "vars");
 | |
| 
 | |
|   for(i = 0; i < var_nstack; i++) {
 | |
|     xmlw_startElem(writer, "vars");
 | |
| 
 | |
|     xmlw_attr(writer, "name", var_stack[i].name);
 | |
| 
 | |
|     switch(var_stack[i].type) {
 | |
|       case MISN_VAR_NIL:
 | |
|         xmlw_attr(writer, "type", "nil");
 | |
|         break;
 | |
|       case MISN_VAR_NUM:
 | |
|         xmlw_attr(writer, "type", "num");
 | |
|         xmlw_str(writer, "%d", var_stack[i].d.num);
 | |
|         break;
 | |
|       case MISN_VAR_BOOL:
 | |
|         xmlw_attr(writer, "type", "bool");
 | |
|         xmlw_str(writer, "%d", var_stack[i].d.b);
 | |
|         break;
 | |
|       case MISN_VAR_STR:
 | |
|         xmlw_attr(writer, "type", "str");
 | |
|         xmlw_str(writer, var_stack[i].d.str);
 | |
|         break;
 | |
|     }
 | |
|     xmlw_endElem(writer); /* var. */
 | |
|   }
 | |
|   xmlw_endElem(writer); /* vars. */
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Load the vars. */
 | |
| int var_load(xmlNodePtr parent) {
 | |
|   char* str;
 | |
|   xmlNodePtr node, cur;
 | |
|   misn_var var;
 | |
| 
 | |
|   var_cleanup();
 | |
| 
 | |
|   node = parent->xmlChildrenNode;
 | |
| 
 | |
|   do {
 | |
|     if(xml_isNode(node, "vars")) {
 | |
|       cur = node->xmlChildrenNode;
 | |
|       
 | |
|       do {
 | |
|         if(xml_isNode(cur, "var")) {
 | |
|           xmlr_attr(cur, "name", var.name);
 | |
|           xmlr_attr(cur, "type", str);
 | |
|           if(strcmp(str, "nil")==0)
 | |
|             var.type = MISN_VAR_NIL;
 | |
|           else if(strcmp(str, "num")==0) {
 | |
|             var.type = MISN_VAR_NUM;
 | |
|             var.d.num = atoi(xml_get(cur));
 | |
|           }
 | |
|           else if(strcmp(str, "bool")) {
 | |
|             var.type = MISN_VAR_BOOL;
 | |
|             var.d.b = atoi(xml_get(cur));
 | |
|           }
 | |
|           else if(strcmp(str, "str")) {
 | |
|             var.type = MISN_VAR_STR;
 | |
|             var.d.str = atoi(xml_get(cur));
 | |
|           } else {
 | |
|             /* Supeh error checking. */
 | |
|             WARN("Unknown var type '%s'", str);
 | |
|             free(var.name);
 | |
|             continue;
 | |
|           }
 | |
|           free(str);
 | |
|           var_add(&var);
 | |
|         }
 | |
|       } while(xml_nextNode(cur));
 | |
|     }
 | |
|   } while(xml_nextNode(node));
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* Add a var to the stack, strings will be SHARED, don't free!!! */
 | |
| static int var_add(misn_var* new_var) {
 | |
|   int i;
 | |
| 
 | |
|   if(var_nstack+1 > var_mstack) {
 | |
|     /* More memory. */
 | |
|     var_mstack += 64; /* Overkill much?? */
 | |
|     var_stack = realloc(var_stack, var_mstack * sizeof(misn_var));
 | |
|   }
 | |
| 
 | |
|   /* Check if already exists. */
 | |
|   for(i = 0; i < var_nstack; i++)
 | |
|     if(strcmp(new_var->name, var_stack[i].name)==0) {
 | |
|       var_free(&var_stack[i]);
 | |
|       memcpy(&var_stack[i], new_var, sizeof(misn_var));
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|   memcpy(&var_stack[var_nstack], new_var, sizeof(misn_var));
 | |
|   var_nstack++;
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* -- Mission. -- */
 | |
| 
 | |
| static int misn_setTitle(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   if(lua_isstring(L, 1)) {
 | |
|     if(cur_mission->title)
 | |
|       /* Cleanup the old title. */
 | |
|       free(cur_mission->title);
 | |
|     cur_mission->title = strdup((char*)lua_tostring(L, 1));
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int misn_setDesc(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   if(lua_isstring(L, 1)) {
 | |
|     if(cur_mission->desc)
 | |
|       /* Cleanup the old description. */
 | |
|       free(cur_mission->desc);
 | |
|     cur_mission->desc = strdup((char*)lua_tostring(L, 1));
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int misn_setReward(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   if(lua_isstring(L, 1)) {
 | |
|     if(cur_mission->reward != NULL) /* Cleanup old reward. */
 | |
|       /* Cleanup the old reward. */
 | |
|       free(cur_mission->reward);
 | |
|     cur_mission->reward = strdup((char*)lua_tostring(L, 1));
 | |
|   }
 | |
|   else LLUA_INVALID_PARAMETER();
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int misn_setMarker(lua_State* L) {
 | |
|   if(lua_isstring(L, 1)) {
 | |
|     if(cur_mission->sys_marker != NULL) /* Cleanup old markers. */
 | |
|       free(cur_mission->sys_marker);
 | |
|     cur_mission->sys_marker = strdup((char*)lua_tostring(L, 1));
 | |
| #ifdef DEBUG
 | |
|     if(system_get(cur_mission->sys_marker)==NULL)
 | |
|       LLUA_DEBUG("Marking unexistant system '%s'", cur_mission->sys_marker);
 | |
| #endif
 | |
|     mission_sysMark();
 | |
|   }
 | |
|   else if(cur_mission->sys_marker != NULL) /* No parameter nullifies. */
 | |
|     free(cur_mission->sys_marker);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int misn_factions(lua_State* L) {
 | |
|   int i;
 | |
|   MissionData* dat;
 | |
| 
 | |
|   dat = cur_mission->data;
 | |
| 
 | |
|   /* We'll push all the factions in table form. */
 | |
|   lua_newtable(L);
 | |
|   for(i = 0; i < dat->avail.nfactions; i++) {
 | |
|     lua_pushnumber(L, i+1);   /* Index, starts with 1. */
 | |
|     lua_pushnumber(L, dat->avail.factions[i]); /* Value. */
 | |
|     lua_rawset(L, -3);  /* Store the value in the table. */
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int misn_accept(lua_State* L) {
 | |
|   int i, ret;
 | |
| 
 | |
|   ret = 0;
 | |
| 
 | |
|   /* Find the last mission. */
 | |
|   for(i = 0; i < MISSION_MAX; i++)
 | |
|     if(player_missions[i].data == NULL) break;
 | |
| 
 | |
|   /* No missions left. */
 | |
|   if(i >= MISSION_MAX) ret = 1;
 | |
|   else {
 | |
|     memcpy(&player_missions[i], cur_mission, sizeof(Mission));
 | |
|     memset(cur_mission, 0, sizeof(Mission));
 | |
|     cur_mission = &player_missions[i];
 | |
|   }
 | |
|   lua_pushboolean(L, !ret); /* We'll convert C style return to lua. */
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int misn_finish(lua_State* L) {
 | |
|   int b;
 | |
| 
 | |
|   if(lua_isboolean(L, -1)) b = lua_toboolean(L, -1);
 | |
|   else {
 | |
|     lua_pushstring(L, "Mission Done");
 | |
|     lua_error(L); /* THERE IS NO RETURN! */
 | |
|     return 0;
 | |
|   }
 | |
|   
 | |
|   misn_delete = 1;
 | |
| 
 | |
|   if(b && mis_isFlag(cur_mission->data, MISSION_UNIQUE))
 | |
|     player_missionFinished(mission_getID(cur_mission->data->name));
 | |
| 
 | |
|   lua_pushstring(L, "Mission Done");
 | |
|   lua_error(L); /* Should not return.. */
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* -- Var. -- */
 | |
| 
 | |
| /* Check if a variable exists. */
 | |
| int var_checkflag(char* str) {
 | |
|   int i;
 | |
|   for(i = 0; i < var_nstack; i++)
 | |
|     if(strcmp(var_stack[i].name, str)==0)
 | |
|       return 1;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int var_peek(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   int i;
 | |
|   char* str;
 | |
| 
 | |
|   if(lua_isstring(L, -1)) str = (char*) lua_tostring(L, -1);
 | |
|   else {
 | |
|     LLUA_DEBUG("Trying to peek a var with non-string name");
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   for(i = 0; i < var_nstack; i++)
 | |
|     if(strcmp(str, var_stack[i].name)==0) {
 | |
|       switch(var_stack[i].type) {
 | |
|         case MISN_VAR_NIL:
 | |
|           lua_pushnil(L);
 | |
|           break;
 | |
|         case MISN_VAR_NUM:
 | |
|           lua_pushnumber(L, var_stack[i].d.num);
 | |
|           break;
 | |
|         case MISN_VAR_BOOL:
 | |
|           lua_pushboolean(L, var_stack[i].d.b);
 | |
|           break;
 | |
|         case MISN_VAR_STR:
 | |
|           lua_pushstring(L, var_stack[i].d.str);
 | |
|           break;
 | |
|       }
 | |
|       return 1;
 | |
|     }
 | |
|   lua_pushnil(L);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int var_pop(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   int i;
 | |
|   char* str;
 | |
| 
 | |
|   if(lua_isstring(L, -1)) str = (char*) lua_tostring(L, -1);
 | |
|   else {
 | |
|     LLUA_DEBUG("Trying to pop a var with non-string name");
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   for(i = 0; i < var_nstack; i++)
 | |
|     if(strcmp(str, var_stack[i].name)==0) {
 | |
|       var_free(&var_stack[i]);
 | |
|       memmove(&var_stack[i], &var_stack[i+1], sizeof(misn_var)*(var_nstack-i-1));
 | |
|       var_stack--;
 | |
|       return 0;
 | |
|     }
 | |
|   LLUA_DEBUG("Var '%s' not found in stack", str);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int var_push(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(2);
 | |
|   char* str;
 | |
|   misn_var var;
 | |
| 
 | |
|   if(lua_isstring(L, -2)) str = (char*) lua_tostring(L, -2);
 | |
|   else {
 | |
|     LLUA_DEBUG("Trying to push a var with non-string name");
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   var.name = strdup(str);
 | |
| 
 | |
|   /* Store appropriate data. */
 | |
|   if(lua_isnil(L, -1))
 | |
|     var.type = MISN_VAR_NIL;
 | |
|   else if(lua_isnumber(L, -1)) {
 | |
|     var.type = MISN_VAR_NUM;
 | |
|     var.d.num = (double)lua_tonumber(L, -1);
 | |
|   }
 | |
|   else if(lua_isboolean(L, -1)) {
 | |
|     var.type = MISN_VAR_BOOL;
 | |
|     var.d.b = lua_toboolean(L, -1);
 | |
|   }
 | |
|   else if(lua_isstring(L, -1)) {
 | |
|     var.type = MISN_VAR_STR;
 | |
|     var.d.str = strdup((char*)lua_tostring(L, -1));
 | |
|   } else {
 | |
|     LLUA_DEBUG("Trying to push a var of invalid data type to stack");
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   var_add(&var);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static void var_free(misn_var* var) {
 | |
|   switch(var->type) {
 | |
|     case MISN_VAR_STR:
 | |
|       if(var->d.str != NULL) {
 | |
|         free(var->d.str);
 | |
|         var->d.str = NULL;
 | |
|       }
 | |
|       break;
 | |
|     case MISN_VAR_NIL:
 | |
|     case MISN_VAR_NUM:
 | |
|     case MISN_VAR_BOOL:
 | |
|       break;
 | |
|   }
 | |
|   if(var->name != NULL) {
 | |
|     free(var->name);
 | |
|     var->name = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void var_cleanup(void) {
 | |
|   int i;
 | |
|   for(i = 0; i < var_nstack; i++)
 | |
|     var_free(&var_stack[i]);
 | |
| 
 | |
|   if(var_stack != NULL) free(var_stack);
 | |
|   var_stack = NULL;
 | |
|   var_nstack = 0;
 | |
|   var_mstack = 0;
 | |
| }
 | |
| 
 | |
| /* -- Player. -- */
 | |
| 
 | |
| static int player_getname(lua_State* L) {
 | |
|   lua_pushstring(L, player_name);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int player_shipname(lua_State* L) {
 | |
|   lua_pushstring(L, player->name);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int player_freeSpace(lua_State* L) {
 | |
|   lua_pushnumber(L, pilot_cargoFree(player));
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int player_addCargo(lua_State* L) {
 | |
|   Commodity* cargo;
 | |
|   int quantity, ret;
 | |
| 
 | |
|   LLUA_MIN_ARGS(2);
 | |
| 
 | |
|   if(lua_isstring(L, -2)) cargo = commodity_get((char*) lua_tostring(L, -2));
 | |
|   else return 0;
 | |
|   if(lua_isnumber(L, -1)) quantity = (int)lua_tonumber(L, -1);
 | |
|   else return 0;
 | |
| 
 | |
|   ret = pilot_addMissionCargo(player, cargo, quantity);
 | |
|   mission_linkCargo(cur_mission, ret);
 | |
| 
 | |
|   lua_pushnumber(L, ret);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int player_rmCargo(lua_State* L) {
 | |
|   int ret;
 | |
|   unsigned int id;
 | |
|   
 | |
|   LLUA_MIN_ARGS(1);
 | |
| 
 | |
|   if(lua_isnumber(L, -1)) id = (unsigned int) lua_tonumber(L, -1);
 | |
|   else return 0;
 | |
| 
 | |
|   ret = pilot_rmMissionCargo(player, id);
 | |
|   mission_unlinkCargo(cur_mission, id);
 | |
| 
 | |
|   lua_pushboolean(L, !ret);
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int player_pay(lua_State* L) {
 | |
|   int money;
 | |
| 
 | |
|   LLUA_MIN_ARGS(1);
 | |
| 
 | |
|   if(lua_isnumber(L, -1)) money = (int) lua_tonumber(L, -1);
 | |
|   else return 0;
 | |
| 
 | |
|   player->credits += money;
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int player_msg(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   char* str;
 | |
| 
 | |
|   if(lua_isstring(L, -1)) str = (char*) lua_tostring(L, -1);
 | |
|   else return 0;
 | |
| 
 | |
|   player_message(str);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int player_modFaction(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(2);
 | |
|   int f, mod;
 | |
| 
 | |
|   if(lua_isstring(L, -2)) f = faction_get(lua_tostring(L, -2));
 | |
|   else LLUA_INVALID_PARAMETER();
 | |
| 
 | |
|   if(lua_isnumber(L, -1)) mod = (int)lua_tonumber(L, -1);
 | |
|   else LLUA_INVALID_PARAMETER();
 | |
| 
 | |
|   faction_modPlayer(f, mod);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int player_getFaction(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   int f;
 | |
| 
 | |
|   if(lua_isstring(L, -1)) f = faction_get(lua_tostring(L, -1));
 | |
|   else LLUA_INVALID_PARAMETER();
 | |
|   lua_pushnumber(L, faction_getPlayer(f));
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| /* -- HOOK -- */
 | |
| static unsigned int hook_generic(lua_State* L, char* stack) {
 | |
|   int i;
 | |
|   char* func;
 | |
|   
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   
 | |
|   /* Make sure mission is a player mission. */
 | |
|   for(i = 0; i < MISSION_MAX; i++)
 | |
|     if(player_missions[i].id == cur_mission->id)
 | |
|       break;
 | |
|   if(i >= MISSION_MAX) {
 | |
|     WARN("Mission not in stack trying to hook");
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if(lua_isstring(L, -1)) func = (char*)lua_tostring(L, -1);
 | |
|   else {
 | |
|     WARN("Mission '%s': trying to push non-valid function hook",
 | |
|         cur_mission->data->name);
 | |
|     return 0;
 | |
|   }
 | |
|   return hook_add(cur_mission->id, func, stack);
 | |
| }
 | |
| 
 | |
| static int hook_land(lua_State* L) {
 | |
|   hook_generic(L, "land");
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int hook_takeoff(lua_State* L) {
 | |
|   hook_generic(L, "takeoff");
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int hook_time(lua_State* L) {
 | |
|   hook_generic(L, "time");
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int hook_enter(lua_State* L) {
 | |
|   hook_generic(L, "enter");
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static int hook_pilotDeath(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(2);
 | |
|   unsigned int h, p;
 | |
| 
 | |
|   if(lua_isnumber(L, -2)) p = (unsigned int) lua_tonumber(L, -2);
 | |
|   else LLUA_INVALID_PARAMETER();
 | |
| 
 | |
|   h = hook_generic(L, "death"); /* We won't actually call the death stack directly. */
 | |
|   pilot_addHook(pilot_get(p), PILOT_HOOK_DEATH, h);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /* -- Pilot. -- */
 | |
| static int pilot_addFleet(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(1);
 | |
|   Fleet* flt;
 | |
|   char* fltname, *fltai;;
 | |
|   int i, j;
 | |
|   unsigned int p;
 | |
|   double a;
 | |
|   Vec2 vv, vp, vn;
 | |
| 
 | |
|   /* Parse first argument - Fleet name. */
 | |
|   if(lua_isstring(L, 1)) fltname = (char*) lua_tostring(L, 1);
 | |
|   else LLUA_INVALID_PARAMETER();
 | |
| 
 | |
|   /* Parse second arguement - Fleet AI override. */
 | |
|   if(lua_isstring(L, 2)) fltai = (char*) lua_tostring(L, 2);
 | |
|   else fltai = NULL;
 | |
| 
 | |
|   /* Pull the fleet. */
 | |
|   flt = fleet_get(fltname);
 | |
|   if(flt == NULL) {
 | |
|     LLUA_DEBUG("Fleet not found!");
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   /* This should probably be done better.. */
 | |
|   vect_pset(&vp, RNG(MIN_HYPERSPACE_DIST, MIN_HYPERSPACE_DIST*1.5),
 | |
|       RNG(0, 360)*M_PI/180.);
 | |
|   vectnull(&vn);
 | |
| 
 | |
|   /* Now we start adding pilots and toss ids into the table we return. */
 | |
|   j = 0;
 | |
|   for(i = 0; i < flt->npilots; i++) {
 | |
|     if(RNG(0, 100) <= flt->pilots[i].chance) {
 | |
|       /* Fleet displacement. */
 | |
|       vect_cadd(&vp, RNG(75, 150) & (RNG(0, 1) ? 1: -1),
 | |
|           RNG(75, 150) * (RNG(0, 1) ? 1 : -1));
 | |
| 
 | |
|       a = vect_angle(&vp, &vn);
 | |
|       vectnull(&vv);
 | |
|       p = pilot_create(flt->pilots[i].ship,
 | |
|           flt->pilots[i].name,
 | |
|           flt->faction,
 | |
|           (fltai != NULL) ? /* AI override */
 | |
|             ai_getProfile(fltai) :
 | |
|             flt->ai,
 | |
|           a,
 | |
|           &vp,
 | |
|           &vv,
 | |
|           0);
 | |
| 
 | |
|       /* We push each pilot created into a table and return it. */
 | |
|       lua_pushnumber(L, ++j); /* Index start with 1. */
 | |
|       lua_pushnumber(L, p);   /* value = pilot id. */
 | |
|       lua_rawset(L, -3);      /* Store the value in the table. */
 | |
|     }
 | |
|   }
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int pilot_rename(lua_State* L) {
 | |
|   LLUA_MIN_ARGS(2);
 | |
|   char* name;
 | |
|   unsigned int id;
 | |
|   Pilot* p;
 | |
| 
 | |
|   if(lua_isnumber(L, -2)) id = (unsigned int) lua_tonumber(L, -2);
 | |
|   else LLUA_INVALID_PARAMETER();
 | |
|   if(lua_isstring(L, -1)) name = (char*) lua_tostring(L, -1);
 | |
|   else LLUA_INVALID_PARAMETER();
 | |
| 
 | |
|   p = pilot_get(id);
 | |
|   free(p->name);
 | |
|   p->name = strdup(name);
 | |
|   return 0;
 | |
| }
 | |
| 
 | 
