mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 22:56:30 -10:00
1666 lines
49 KiB
C++
1666 lines
49 KiB
C++
|
|
#include "ai/ai.h"
|
|
#include "ai/aigoals.h"
|
|
#include "asteroid/asteroid.h"
|
|
#include "camera/camera.h"
|
|
#include "cfile/cfilesystem.h"
|
|
#include "cmdline/cmdline.h"
|
|
#include "cutscene/movie.h"
|
|
#include "debris/debris.h"
|
|
#include "freespace.h"
|
|
#include "gamesequence/gamesequence.h"
|
|
#include "globalincs/linklist.h"
|
|
#include "graphics/2d.h"
|
|
#include "graphics/font.h"
|
|
#include "graphics/generic.h"
|
|
#include "graphics/opengl/gropenglpostprocessing.h"
|
|
#include "headtracking/headtracking.h"
|
|
#include "hud/hudbrackets.h"
|
|
#include "hud/hudconfig.h"
|
|
#include "hud/hudescort.h"
|
|
#include "hud/hudets.h"
|
|
#include "hud/hudgauges.h"
|
|
#include "hud/hudshield.h"
|
|
#include "iff_defs/iff_defs.h"
|
|
#include "io/joy.h"
|
|
#include "io/key.h"
|
|
#include "io/mouse.h"
|
|
#include "io/timer.h"
|
|
#include "jumpnode/jumpnode.h"
|
|
#include "lighting/lighting.h"
|
|
#include "menuui/credits.h"
|
|
#include "mission/missioncampaign.h"
|
|
#include "mission/missiongoals.h"
|
|
#include "mission/missionload.h"
|
|
#include "mission/missionlog.h"
|
|
#include "mission/missionmessage.h"
|
|
#include "mission/missiontraining.h"
|
|
#include "missionui/missionbrief.h"
|
|
#include "model/model.h"
|
|
#include "network/multi.h"
|
|
#include "network/multimsgs.h"
|
|
#include "object/objectshield.h"
|
|
#include "object/waypoint.h"
|
|
#include "parse/parselo.h"
|
|
#include "scripting/scripting.h"
|
|
#include "particle/particle.h"
|
|
#include "playerman/player.h"
|
|
#include "render/3d.h"
|
|
#include "render/3dinternal.h"
|
|
#include "scripting/ade_api.h"
|
|
#include "ship/ship.h"
|
|
#include "ship/shipfx.h"
|
|
#include "ship/shiphit.h"
|
|
#include "sound/audiostr.h"
|
|
#include "sound/ds.h"
|
|
#include "weapon/beam.h"
|
|
#include "weapon/weapon.h"
|
|
|
|
#define BMPMAN_INTERNAL
|
|
#include "bmpman/bm_internal.h"
|
|
|
|
#include "scripting/api/bitops.h"
|
|
#include "scripting/api/enums.h"
|
|
#include "scripting/api/vecmath.h"
|
|
#include "scripting/api/event.h"
|
|
#include "scripting/api/file.h"
|
|
#include "scripting/api/font.h"
|
|
#include "scripting/api/gameevent.h"
|
|
#include "scripting/api/gamestate.h"
|
|
#include "scripting/api/hudgauge.h"
|
|
#include "scripting/api/eye.h"
|
|
#include "scripting/api/model.h"
|
|
#include "scripting/api/physics_info.h"
|
|
#include "scripting/api/sexpvar.h"
|
|
#include "scripting/api/shields.h"
|
|
#include "scripting/api/shiptype.h"
|
|
#include "scripting/api/species.h"
|
|
#include "scripting/api/team.h"
|
|
#include "scripting/api/streaminganim.h"
|
|
#include "scripting/api/texture.h"
|
|
#include "scripting/api/texturemap.h"
|
|
#include "scripting/api/weaponclass.h"
|
|
#include "scripting/api/mc_info.h"
|
|
#include "scripting/api/object.h"
|
|
#include "scripting/api/asteroid.h"
|
|
#include "scripting/api/cockpit_display.h"
|
|
#include "scripting/api/shipclass.h"
|
|
#include "scripting/api/debris.h"
|
|
#include "scripting/api/waypoint.h"
|
|
#include "scripting/api/ship_bank.h"
|
|
#include "scripting/api/subsystem.h"
|
|
#include "scripting/api/order.h"
|
|
#include "scripting/api/ship.h"
|
|
#include "scripting/api/sound.h"
|
|
#include "scripting/api/message.h"
|
|
#include "scripting/api/wing.h"
|
|
#include "scripting/api/beam.h"
|
|
#include "scripting/api/player.h"
|
|
#include "scripting/api/camera.h"
|
|
#include "scripting/api/control_info.h"
|
|
#include "scripting/api/particle.h"
|
|
#include "scripting/api/audio.h"
|
|
#include "scripting/api/base.h"
|
|
#include "scripting/api/cfile.h"
|
|
#include "scripting/api/weapon.h"
|
|
#include "scripting/api/controls.h"
|
|
#include "scripting/api/graphics.h"
|
|
#include "scripting/api/hud.h"
|
|
#include "scripting/api/hookvars.h"
|
|
|
|
using namespace scripting;
|
|
using namespace scripting::api;
|
|
|
|
//**********Handles
|
|
/*ade_obj<int> l_Camera("camera", "Camera handle");
|
|
ade_obj<int> l_Cmission("cmission", "Campaign mission handle"); //WMC - We can get away with a pointer right now, but if it ever goes dynamic, it'd be a prob
|
|
ade_obj<enum_h> l_Enum("enumeration", "Enumeration object");
|
|
ade_obj<int> l_Event("event", "Mission event handle");
|
|
ade_obj<int> l_Font("font", "font handle");
|
|
ade_obj<matrix_h> l_Matrix("orientation", "Orientation matrix object");
|
|
ade_obj<int> l_Model("model", "3D Model (POF) handle");
|
|
ade_obj<object_h> l_Object("object", "Object handle");
|
|
ade_obj<physics_info_h> l_Physics("physics", "Physics handle");
|
|
ade_obj<int> l_Player("player", "Player handle");
|
|
ade_obj<object_h> l_Shields("shields", "Shields handle");
|
|
ade_obj<object_h> l_Ship("ship", "Ship handle", &l_Object);
|
|
ade_obj<int> l_Shipclass("shipclass", "Ship class handle");
|
|
ade_obj<object_h> l_ShipTextures("shiptextures", "Ship textures handle");
|
|
ade_obj<int> l_Shiptype("shiptype", "Ship type handle");
|
|
ade_obj<int> l_Species("species", "Species handle");
|
|
ade_obj<ship_subsys_h> l_Subsystem("subsystem", "Ship subsystem handle");
|
|
ade_obj<int> l_Team("team", "Team handle");
|
|
ade_obj<int> l_Texture("texture", "Texture handle");
|
|
ade_obj<int> l_Wing("wing", "Wing handle");
|
|
ade_obj<vec3d> l_Vector("vector", "Vector object");
|
|
ade_obj<object_h> l_Weapon("weapon", "Weapon handle", &l_Object);
|
|
ade_obj<ship_bank_h> l_WeaponBank("weaponbank", "Ship/subystem weapons bank handle");
|
|
ade_obj<ship_banktype_h> l_WeaponBankType("weaponbanktype", "Ship/subsystem weapons bank type handle");
|
|
ade_obj<int> l_Weaponclass("weaponclass", "Weapon class handle");
|
|
*/
|
|
//###########################################################
|
|
//########################<IMPORTANT>########################
|
|
//###########################################################
|
|
//If you are a coder who wants to add libraries, functions,
|
|
//or objects to Lua, then you want to be below this point.
|
|
//###########################################################
|
|
//########################</IMPORTANT>#######################
|
|
//###########################################################
|
|
|
|
//**********LIBRARY: Mission
|
|
ade_lib l_Mission("Mission", NULL, "mn", "Mission library");
|
|
|
|
// for use in creating faster metadata systems, use in conjunction with getSignature()
|
|
ADE_FUNC(getObjectFromSignature, l_Mission, "number Signature", "Gets a handle of an object from its signature", "object", "Handle of object with signaure, invalid handle if signature is not in use")
|
|
{
|
|
int sig = -1;
|
|
int objnum;
|
|
if(!ade_get_args(L, "i", &sig))
|
|
return ade_set_error(L, "o", l_Object.Set(object_h()));
|
|
|
|
if (sig == -1) {
|
|
return ade_set_error(L, "o", l_Object.Set(object_h()));
|
|
}
|
|
|
|
objnum = obj_get_by_signature(sig);
|
|
|
|
return ade_set_object_with_breed(L, objnum);
|
|
}
|
|
|
|
ADE_FUNC(evaluateSEXP, l_Mission, "string", "Runs the defined SEXP script", "boolean", "if the operation was successful")
|
|
{
|
|
char *s;
|
|
int r_val;
|
|
|
|
if(!ade_get_args(L, "s", &s))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
r_val = run_sexp(s);
|
|
|
|
if (r_val == SEXP_TRUE)
|
|
return ADE_RETURN_TRUE;
|
|
else
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
ADE_FUNC(runSEXP, l_Mission, "string", "Runs the defined SEXP script", "boolean", "if the operation was successful")
|
|
{
|
|
char *s;
|
|
int r_val;
|
|
char buf[8192];
|
|
|
|
if(!ade_get_args(L, "s", &s))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
while (is_white_space(*s))
|
|
s++;
|
|
if (*s != '(')
|
|
{
|
|
static bool Warned_about_runSEXP_parentheses = false;
|
|
if (!Warned_about_runSEXP_parentheses)
|
|
{
|
|
Warned_about_runSEXP_parentheses = true;
|
|
Warning(LOCATION, "Invalid SEXP syntax: SEXPs must be surrounded by parentheses. For backwards compatibility, the string has been enclosed in parentheses. This may not be correct in all use cases.");
|
|
}
|
|
// this is the old sexp handling method, which is incorrect
|
|
snprintf(buf, 8191, "( when ( true ) ( %s ) )", s);
|
|
}
|
|
else
|
|
{
|
|
// this is correct usage
|
|
snprintf(buf, 8191, "( when ( true ) %s )", s);
|
|
}
|
|
|
|
r_val = run_sexp(buf);
|
|
|
|
if (r_val == SEXP_TRUE)
|
|
return ADE_RETURN_TRUE;
|
|
else
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Asteroids
|
|
ade_lib l_Mission_Asteroids("Asteroids", &l_Mission, NULL, "Asteroids in the mission");
|
|
|
|
ADE_INDEXER(l_Mission_Asteroids, "number Index", "Gets asteroid", "asteroid", "Asteroid handle, or invalid handle if invalid index specified")
|
|
{
|
|
int idx = -1;
|
|
if( !ade_get_args(L, "*i", &idx) ) {
|
|
return ade_set_error( L, "o", l_Asteroid.Set( object_h() ) );
|
|
}
|
|
if( idx > -1 && idx < asteroid_count() ) {
|
|
idx--; //Convert from Lua to C, as lua indices start from 1, not 0
|
|
return ade_set_args( L, "o", l_Asteroid.Set( object_h( &Objects[Asteroids[idx].objnum] ), Objects[Asteroids[idx].objnum].signature ) );
|
|
}
|
|
|
|
return ade_set_error(L, "o", l_Asteroid.Set( object_h() ) );
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_Asteroids, NULL,
|
|
"Number of asteroids in mission. Note that the value returned is only good until an asteroid is destroyed, and so cannot be relied on for more than one frame.",
|
|
"number",
|
|
"Number of asteroids in the mission, or 0 if asteroids are not enabled")
|
|
{
|
|
if(Asteroids_enabled) {
|
|
return ade_set_args(L, "i", asteroid_count());
|
|
}
|
|
return ade_set_args(L, "i", 0);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Debris
|
|
ade_lib l_Mission_Debris("Debris", &l_Mission, NULL, "debris in the mission");
|
|
|
|
ADE_INDEXER(l_Mission_Debris, "number Index", "Array of debris in the current mission", "debris", "Debris handle, or invalid debris handle if index wasn't valid")
|
|
{
|
|
int idx = -1;
|
|
if( !ade_get_args( L, "*i", &idx ) ) {
|
|
return ade_set_error(L, "o", l_Debris.Set(object_h()));
|
|
}
|
|
if( idx > -1 && idx < Num_debris_pieces ) {
|
|
idx--; // Lua -> C
|
|
if (Debris[idx].objnum == -1) //Somehow accessed an invalid debris piece
|
|
return ade_set_error(L, "o", l_Debris.Set(object_h()));
|
|
return ade_set_args(L, "o", l_Debris.Set(object_h(&Objects[Debris[idx].objnum]), Objects[Debris[idx].objnum].signature));
|
|
}
|
|
|
|
return ade_set_error(L, "o", l_Debris.Set(object_h()));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_Debris, NULL,
|
|
"Number of debris pieces in the mission. "
|
|
"Note that the value returned is only good until a piece of debris is destroyed, and so cannot be relied on for more than one frame.",
|
|
"number",
|
|
"Current number of debris particles")
|
|
{
|
|
return ade_set_args(L, "i", Num_debris_pieces);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/EscortShips
|
|
ade_lib l_Mission_EscortShips("EscortShips", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_EscortShips, "number Index", "Gets escort ship at specified index on escort list", "ship", "Specified ship, or invalid ship handle if invalid index")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "*i", &idx))
|
|
return ade_set_error(L, "o", l_Ship.Set(object_h()));
|
|
|
|
if(idx < 1 || idx > hud_escort_num_ships_on_list())
|
|
return ade_set_error(L, "o", l_Ship.Set(object_h()));
|
|
|
|
//Lua->FS2
|
|
idx--;
|
|
|
|
idx = hud_escort_return_objnum(idx);
|
|
|
|
if(idx < 0)
|
|
return ade_set_error(L, "o", l_Ship.Set(object_h()));
|
|
|
|
return ade_set_args(L, "o", l_Ship.Set(object_h(&Objects[idx])));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_EscortShips, NULL, "Current number of escort ships", "number", "Current number of escort ships")
|
|
{
|
|
return ade_set_args(L, "i", hud_escort_num_ships_on_list());
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Events
|
|
ade_lib l_Mission_Events("Events", &l_Mission, NULL, "Events");
|
|
|
|
ADE_INDEXER(l_Mission_Events, "number Index/string Name", "Indexes events list", "event", "Event handle, or invalid event handle if index was invalid")
|
|
{
|
|
char *s;
|
|
if(!ade_get_args(L, "*s", &s))
|
|
return ade_set_error(L, "o", l_Event.Set(-1));
|
|
|
|
int i;
|
|
for(i = 0; i < Num_mission_events; i++)
|
|
{
|
|
if(!stricmp(Mission_events[i].name, s))
|
|
return ade_set_args(L, "o", l_Event.Set(i));
|
|
}
|
|
|
|
//Now try as a number
|
|
i = atoi(s);
|
|
if(i < 1 || i > Num_mission_events)
|
|
return ade_set_error(L, "o", l_Event.Set(-1));
|
|
|
|
//Lua-->FS2
|
|
i--;
|
|
|
|
return ade_set_args(L, "o", l_Event.Set(i));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_Events, NULL, "Number of events in mission", "number", "Number of events in mission")
|
|
{
|
|
return ade_set_args(L, "i", Num_mission_events);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/SEXPVariables
|
|
ade_lib l_Mission_SEXPVariables("SEXPVariables", &l_Mission, NULL, "SEXP Variables");
|
|
|
|
ADE_INDEXER(l_Mission_SEXPVariables, "number Index/string Name", "Array of SEXP variables. Note that you can set a sexp variable using the array, eg \'SEXPVariables[\"newvariable\"] = \"newvalue\"\'", "sexpvariable", "Handle to SEXP variable, or invalid sexpvariable handle if index was invalid")
|
|
{
|
|
char *name = NULL;
|
|
char *newval = NULL;
|
|
if(!ade_get_args(L, "*s|s", &name, &newval))
|
|
return ade_set_error(L, "o", l_SEXPVariable.Set(sexpvar_h()));
|
|
|
|
int idx = get_index_sexp_variable_name(name);
|
|
if(idx < 0)
|
|
{
|
|
idx = atoi(name);
|
|
|
|
//Lua-->FS2
|
|
idx--;
|
|
}
|
|
|
|
if(idx < 0 || idx >= MAX_SEXP_VARIABLES)
|
|
{
|
|
if(ADE_SETTING_VAR && newval != NULL)
|
|
{
|
|
idx = sexp_add_variable(newval, name, lua_type(L, 2) == LUA_TNUMBER ? SEXP_VARIABLE_NUMBER : SEXP_VARIABLE_STRING);
|
|
}
|
|
|
|
//We have failed.
|
|
if(idx < 0)
|
|
{
|
|
return ade_set_error(L, "o", l_SEXPVariable.Set(sexpvar_h()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(ADE_SETTING_VAR && newval != NULL)
|
|
{
|
|
sexp_modify_variable(newval, idx, false);
|
|
}
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_SEXPVariable.Set(sexpvar_h(idx)));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_SEXPVariables, NULL, "Current number of SEXP variables", "number", "Counts number of loaded SEXP Variables. May be slow.")
|
|
{
|
|
return ade_set_args(L, "i", sexp_variable_count());
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Ships
|
|
ade_lib l_Mission_Ships("Ships", &l_Mission, NULL, "Ships in the mission");
|
|
|
|
ADE_INDEXER(l_Mission_Ships, "number Index/string Name", "Gets ship", "ship", "Ship handle, or invalid ship handle if index was invalid")
|
|
{
|
|
char *name;
|
|
if(!ade_get_args(L, "*s", &name))
|
|
return ade_set_error(L, "o", l_Ship.Set(object_h()));
|
|
|
|
int idx = ship_name_lookup(name);
|
|
|
|
if(idx > -1)
|
|
{
|
|
return ade_set_args(L, "o", l_Ship.Set(object_h(&Objects[Ships[idx].objnum]), Objects[Ships[idx].objnum].signature));
|
|
}
|
|
else
|
|
{
|
|
idx = atoi(name);
|
|
if(idx > 0)
|
|
{
|
|
int count=1;
|
|
|
|
for(int i = 0; i < MAX_SHIPS; i++)
|
|
{
|
|
if (Ships[i].objnum < 0 || Objects[Ships[i].objnum].type != OBJ_SHIP)
|
|
continue;
|
|
|
|
if(count == idx) {
|
|
return ade_set_args(L, "o", l_Ship.Set(object_h(&Objects[Ships[i].objnum]), Objects[Ships[i].objnum].signature));
|
|
}
|
|
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ade_set_error(L, "o", l_Ship.Set(object_h()));
|
|
}
|
|
|
|
extern int ships_inited;
|
|
ADE_FUNC(__len, l_Mission_Ships, NULL,
|
|
"Number of ships in the mission. "
|
|
"This function is somewhat slow, and should be set to a variable for use in looping situations. "
|
|
"Note that the value returned is only good until a ship is destroyed, and so cannot be relied on for more than one frame.",
|
|
"number",
|
|
"Number of ships in the mission, or 0 if ships haven't been initialized yet")
|
|
{
|
|
if(ships_inited)
|
|
return ade_set_args(L, "i", ship_get_num_ships());
|
|
else
|
|
return ade_set_args(L, "i", 0);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Waypoints
|
|
ade_lib l_Mission_Waypoints("Waypoints", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_Waypoints, "number Index", "Array of waypoints in the current mission", "waypoint", "Waypoint handle, or invalid waypoint handle if index was invalid")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "*i", &idx))
|
|
return ade_set_error(L, "o", l_Waypoint.Set(object_h()));
|
|
|
|
//Remember, Lua indices start at 0.
|
|
int count=0;
|
|
|
|
object *ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list))
|
|
{
|
|
if (ptr->type == OBJ_WAYPOINT)
|
|
count++;
|
|
|
|
if(count == idx) {
|
|
return ade_set_args(L, "o", l_Waypoint.Set(object_h(ptr)));
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
|
|
return ade_set_error(L, "o", l_Weapon.Set(object_h()));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_Waypoints, NULL, "Gets number of waypoints in mission. Note that this is only accurate for one frame.", "number", "Number of waypoints in the mission")
|
|
{
|
|
uint count=0;
|
|
for(uint i = 0; i < MAX_OBJECTS; i++)
|
|
{
|
|
if (Objects[i].type == OBJ_WAYPOINT)
|
|
count++;
|
|
}
|
|
|
|
return ade_set_args(L, "i", count);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/WaypointLists
|
|
ade_lib l_Mission_WaypointLists("WaypointLists", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_WaypointLists, "number Index/string WaypointListName", "Array of waypoint lists", "waypointlist", "Gets waypointlist handle")
|
|
{
|
|
waypointlist_h wpl;
|
|
char *name;
|
|
if(!ade_get_args(L, "*s", &name))
|
|
return ade_set_error(L, "o", l_WaypointList.Set(waypointlist_h()));
|
|
|
|
wpl = waypointlist_h(name);
|
|
|
|
if (!wpl.IsValid()) {
|
|
int idx = atoi(name) - 1;
|
|
wpl = waypointlist_h(find_waypoint_list_at_index(idx));
|
|
}
|
|
|
|
if (wpl.IsValid()) {
|
|
return ade_set_args(L, "o", l_WaypointList.Set(wpl));
|
|
}
|
|
|
|
return ade_set_error(L, "o", l_WaypointList.Set(waypointlist_h()));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_WaypointLists, NULL, "Number of waypoint lists in mission. Note that this is only accurate for one frame.", "number", "Number of waypoint lists in the mission")
|
|
{
|
|
return ade_set_args(L, "i", Waypoint_lists.size());
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Weapons
|
|
ade_lib l_Mission_Weapons("Weapons", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_Weapons, "number Index", "Gets handle to a weapon object in the mission.", "weapon", "Weapon handle, or invalid weapon handle if index is invalid")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "*i", &idx))
|
|
return ade_set_error(L, "o", l_Weapon.Set(object_h()));
|
|
|
|
//Remember, Lua indices start at 0.
|
|
int count=1;
|
|
|
|
for(int i = 0; i < MAX_WEAPONS; i++)
|
|
{
|
|
if (Weapons[i].weapon_info_index < 0 || Weapons[i].objnum < 0 || Objects[Weapons[i].objnum].type != OBJ_WEAPON)
|
|
continue;
|
|
|
|
if(count == idx) {
|
|
return ade_set_args(L, "o", l_Weapon.Set(object_h(&Objects[Weapons[i].objnum])));
|
|
}
|
|
|
|
count++;
|
|
}
|
|
|
|
return ade_set_error(L, "o", l_Weapon.Set(object_h()));
|
|
}
|
|
ADE_FUNC(__len, l_Mission_Weapons, NULL, "Number of weapon objects in mission. Note that this is only accurate for one frame.", "number", "Number of weapon objects in mission")
|
|
{
|
|
return ade_set_args(L, "i", Num_weapons);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Beams
|
|
ade_lib l_Mission_Beams("Beams", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_Beams, "number Index", "Gets handle to a beam object in the mission.", "beam", "Beam handle, or invalid beam handle if index is invalid")
|
|
{
|
|
int idx;
|
|
if(!ade_get_args(L, "*i", &idx))
|
|
return ade_set_error(L, "o", l_Beam.Set(object_h()));
|
|
|
|
//Remember, Lua indices start at 0.
|
|
int count=1;
|
|
|
|
for(int i = 0; i < MAX_BEAMS; i++)
|
|
{
|
|
if (Beams[i].weapon_info_index < 0 || Beams[i].objnum < 0 || Objects[Beams[i].objnum].type != OBJ_BEAM)
|
|
continue;
|
|
|
|
if(count == idx) {
|
|
return ade_set_args(L, "o", l_Beam.Set(object_h(&Objects[Beams[i].objnum])));
|
|
}
|
|
|
|
count++;
|
|
}
|
|
|
|
return ade_set_error(L, "o", l_Beam.Set(object_h()));
|
|
}
|
|
ADE_FUNC(__len, l_Mission_Beams, NULL, "Number of beam objects in mission. Note that this is only accurate for one frame.", "number", "Number of beam objects in mission")
|
|
{
|
|
return ade_set_args(L, "i", Beam_count);
|
|
}
|
|
|
|
//****SUBLIBRARY: Campaign
|
|
ade_lib l_Campaign("Campaign", NULL, "ca", "Campaign Library");
|
|
|
|
ADE_FUNC(getNextMissionFilename, l_Campaign, NULL, "Gets next mission filename", "string", "Next mission filename, or nil if the next mission is invalid")
|
|
{
|
|
if (Campaign.next_mission < 0 || Campaign.next_mission >= MAX_CAMPAIGN_MISSIONS) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
return ade_set_args(L, "s", Campaign.missions[Campaign.next_mission].name);
|
|
}
|
|
|
|
ADE_FUNC(getPrevMissionFilename, l_Campaign, NULL, "Gets previous mission filename", "string", "Previous mission filename, or nil if the previous mission is invalid")
|
|
{
|
|
if (Campaign.prev_mission < 0 || Campaign.prev_mission >= MAX_CAMPAIGN_MISSIONS) {
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
return ade_set_args(L, "s", Campaign.missions[Campaign.prev_mission].name);
|
|
}
|
|
|
|
// DahBlount - This jumps to a mission, the reason it accepts a boolean value is so that players can return to campaign maps
|
|
ADE_FUNC(jumpToMission, l_Campaign, "string filename, [boolean hub]", "Jumps to a mission based on the filename. Optionally, the player can be sent to a hub mission without setting missions to skipped.", "boolean", "Jumps to a mission, or returns nil.")
|
|
{
|
|
char *filename = NULL;;
|
|
bool hub = false;
|
|
if (!ade_get_args(L, "s|b", &filename, &hub))
|
|
return ADE_RETURN_NIL;
|
|
|
|
mission_campaign_jump_to_mission(filename, hub);
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
// TODO: add a proper indexer type that returns a handle
|
|
// something like ca.Mission[filename/index]
|
|
|
|
//****SUBLIBRARY: Mission/Wings
|
|
ade_lib l_Mission_Wings("Wings", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_Wings, "number Index/string WingName", "Wings in the mission", "wing", "Wing handle, or invalid wing handle if index or name was invalid")
|
|
{
|
|
char *name;
|
|
if(!ade_get_args(L, "*s", &name))
|
|
return ade_set_error(L, "o", l_Wing.Set(-1));
|
|
|
|
//MageKing17 - Make the count-ignoring version of the lookup and leave checking if the wing has any ships to the scripter
|
|
int idx = wing_lookup(name);
|
|
|
|
if(idx < 0)
|
|
{
|
|
idx = atoi(name);
|
|
if(idx < 1 || idx > Num_wings)
|
|
return ade_set_error(L, "o", l_Wing.Set(-1));
|
|
|
|
idx--; //Lua->FS2
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Wing.Set(idx));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_Wings, NULL, "Number of wings in mission", "number", "Number of wings in mission")
|
|
{
|
|
return ade_set_args(L, "i", Num_wings);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Teams
|
|
ade_lib l_Mission_Teams("Teams", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_Teams, "number Index/string TeamName", "Teams in the mission", "team", "Team handle or invalid team handle if the requested team could not be found")
|
|
{
|
|
char *name;
|
|
if(!ade_get_args(L, "*s", &name))
|
|
return ade_set_error(L, "o", l_Team.Set(-1));
|
|
|
|
int idx = iff_lookup(name);
|
|
|
|
if(idx < 0)
|
|
{
|
|
idx = atoi(name);
|
|
|
|
idx--; //Lua->FS2
|
|
}
|
|
|
|
if(idx < 0 || idx >= Num_iffs)
|
|
return ade_set_error(L, "o", l_Team.Set(-1));
|
|
|
|
return ade_set_args(L, "o", l_Team.Set(idx));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_Teams, NULL, "Number of teams in mission", "number", "Number of teams in mission")
|
|
{
|
|
return ade_set_args(L, "i", Num_iffs);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Messages
|
|
ade_lib l_Mission_Messages("Messages", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_Messages, "number Index/string messageName", "Messages of the mission", "message", "Message handle or invalid handle on error")
|
|
{
|
|
int idx = -1;
|
|
|
|
if (lua_isnumber(L, 2))
|
|
{
|
|
if (!ade_get_args(L, "*i", &idx))
|
|
return ade_set_args(L, "o", l_Message.Set(-1));
|
|
|
|
idx--; // Lua --> FS2
|
|
|
|
idx += Num_builtin_messages;
|
|
}
|
|
else
|
|
{
|
|
char* name = NULL;
|
|
|
|
if (!ade_get_args(L, "*s", &name))
|
|
return ade_set_args(L, "o", l_Message.Set(-1));
|
|
|
|
if (name == NULL)
|
|
return ade_set_args(L, "o", l_Message.Set(-1));
|
|
|
|
for (int i = Num_builtin_messages; i < (int) Messages.size(); i++)
|
|
{
|
|
if (!stricmp(Messages[i].name, name))
|
|
{
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (idx < Num_builtin_messages || idx >= (int) Messages.size())
|
|
return ade_set_args(L, "o", l_Message.Set(-1));
|
|
else
|
|
return ade_set_args(L, "o", l_Message.Set(idx));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_Messages, NULL, "Number of messages in the mission", "number", "Number of messages in mission")
|
|
{
|
|
return ade_set_args(L, "i", (int) Messages.size() - Num_builtin_messages);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/BuiltinMessages
|
|
ade_lib l_Mission_BuiltinMessages("BuiltinMessages", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_BuiltinMessages, "number Index/string messageName", "Built-in messages of the mission", "message", "Message handle or invalid handle on error")
|
|
{
|
|
int idx = -1;
|
|
|
|
if (lua_isnumber(L, 2))
|
|
{
|
|
if (!ade_get_args(L, "*i", &idx))
|
|
return ade_set_args(L, "o", l_Message.Set(-1));
|
|
|
|
idx--; // Lua --> FS2
|
|
}
|
|
else
|
|
{
|
|
char* name = NULL;
|
|
|
|
if (!ade_get_args(L, "*s", &name))
|
|
return ade_set_args(L, "o", l_Message.Set(-1));
|
|
|
|
if (name == NULL)
|
|
return ade_set_args(L, "o", l_Message.Set(-1));
|
|
|
|
for (int i = 0; i < Num_builtin_messages; i++)
|
|
{
|
|
if (!stricmp(Messages[i].name, name))
|
|
{
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (idx < 0 || idx >= Num_builtin_messages)
|
|
return ade_set_args(L, "o", l_Message.Set(-1));
|
|
else
|
|
return ade_set_args(L, "o", l_Message.Set(idx));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_BuiltinMessages, NULL, "Number of built-in messages in the mission", "number", "Number of messages in mission")
|
|
{
|
|
return ade_set_args(L, "i", Num_builtin_messages);
|
|
}
|
|
|
|
//****SUBLIBRARY: Mission/Personas
|
|
ade_lib l_Mission_Personas("Personas", &l_Mission, NULL, NULL);
|
|
|
|
ADE_INDEXER(l_Mission_Personas, "number Index/string name", "Personas of the mission", "persona", "Persona handle or invalid handle on error")
|
|
{
|
|
int idx = -1;
|
|
|
|
if (lua_isnumber(L, 2))
|
|
{
|
|
if (!ade_get_args(L, "*i", &idx))
|
|
return ade_set_args(L, "o", l_Persona.Set(-1));
|
|
|
|
idx--; // Lua --> FS2
|
|
}
|
|
else
|
|
{
|
|
char* name = NULL;
|
|
|
|
if (!ade_get_args(L, "*s", &name))
|
|
return ade_set_args(L, "o", l_Persona.Set(-1));
|
|
|
|
if (name == NULL)
|
|
return ade_set_args(L, "o", l_Persona.Set(-1));
|
|
|
|
idx = message_persona_name_lookup(name);
|
|
}
|
|
|
|
if (idx < 0 || idx >= Num_personas)
|
|
return ade_set_args(L, "o", l_Persona.Set(-1));
|
|
else
|
|
return ade_set_args(L, "o", l_Persona.Set(idx));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Mission_Personas, NULL, "Number of personas in the mission", "number", "Number of messages in mission")
|
|
{
|
|
return ade_set_args(L, "i", Num_personas);
|
|
}
|
|
|
|
ADE_FUNC(addMessage, l_Mission, "string name, string text[, persona persona]", "Adds a message", "message", "The new message or invalid handle on error")
|
|
{
|
|
char* name = NULL;
|
|
char* text = NULL;
|
|
int personaIdx = -1;
|
|
|
|
if (!ade_get_args(L, "ss|o", &name, &text, l_Persona.Get(&personaIdx)))
|
|
return ade_set_error(L, "o", l_Message.Set(-1));
|
|
|
|
if (name == NULL || text == NULL)
|
|
return ade_set_error(L, "o", l_Message.Set(-1));
|
|
|
|
if (personaIdx < 0 || personaIdx >= Num_personas)
|
|
personaIdx = -1;
|
|
|
|
add_message(name, text, personaIdx, 0);
|
|
|
|
return ade_set_error(L, "o", l_Message.Set((int) Messages.size() - 1));
|
|
}
|
|
|
|
ADE_FUNC(sendMessage, l_Mission, "string sender, message message[, number delay=0.0[, enumeration priority = MESSAGE_PRIORITY_NORMAL[, boolean fromCommand = false]]]",
|
|
"Sends a message from the given source (not from a ship!) with the given priority or optionally sends it from the missions command source.<br>"
|
|
"If delay is specified the message will be delayed by the specified time in seconds<br>"
|
|
"If you pass <i>nil</i> as the sender then the message will not have a sender.",
|
|
"boolean", "true if successfull, false otherwise")
|
|
{
|
|
char* sender = NULL;
|
|
int messageIdx = -1;
|
|
int priority = MESSAGE_PRIORITY_NORMAL;
|
|
bool fromCommand = false;
|
|
int messageSource = MESSAGE_SOURCE_SPECIAL;
|
|
float delay = 0.0f;
|
|
|
|
enum_h* ehp = NULL;
|
|
|
|
// if first is nil then use no source
|
|
if (lua_isnil(L, 1))
|
|
{
|
|
if (!ade_get_args(L, "*o|fob", l_Message.Get(&messageIdx), &delay, l_Enum.GetPtr(&ehp), &fromCommand))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
messageSource = MESSAGE_SOURCE_NONE;
|
|
}
|
|
else
|
|
{
|
|
if (!ade_get_args(L, "so|fob", &sender, l_Message.Get(&messageIdx), &delay, l_Enum.GetPtr(&ehp), &fromCommand))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
if (sender == NULL)
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
if (fromCommand)
|
|
messageSource = MESSAGE_SOURCE_COMMAND;
|
|
|
|
if (messageIdx < 0 || messageIdx >= (int) Messages.size())
|
|
return ADE_RETURN_FALSE;
|
|
|
|
if (messageIdx < Num_builtin_messages)
|
|
{
|
|
LuaError(L, "Cannot send built-in messages!");
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
if (delay < 0.0f)
|
|
{
|
|
LuaError(L, "Invalid negative delay of %f!", delay);
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
if (ehp != NULL)
|
|
{
|
|
switch(ehp->index)
|
|
{
|
|
case LE_MESSAGE_PRIORITY_HIGH:
|
|
priority = MESSAGE_PRIORITY_HIGH;
|
|
break;
|
|
case LE_MESSAGE_PRIORITY_NORMAL:
|
|
priority = MESSAGE_PRIORITY_NORMAL;
|
|
break;
|
|
case LE_MESSAGE_PRIORITY_LOW:
|
|
priority = MESSAGE_PRIORITY_LOW;
|
|
break;
|
|
default:
|
|
LuaError(L, "Invalid enumeration used! Must be one of MESSAGE_PRIORITY_*.");
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
}
|
|
|
|
if (messageSource == MESSAGE_SOURCE_NONE)
|
|
message_send_unique_to_player(Messages[messageIdx].name, NULL, MESSAGE_SOURCE_NONE, priority, 0, fl2i(delay * 1000.0f));
|
|
else
|
|
message_send_unique_to_player(Messages[messageIdx].name, (void*) sender, messageSource, priority, 0, fl2i(delay * 1000.0f));
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
ADE_FUNC(sendTrainingMessage, l_Mission, "message message, number time[, number delay=0.0]",
|
|
"Sends a training message to the player. <i>time</i> is the amount in seconds to display the message, only whole seconds are used!",
|
|
"boolean", "true if successfull, false otherwise")
|
|
{
|
|
int messageIdx = -1;
|
|
float delay = 0.0f;
|
|
int time = -1;
|
|
|
|
if (!ade_get_args(L, "oi|f", l_Message.Get(&messageIdx), &time, &delay))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
if (messageIdx < 0 || messageIdx >= (int) Messages.size())
|
|
return ADE_RETURN_FALSE;
|
|
|
|
if (delay < 0.0f)
|
|
{
|
|
LuaError(L, "Got invalid delay of %f seconds!", delay);
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
if (time < 0)
|
|
{
|
|
LuaError(L, "Got invalid time of %d seconds!", time);
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
message_training_queue(Messages[messageIdx].name, timestamp(fl2i(delay * 1000.0f)), time);
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
ADE_FUNC(createShip, l_Mission, "[string Name, shipclass Class=Shipclass[1], orientation Orientation=null, vector Position={0,0,0}]", "Creates a ship and returns a handle to it using the specified name, class, world orientation, and world position", "ship", "Ship handle, or invalid ship handle if ship couldn't be created")
|
|
{
|
|
char *name = NULL;
|
|
int sclass = -1;
|
|
matrix_h *orient = NULL;
|
|
vec3d pos = vmd_zero_vector;
|
|
ade_get_args(L, "|sooo", &name, l_Shipclass.Get(&sclass), l_Matrix.GetPtr(&orient), l_Vector.Get(&pos));
|
|
|
|
matrix *real_orient = &vmd_identity_matrix;
|
|
if(orient != NULL)
|
|
{
|
|
real_orient = orient->GetMatrix();
|
|
}
|
|
|
|
int obj_idx = ship_create(real_orient, &pos, sclass, name);
|
|
|
|
if(obj_idx > -1) {
|
|
model_page_in_textures(Ship_info[sclass].model_num, sclass);
|
|
|
|
return ade_set_args(L, "o", l_Ship.Set(object_h(&Objects[obj_idx]), Objects[obj_idx].signature));
|
|
} else
|
|
return ade_set_error(L, "o", l_Ship.Set(object_h()));
|
|
}
|
|
|
|
ADE_FUNC(createWaypoint, l_Mission, "[vector Position, waypointlist List]",
|
|
"Creates a waypoint",
|
|
"waypoint",
|
|
"Waypoint handle, or invalid waypoint handle if waypoint couldn't be created")
|
|
{
|
|
vec3d *v3 = NULL;
|
|
waypointlist_h *wlh = NULL;
|
|
if(!ade_get_args(L, "|oo", l_Vector.GetPtr(&v3), l_WaypointList.GetPtr(&wlh)))
|
|
return ade_set_error(L, "o", l_Waypoint.Set(object_h()));
|
|
|
|
// determine where we need to create it - it looks like we were given a waypoint list but not a waypoint itself
|
|
int waypoint_instance = -1;
|
|
if (wlh && wlh->IsValid())
|
|
{
|
|
int wp_list_index = find_index_of_waypoint_list(wlh->wlp);
|
|
int wp_index = (int) wlh->wlp->get_waypoints().size() - 1;
|
|
waypoint_instance = calc_waypoint_instance(wp_list_index, wp_index);
|
|
}
|
|
int obj_idx = waypoint_add(v3 != NULL ? v3 : &vmd_zero_vector, waypoint_instance);
|
|
|
|
if(obj_idx >= 0)
|
|
return ade_set_args(L, "o", l_Waypoint.Set(object_h(&Objects[obj_idx])));
|
|
else
|
|
return ade_set_args(L, "o", l_Waypoint.Set(object_h()));
|
|
}
|
|
|
|
ADE_FUNC(createWeapon, l_Mission, "[weaponclass Class=WeaponClass[1], orientation Orientation=null, world vector Position={0,0,0}, object Parent = nil, number Group = -1",
|
|
"Creates a weapon and returns a handle to it. 'Group' is used for lighting grouping purposes;"
|
|
" for example, quad lasers would only need to act as one light source.",
|
|
"weapon",
|
|
"Weapon handle, or invalid weapon handle if weapon couldn't be created.")
|
|
{
|
|
int wclass = -1;
|
|
object_h *parent = NULL;
|
|
int group = -1;
|
|
matrix_h *orient = NULL;
|
|
vec3d pos = vmd_zero_vector;
|
|
ade_get_args(L, "|ooooi", l_Weaponclass.Get(&wclass), l_Matrix.GetPtr(&orient), l_Vector.Get(&pos), l_Object.GetPtr(&parent), &group);
|
|
|
|
matrix *real_orient = &vmd_identity_matrix;
|
|
if(orient != NULL)
|
|
{
|
|
real_orient = orient->GetMatrix();
|
|
}
|
|
|
|
int parent_idx = (parent && parent->IsValid()) ? OBJ_INDEX(parent->objp) : -1;
|
|
|
|
int obj_idx = weapon_create(&pos, real_orient, wclass, parent_idx, group);
|
|
|
|
if(obj_idx > -1)
|
|
return ade_set_args(L, "o", l_Weapon.Set(object_h(&Objects[obj_idx]), Objects[obj_idx].signature));
|
|
else
|
|
return ade_set_error(L, "o", l_Weapon.Set(object_h()));
|
|
}
|
|
|
|
ADE_FUNC(getMissionFilename, l_Mission, NULL, "Gets mission filename", "string", "Mission filename, or empty string if game is not in a mission")
|
|
{
|
|
return ade_set_args(L, "s", Game_current_mission_filename);
|
|
}
|
|
|
|
ADE_FUNC(startMission, l_Mission, "[Filename or MISSION_* enumeration, Briefing = true]", "Starts the defined mission", "boolean", "True, or false if the function fails")
|
|
{
|
|
bool b = true;
|
|
char s[MAX_FILENAME_LEN];
|
|
char *str = s;
|
|
|
|
if(lua_isstring(L, 1))
|
|
{
|
|
if (!ade_get_args(L, "s|b", &str, &b))
|
|
return ade_set_args(L, "b", false);
|
|
|
|
} else {
|
|
enum_h *e = NULL;
|
|
|
|
if (!ade_get_args(L, "o|b", l_Enum.GetPtr(&e), &b))
|
|
return ade_set_args(L, "b", false);
|
|
|
|
if (e->index == LE_MISSION_REPEAT) {
|
|
if (Num_recent_missions > 0) {
|
|
strncpy( s, Recent_missions[0], MAX_FILENAME_LEN );
|
|
} else {
|
|
return ade_set_args(L, "b", false);
|
|
}
|
|
} else {
|
|
return ade_set_args(L, "b", false);
|
|
}
|
|
}
|
|
|
|
// no filename... bail
|
|
if (str == NULL)
|
|
return ade_set_args(L, "b", false);
|
|
|
|
// if mission name has extension... it needs to be removed...
|
|
char *file_ext;
|
|
|
|
file_ext = strrchr(str, '.');
|
|
if (file_ext)
|
|
*file_ext = 0;
|
|
|
|
// game is in MP mode... or if the file does not exist... bail
|
|
if ((Game_mode & GM_MULTIPLAYER) || (cf_exists_full(str, CF_TYPE_MISSIONS) != 0))
|
|
return ade_set_args(L, "b", false);
|
|
|
|
// mission is already running...
|
|
if (Game_mode & GM_IN_MISSION) {
|
|
// TO DO... All the things needed if this function is called in any state of the game while mission is running.
|
|
// most likely all require 'stricmp(str, Game_current_mission_filename)' to make sure missions arent mixed
|
|
// but after that it might be possible to imprement method for jumping directly into already running
|
|
// missions.
|
|
return ade_set_args(L, "b", false);
|
|
// if mission is not running
|
|
} else {
|
|
// due safety checks of the game_start_mission() function allow only main menu for now.
|
|
if (gameseq_get_state(gameseq_get_depth()) == GS_STATE_MAIN_MENU) {
|
|
strcpy_s( Game_current_mission_filename, str );
|
|
if (b == true) {
|
|
// start mission - go via briefing screen
|
|
gameseq_post_event(GS_EVENT_START_GAME);
|
|
} else {
|
|
// start mission - enter the game directly
|
|
gameseq_post_event(GS_EVENT_START_GAME_QUICK);
|
|
}
|
|
return ade_set_args(L, "b", true);
|
|
}
|
|
}
|
|
return ade_set_args(L, "b", false);
|
|
}
|
|
|
|
ADE_FUNC(getMissionTime, l_Mission, NULL, "Game time in seconds since the mission was started; is affected by time compression", "number", "Mission time (seconds), or 0 if game is not in a mission")
|
|
{
|
|
if(!(Game_mode & GM_IN_MISSION))
|
|
return ade_set_error(L, "f", 0.0f);
|
|
|
|
return ade_set_args(L, "x", Missiontime);
|
|
}
|
|
|
|
//WMC - These are in freespace.cpp
|
|
ADE_FUNC(loadMission, l_Mission, "Mission name", "Loads a mission", "boolean", "True if mission was loaded, otherwise false")
|
|
{
|
|
char *s;
|
|
if(!ade_get_args(L, "s", &s))
|
|
return ade_set_error(L, "b", false);
|
|
|
|
// clear post processing settings
|
|
gr_post_process_set_defaults();
|
|
|
|
//NOW do the loading stuff
|
|
game_stop_time();
|
|
get_mission_info(s, &The_mission, false);
|
|
game_level_init();
|
|
|
|
if(mission_load(s) == -1)
|
|
return ADE_RETURN_FALSE;
|
|
|
|
game_post_level_init();
|
|
|
|
Game_mode |= GM_IN_MISSION;
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
ADE_FUNC(unloadMission, l_Mission, NULL, "Stops the current mission and unloads it", NULL, NULL)
|
|
{
|
|
if(Game_mode & GM_IN_MISSION)
|
|
{
|
|
game_level_close();
|
|
Game_mode &= ~GM_IN_MISSION;
|
|
strcpy_s(Game_current_mission_filename, "");
|
|
}
|
|
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
ADE_FUNC(simulateFrame, l_Mission, NULL, "Simulates mission frame", NULL, NULL)
|
|
{
|
|
game_update_missiontime();
|
|
game_simulation_frame();
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
ADE_FUNC(renderFrame, l_Mission, NULL, "Renders mission frame, but does not move anything", NULL, NULL)
|
|
{
|
|
camid cid = game_render_frame_setup();
|
|
game_render_frame( cid );
|
|
game_render_post_frame();
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
ADE_FUNC(applyShudder, l_Mission, "number time, number intesity", "Applies a shudder effects to the camera. Time is in seconds. Intensity specifies the shudder effect strength, the Maxim has a value of 1440.", "boolean", "true if successfull, false otherwise")
|
|
{
|
|
float time = -1.0f;
|
|
float intensity = -1.0f;
|
|
|
|
if (!ade_get_args(L, "ff", &time, &intensity))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
if (time < 0.0f || intensity < 0.0f)
|
|
{
|
|
LuaError(L, "Illegal shudder values given. Must be bigger than zero, got time of %f and intensity of %f.", time, intensity);
|
|
return ADE_RETURN_FALSE;
|
|
}
|
|
|
|
int int_time = fl2i(time * 1000.0f);
|
|
|
|
game_shudder_apply(int_time, intensity * 0.01f);
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
ADE_FUNC(isInCampaign, l_Mission, NULL, "Get whether or not the current mission being played in a campaign (as opposed to the tech room's simulator)", "boolean", "true if in campaign, false if not")
|
|
{
|
|
bool b = false;
|
|
|
|
if (Game_mode & GM_CAMPAIGN_MODE) {
|
|
b = true;
|
|
}
|
|
|
|
return ade_set_args(L, "b", b);
|
|
}
|
|
|
|
//**********LIBRARY: Tables
|
|
ade_lib l_Tables("Tables", NULL, "tb", "Tables library");
|
|
|
|
//*****SUBLIBRARY: Tables/ShipClasses
|
|
ade_lib l_Tables_ShipClasses("ShipClasses", &l_Tables, NULL, NULL);
|
|
ADE_INDEXER(l_Tables_ShipClasses, "number Index/string Name", "Array of ship classes", "shipclass", "Ship handle, or invalid ship handle if index is invalid")
|
|
{
|
|
if(!ships_inited)
|
|
return ade_set_error(L, "o", l_Shipclass.Set(-1));
|
|
|
|
char *name;
|
|
if(!ade_get_args(L, "*s", &name))
|
|
return ade_set_error(L, "o", l_Shipclass.Set(-1));
|
|
|
|
int idx = ship_info_lookup(name);
|
|
|
|
if(idx < 0) {
|
|
idx = atoi(name);
|
|
if(idx < 1 || idx >= static_cast<int>(Ship_info.size()))
|
|
return ade_set_error(L, "o", l_Shipclass.Set(-1));
|
|
|
|
idx--; //Lua->FS2
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Shipclass.Set(idx));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Tables_ShipClasses, NULL, "Number of ship classes", "number", "Number of ship classes, or 0 if ship classes haven't been loaded yet")
|
|
{
|
|
if(!ships_inited)
|
|
return ade_set_args(L, "i", 0); //No ships loaded...should be 0
|
|
|
|
return ade_set_args(L, "i", Ship_info.size());
|
|
}
|
|
|
|
//*****SUBLIBRARY: Tables/WeaponClasses
|
|
ade_lib l_Tables_WeaponClasses("WeaponClasses", &l_Tables, NULL, NULL);
|
|
|
|
extern int Weapons_inited;
|
|
|
|
ADE_INDEXER(l_Tables_WeaponClasses, "number Index/string WeaponName", "Array of weapon classes", "weapon", "Weapon class handle, or invalid weaponclass handle if index is invalid")
|
|
{
|
|
if(!Weapons_inited)
|
|
return ade_set_error(L, "o", l_Weaponclass.Set(-1));
|
|
|
|
char *name;
|
|
if(!ade_get_args(L, "*s", &name))
|
|
return 0;
|
|
|
|
int idx = weapon_info_lookup(name);
|
|
|
|
if(idx < 0) {
|
|
idx = atoi(name);
|
|
|
|
// atoi is good enough here, 0 is invalid anyway
|
|
if (idx > 0)
|
|
{
|
|
idx--; // Lua --> C/C++
|
|
}
|
|
else
|
|
{
|
|
return ade_set_args(L, "o", l_Weaponclass.Set(-1));
|
|
}
|
|
}
|
|
|
|
return ade_set_args(L, "o", l_Weaponclass.Set(idx));
|
|
}
|
|
|
|
ADE_FUNC(__len, l_Tables_WeaponClasses, NULL, "Number of weapon classes", "number", "Number of weapon classes, or 0 if weapon classes haven't been loaded yet")
|
|
{
|
|
if(!Weapons_inited)
|
|
return ade_set_args(L, "i", 0);
|
|
|
|
return ade_set_args(L, "i", Num_weapon_types);
|
|
}
|
|
|
|
//*************************Testing stuff*************************
|
|
//This section is for stuff that's considered experimental.
|
|
ade_lib l_Testing("Testing", NULL, "ts", "Experimental or testing stuff");
|
|
|
|
ADE_FUNC(avdTest, l_Testing, NULL, "Test the AVD Physics code", NULL, NULL)
|
|
{
|
|
static bool initialized = false;
|
|
static avd_movement avd;
|
|
|
|
if(!initialized)
|
|
{
|
|
avd.setAVD(10.0f, 3.0f, 1.0f, 1.0f, 0.0f);
|
|
initialized = true;
|
|
}
|
|
for(int i = 0; i < 3000; i++)
|
|
{
|
|
float Pc, Vc;
|
|
avd.get((float)i/1000.0f, &Pc, &Vc);
|
|
gr_set_color(0, 255, 0);
|
|
gr_pixel(i/10, gr_screen.clip_bottom - (int)(Pc*10.0f), GR_RESIZE_NONE);
|
|
gr_set_color(255, 0, 0);
|
|
gr_pixel(i/10, gr_screen.clip_bottom - (int)(Vc*10.0f), GR_RESIZE_NONE);
|
|
|
|
avd.get(&Pc, &Vc);
|
|
gr_set_color(255, 255, 255);
|
|
gr_pixel((timestamp()%3000)/10, gr_screen.clip_bottom - (int)(Pc*10.0f), GR_RESIZE_NONE);
|
|
gr_pixel((timestamp()%3000)/10, gr_screen.clip_bottom - (int)(Vc*10.0f), GR_RESIZE_NONE);
|
|
}
|
|
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
ADE_FUNC(createParticle, l_Testing, "vector Position, vector Velocity, number Lifetime, number Radius, enumeration Type, [number Tracer length=-1, boolean Reverse=false, texture Texture=Nil, object Attached Object=Nil]",
|
|
"Creates a particle. Use PARTICLE_* enumerations for type."
|
|
"Reverse reverse animation, if one is specified"
|
|
"Attached object specifies object that Position will be (and always be) relative to.",
|
|
"particle",
|
|
"Handle to the created particle")
|
|
{
|
|
particle::particle_info pi;
|
|
pi.type = particle::PARTICLE_DEBUG;
|
|
pi.optional_data = -1;
|
|
pi.attached_objnum = -1;
|
|
pi.attached_sig = -1;
|
|
pi.reverse = 0;
|
|
|
|
// Need to consume tracer_length parameter but it isn't used anymore
|
|
float temp;
|
|
|
|
enum_h *type = NULL;
|
|
bool rev=false;
|
|
object_h *objh=NULL;
|
|
if(!ade_get_args(L, "ooffo|fboo", l_Vector.Get(&pi.pos), l_Vector.Get(&pi.vel), &pi.lifetime, &pi.rad, l_Enum.GetPtr(&type), &temp, &rev, l_Texture.Get((int*)&pi.optional_data), l_Object.GetPtr(&objh)))
|
|
return ADE_RETURN_NIL;
|
|
|
|
if(type != NULL)
|
|
{
|
|
switch(type->index)
|
|
{
|
|
case LE_PARTICLE_DEBUG:
|
|
pi.type = particle::PARTICLE_DEBUG;
|
|
break;
|
|
case LE_PARTICLE_FIRE:
|
|
pi.type = particle::PARTICLE_FIRE;
|
|
break;
|
|
case LE_PARTICLE_SMOKE:
|
|
pi.type = particle::PARTICLE_SMOKE;
|
|
break;
|
|
case LE_PARTICLE_SMOKE2:
|
|
pi.type = particle::PARTICLE_SMOKE2;
|
|
break;
|
|
case LE_PARTICLE_BITMAP:
|
|
if (pi.optional_data < 0)
|
|
{
|
|
LuaError(L, "Invalid texture specified for createParticle()!");
|
|
}
|
|
|
|
pi.type = particle::PARTICLE_BITMAP;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(rev)
|
|
pi.reverse = 0;
|
|
|
|
if(objh != NULL && objh->IsValid())
|
|
{
|
|
pi.attached_objnum = OBJ_INDEX(objh->objp);
|
|
pi.attached_sig = objh->objp->signature;
|
|
}
|
|
|
|
particle::WeakParticlePtr p = particle::create(&pi);
|
|
|
|
if (!p.expired())
|
|
return ade_set_args(L, "o", l_Particle.Set(particle_h(p)));
|
|
else
|
|
return ADE_RETURN_NIL;
|
|
}
|
|
|
|
ADE_FUNC(getStack, l_Testing, NULL, "Generates an ADE stackdump", "string", "Current Lua stack")
|
|
{
|
|
char buf[10240] = {'\0'};
|
|
ade_stackdump(L, buf);
|
|
return ade_set_args(L, "s", buf);
|
|
}
|
|
|
|
ADE_FUNC(isCurrentPlayerMulti, l_Testing, NULL, "Returns whether current player is a multiplayer pilot or not.", "boolean", "Whether current player is a multiplayer pilot or not")
|
|
{
|
|
if(Player == NULL)
|
|
return ade_set_error(L, "b", false);
|
|
|
|
if(!(Player->flags & PLAYER_FLAGS_IS_MULTI))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
// Om_tracker_flag should already be set in FreeSpace.cpp, needed to determine if PXO is enabled from the registry
|
|
extern int Om_tracker_flag; // needed for FS2OpenPXO config
|
|
|
|
ADE_FUNC(isPXOEnabled, l_Testing, NULL, "Returns whether PXO is currently enabled in the configuration.", "boolean", "Whether PXO is enabled or not")
|
|
{
|
|
if(!(Om_tracker_flag))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
ADE_FUNC(playCutscene, l_Testing, NULL, "Forces a cutscene by the specified filename string to play. Should really only be used in a non-gameplay state (i.e. start of GS_STATE_BRIEFING) otherwise odd side effects may occur. Highly Experimental.", "string", NULL)
|
|
{
|
|
//This whole thing is a quick hack and can probably be done way better, but is currently functioning fine for my purposes.
|
|
char *filename;
|
|
|
|
if (!ade_get_args(L, "s", &filename))
|
|
return ADE_RETURN_FALSE;
|
|
|
|
movie::play(filename);
|
|
|
|
return ADE_RETURN_TRUE;
|
|
}
|
|
|
|
//###########################################################
|
|
//########################<IMPORTANT>########################
|
|
//###########################################################
|
|
//If you are a coder who wants to add libraries, functions,
|
|
//or objects to Lua, then you want to be above this point.
|
|
//###########################################################
|
|
//########################</IMPORTANT>#######################
|
|
//###########################################################
|
|
|
|
// *************************Housekeeping*************************
|
|
//WMC - The miraculous lines of code that make Lua debugging worth something.
|
|
lua_Debug Ade_debug_info;
|
|
char debug_stack[4][32];
|
|
|
|
void ade_debug_ret(lua_State *L, lua_Debug *ar)
|
|
{
|
|
Assert(L != NULL);
|
|
Assert(ar != NULL);
|
|
lua_getstack(L, 1, ar);
|
|
lua_getinfo(L, "nSlu", ar);
|
|
memcpy(&Ade_debug_info, ar, sizeof(lua_Debug));
|
|
|
|
int n;
|
|
for (n = 0; n < 4; n++) {
|
|
debug_stack[n][0] = '\0';
|
|
}
|
|
|
|
for (n = 0; n < 4; n++) {
|
|
if (lua_getstack(L,n+1, ar) == 0)
|
|
break;
|
|
lua_getinfo(L,"n", ar);
|
|
if (ar->name == NULL)
|
|
break;
|
|
strcpy_s(debug_stack[n],ar->name);
|
|
}
|
|
}
|
|
|
|
//WMC - because the behavior of the return keyword
|
|
//was changed, I now have to use this in hooks.
|
|
static int ade_return_hack(lua_State *L)
|
|
{
|
|
int i = 0;
|
|
int num = lua_gettop(L);
|
|
for(i = 0; i < num; i++)
|
|
{
|
|
lua_pushvalue(L, i+1);
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
static void *vm_lua_alloc(void*, void *ptr, size_t, size_t nsize) {
|
|
if (nsize == 0)
|
|
{
|
|
vm_free(ptr);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return vm_realloc(ptr, nsize);
|
|
}
|
|
}
|
|
|
|
//Inits LUA
|
|
//Note that "libraries" must end with a {NULL, NULL}
|
|
//element
|
|
int script_state::CreateLuaState()
|
|
{
|
|
mprintf(("LUA: Opening LUA state...\n"));
|
|
lua_State *L = lua_newstate(vm_lua_alloc, nullptr);
|
|
|
|
if(L == NULL)
|
|
{
|
|
Warning(LOCATION, "Could not initialize Lua");
|
|
return 0;
|
|
}
|
|
|
|
//*****INITIALIZE AUXILIARY LIBRARIES
|
|
mprintf(("LUA: Initializing base Lua libraries...\n"));
|
|
luaL_openlibs(L);
|
|
|
|
//*****DISABLE DANGEROUS COMMANDS
|
|
lua_pushstring(L, "os");
|
|
lua_rawget(L, LUA_GLOBALSINDEX);
|
|
int os_ldx = lua_gettop(L);
|
|
if(lua_istable(L, os_ldx))
|
|
{
|
|
lua_pushstring(L, "execute");
|
|
lua_pushnil(L);
|
|
lua_rawset(L, os_ldx);
|
|
lua_pushstring(L, "remove");
|
|
lua_pushnil(L);
|
|
lua_rawset(L, os_ldx);
|
|
lua_pushstring(L, "rename");
|
|
lua_pushnil(L);
|
|
lua_rawset(L, os_ldx);
|
|
}
|
|
lua_pop(L, 1); //os table
|
|
|
|
//*****SET DEBUG HOOKS
|
|
#ifndef NDEBUG
|
|
lua_sethook(L, ade_debug_ret, LUA_MASKRET, 0);
|
|
#endif
|
|
|
|
//*****INITIALIZE ADE
|
|
uint i;
|
|
mprintf(("LUA: Beginning ADE initialization\n"));
|
|
for(i = 0; i < ade_manager::getInstance()->getNumEntries(); i++)
|
|
{
|
|
//WMC - Do only toplevel table entries, doi
|
|
if(ade_manager::getInstance()->getEntry(i).ParentIdx == UINT_MAX) //WMC - oh hey, we're done with the meaty point in < 10 lines.
|
|
ade_manager::getInstance()->getEntry(i).SetTable(L, LUA_GLOBALSINDEX, LUA_GLOBALSINDEX); //Oh the miracles of OOP.
|
|
}
|
|
|
|
//*****INITIALIZE RETURN HACK FUNCTION
|
|
lua_pushstring(L, "ade_return_hack");
|
|
lua_pushboolean(L, 0);
|
|
lua_pushcclosure(L, ade_return_hack, 2);
|
|
lua_setglobal(L, "ade_return_hack");
|
|
|
|
//*****INITIALIZE ENUMERATION CONSTANTS
|
|
mprintf(("ADE: Initializing enumeration constants...\n"));
|
|
enum_h eh;
|
|
for(i = 0; i < Num_enumerations; i++)
|
|
{
|
|
eh.index = Enumerations[i].def;
|
|
eh.is_constant = true;
|
|
|
|
ade_set_args(L, "o", l_Enum.Set(eh));
|
|
lua_setglobal(L, Enumerations[i].name);
|
|
}
|
|
|
|
//*****ASSIGN LUA SESSION
|
|
mprintf(("ADE: Assigning Lua session...\n"));
|
|
SetLuaSession(L);
|
|
|
|
// (void)l_BitOps.GetName();
|
|
|
|
return 1;
|
|
}
|
|
|
|
void script_state::EndLuaFrame()
|
|
{
|
|
scripting::api::graphics_on_frame();
|
|
}
|
|
|
|
void ade_output_toc(FILE *fp, ade_table_entry *ate)
|
|
{
|
|
Assert(fp != NULL);
|
|
Assert(ate != NULL);
|
|
|
|
//WMC - sanity checking
|
|
if(ate->Name == NULL && ate->ShortName == NULL) {
|
|
Warning(LOCATION, "Found ade_table_entry with no name or shortname");
|
|
return;
|
|
}
|
|
|
|
fputs("<dd>", fp);
|
|
|
|
if(ate->Name == NULL)
|
|
{
|
|
fprintf(fp, "<a href=\"#%s\">%s", ate->ShortName, ate->ShortName);
|
|
}
|
|
else
|
|
{
|
|
fprintf(fp, "<a href=\"#%s\">%s", ate->Name, ate->Name);
|
|
if(ate->ShortName)
|
|
fprintf(fp, " (%s)", ate->ShortName);
|
|
}
|
|
fputs("</a>", fp);
|
|
|
|
if(ate->Description)
|
|
fprintf(fp, " - %s\n", ate->Description);
|
|
|
|
fputs("</dd>\n", fp);
|
|
}
|
|
|
|
static bool sort_table_entries(const ade_table_entry* left, const ade_table_entry* right) {
|
|
const char* leftCmp = left->Name != nullptr ? left->Name : left->ShortName;
|
|
const char* rightCmp = right->Name != nullptr ? right->Name : left->ShortName;
|
|
|
|
if (leftCmp == nullptr) {
|
|
return false;
|
|
}
|
|
if (rightCmp == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
SCP_string leftStr(leftCmp);
|
|
std::transform(std::begin(leftStr), std::end(leftStr), std::begin(leftStr), ::tolower);
|
|
|
|
SCP_string rightStr(rightCmp);
|
|
std::transform(std::begin(rightStr), std::end(rightStr), std::begin(rightStr), ::tolower);
|
|
|
|
return leftStr < rightStr;
|
|
}
|
|
|
|
static bool sort_doc_entries(const ade_table_entry* left, const ade_table_entry* right) {
|
|
if (left->Instanced == right->Instanced) {
|
|
// Same type -> compare as normal
|
|
return sort_table_entries(left, right);
|
|
}
|
|
if (left->Instanced) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void script_state::OutputLuaMeta(FILE *fp)
|
|
{
|
|
uint i;
|
|
ade_table_entry *ate;
|
|
fputs("<dl>\n", fp);
|
|
|
|
SCP_vector<ade_table_entry*> table_entries;
|
|
|
|
//***TOC: Libraries
|
|
fputs("<dt><b>Libraries</b></dt>\n", fp);
|
|
for(i = 0; i < ade_manager::getInstance()->getNumEntries(); i++)
|
|
{
|
|
ate = &ade_manager::getInstance()->getEntry(i);
|
|
if(ate->ParentIdx == UINT_MAX && ate->Type == 'o' && ate->Instanced) {
|
|
table_entries.push_back(ate);
|
|
}
|
|
}
|
|
std::sort(std::begin(table_entries), std::end(table_entries), sort_table_entries);
|
|
for (auto entry : table_entries) {
|
|
ade_output_toc(fp, entry);
|
|
}
|
|
table_entries.clear();
|
|
|
|
//***TOC: Objects
|
|
fputs("<dt><b>Types</b></dt>\n", fp);
|
|
for(i = 0; i < ade_manager::getInstance()->getNumEntries(); i++)
|
|
{
|
|
ate = &ade_manager::getInstance()->getEntry(i);
|
|
if(ate->ParentIdx == UINT_MAX && ate->Type == 'o' && !ate->Instanced) {
|
|
table_entries.push_back(ate);
|
|
}
|
|
}
|
|
std::sort(std::begin(table_entries), std::end(table_entries), sort_table_entries);
|
|
for (auto entry : table_entries) {
|
|
ade_output_toc(fp, entry);
|
|
}
|
|
table_entries.clear();
|
|
|
|
//***TOC: Enumerations
|
|
fputs("<dt><b><a href=\"#Enumerations\">Enumerations</a></b></dt>", fp);
|
|
|
|
//***End TOC
|
|
fputs("</dl><br/><br/>", fp);
|
|
|
|
//***Everything
|
|
fputs("<dl>\n", fp);
|
|
for(i = 0; i < ade_manager::getInstance()->getNumEntries(); i++)
|
|
{
|
|
ate = &ade_manager::getInstance()->getEntry(i);
|
|
if(ate->ParentIdx == UINT_MAX)
|
|
table_entries.push_back(ate);
|
|
}
|
|
|
|
std::sort(std::begin(table_entries), std::end(table_entries), sort_doc_entries);
|
|
for (auto entry : table_entries) {
|
|
entry->OutputMeta(fp);
|
|
}
|
|
table_entries.clear();
|
|
|
|
//***Enumerations
|
|
fprintf(fp, "<dt id=\"Enumerations\"><h2>Enumerations</h2></dt>");
|
|
for(i = 0; i < Num_enumerations; i++)
|
|
{
|
|
//WMC - This is in case we ever want to add descriptions to enums.
|
|
//fprintf(fp, "<dd><dl><dt><b>%s</b></dt><dd>%s</dd></dl></dd>", Enumerations[i].name, Enumerations[i].desc);
|
|
|
|
//WMC - Otherwise, just use this.
|
|
fprintf(fp, "<dd><b>%s</b></dd>", Enumerations[i].name);
|
|
}
|
|
fputs("</dl>\n", fp);
|
|
|
|
//***End LUA
|
|
fputs("</dl>\n", fp);
|
|
}
|