Files
fs2open.github.com/code/scripting/api/libs/base.cpp
T
asarium 2eea0a6eb1 Add lua functions for accessing the current engine language
This can be used by scripts to implement language specific behavior.
2018-02-18 17:12:17 +01:00

371 lines
12 KiB
C++

//
//
#include <freespace.h>
#include <gamesequence/gamesequence.h>
#include <network/multi.h>
#include <playerman/player.h>
#include <parse/parselo.h>
#include <globalincs/version.h>
#include "base.h"
#include "scripting/api/objs/vecmath.h"
#include "scripting/api/objs/gamestate.h"
#include "scripting/api/objs/player.h"
#include "scripting/api/objs/enums.h"
#include "scripting/api/objs/control_info.h"
#include "scripting/api/objs/gameevent.h"
namespace scripting {
namespace api {
//**********LIBRARY: Base
ADE_LIB(l_Base, "Base", "ba", "Base FreeSpace 2 functions");
ADE_FUNC(print, l_Base, "string Message", "Prints a string", NULL, NULL)
{
mprintf(("%s", lua_tostring(L, -1)));
return ADE_RETURN_NIL;
}
ADE_FUNC(warning, l_Base, "string Message", "Displays a FreeSpace warning (debug build-only) message with the string provided", NULL, NULL)
{
Warning(LOCATION, "%s", lua_tostring(L, -1));
return ADE_RETURN_NIL;
}
ADE_FUNC(error, l_Base, "string Message", "Displays a FreeSpace error message with the string provided", NULL, NULL)
{
Error(LOCATION, "%s", lua_tostring(L, -1));
return ADE_RETURN_NIL;
}
ADE_FUNC(createOrientation, l_Base, "[p/r1c1, b/r1c2, h/r1c3, r2c1, r2c2, r2c3, r3c1, r3c2, r3c3]", "Given 0, 3, or 9 arguments, creates an orientation object with that orientation.", "orientation", "New orientation object, or null orientation on failure")
{
matrix m;
int numargs = ade_get_args(L, "|fffffffff", &m.a1d[0], &m.a1d[1], &m.a1d[2], &m.a1d[3], &m.a1d[4], &m.a1d[5], &m.a1d[6], &m.a1d[7], &m.a1d[8]);
if(!numargs)
{
return ade_set_args(L, "o", l_Matrix.Set( matrix_h(&vmd_identity_matrix) ));
}
else if(numargs == 3)
{
angles a = {m.a1d[0], m.a1d[1], m.a1d[2]};
return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&a)));
}
else if(numargs == 9)
{
return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&m)));
}
return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
}
ADE_FUNC(createVector, l_Base, "[x, y, z]", "Creates a vector object", "vector", "Vector object")
{
vec3d v3 = vmd_zero_vector;
ade_get_args(L, "|fff", &v3.xyz.x, &v3.xyz.y, &v3.xyz.z);
return ade_set_args(L, "o", l_Vector.Set(v3));
}
ADE_FUNC(getFrametimeOverall, l_Base, NULL, "The overall frame time in seconds since the engine has started", "number", "Overall time (seconds)")
{
return ade_set_args(L, "x", game_get_overall_frametime());
}
ADE_FUNC(getFrametime, l_Base, "[Do not adjust for time compression (Boolean)]", "Gets how long this frame is calculated to take. Use it to for animations, physics, etc to make incremental changes.", "number", "Frame time (seconds)")
{
bool b=false;
ade_get_args(L, "|b", &b);
return ade_set_args(L, "f", b ? flRealframetime : flFrametime);
}
ADE_FUNC(getCurrentGameState, l_Base, "[Depth (number)]", "Gets current FreeSpace state; if a depth is specified, the state at that depth is returned. (IE at the in-game options game, a depth of 1 would give you the game state, while the function defaults to 0, which would be the options screen.", "gamestate", "Current game state at specified depth, or invalid handle if no game state is active yet")
{
int depth = 0;
ade_get_args(L, "|i", &depth);
if(depth > gameseq_get_depth())
return ade_set_args(L, "o", l_GameState.Set(gamestate_h()));
return ade_set_args(L, "o", l_GameState.Set(gamestate_h(gameseq_get_state(depth))));
}
ADE_FUNC(getCurrentMPStatus, l_Base, "NIL", "Gets this computers current MP status", "string", "Current MP status" )
{
if ( MULTIPLAYER_MASTER )
return ade_set_args(L, "s", "MULTIPLAYER_MASTER");
if ( MULTIPLAYER_HOST )
return ade_set_args(L, "s", "MULTIPLAYER_HOST");
if ( MULTIPLAYER_CLIENT )
return ade_set_args(L, "s", "MULTIPLAYER_CLIENT");
if ( MULTIPLAYER_STANDALONE )
return ade_set_args(L, "s", "MULTIPLAYER_STANDALONE");
return ade_set_args(L, "s", "SINGLEPLAYER");
}
ADE_FUNC(getCurrentPlayer, l_Base, NULL, "Gets a handle of the currently used player.<br><b>Note:</b> If there is no current player then the first player will be returned, check the game state to make sure you have a valid player handle.", "player", "Player handle")
{
return ade_set_args(L, "o", l_Player.Set(Player_num));
}
ADE_FUNC(setControlMode, l_Base, "NIL or enumeration LE_*_CONTROL", "Sets the current control mode for the game.", "string", "Current control mode")
{
enum_h *e = NULL;
if (!(ade_get_args(L, "|o", l_Enum.GetPtr(&e)))) {
if (lua_game_control & LGC_NORMAL)
return ade_set_args(L, "s", "NORMAL");
else if (lua_game_control & LGC_STEERING)
return ade_set_args(L, "s", "STEERING");
else if (lua_game_control & LGC_FULL)
return ade_set_args(L, "s", "FULL");
else
return ade_set_error(L, "s", "");
}
if (!e) {
return ade_set_error(L, "s", "");
}
switch (e->index) {
case LE_NORMAL_CONTROLS:
lua_game_control |= LGC_NORMAL;
lua_game_control &= ~(LGC_STEERING|LGC_FULL);
return ade_set_args(L, "s", "NORMAL CONTROLS");
case LE_LUA_STEERING_CONTROLS:
lua_game_control |= LGC_STEERING;
lua_game_control &= ~(LGC_NORMAL|LGC_FULL);
return ade_set_args(L, "s", "LUA STEERING CONTROLS");
case LE_LUA_FULL_CONTROLS:
lua_game_control |= LGC_FULL;
lua_game_control &= ~(LGC_STEERING|LGC_NORMAL);
return ade_set_args(L, "s", "LUA FULL CONTROLS");
default:
return ade_set_error(L, "s", "");
}
}
ADE_FUNC(setButtonControlMode, l_Base, "NIL or enumeration LE_*_BUTTON_CONTROL", "Sets the current control mode for the game.", "string", "Current control mode")
{
enum_h *e = NULL;
if (!(ade_get_args(L, "|o", l_Enum.GetPtr(&e)))) {
if (lua_game_control & LGC_B_NORMAL)
return ade_set_args(L, "s", "NORMAL");
else if (lua_game_control & LGC_B_OVERRIDE)
return ade_set_args(L, "s", "OVERRIDE");
else if (lua_game_control & LGC_B_ADDITIVE)
return ade_set_args(L, "s", "ADDITIVE");
else
return ade_set_error(L, "s", "");
}
if (!e) {
return ade_set_error(L, "s", "");
}
switch (e->index) {
case LE_NORMAL_BUTTON_CONTROLS:
lua_game_control |= LGC_B_NORMAL;
lua_game_control &= ~(LGC_B_ADDITIVE|LGC_B_OVERRIDE);
return ade_set_args(L, "s", "NORMAL BUTTON CONTROL");
case LE_LUA_ADDITIVE_BUTTON_CONTROL:
lua_game_control |= LGC_B_ADDITIVE;
lua_game_control &= ~(LGC_B_NORMAL|LGC_B_OVERRIDE);
return ade_set_args(L, "s", "LUA OVERRIDE BUTTON CONTROL");
case LE_LUA_OVERRIDE_BUTTON_CONTROL:
lua_game_control |= LGC_B_OVERRIDE;
lua_game_control &= ~(LGC_B_ADDITIVE|LGC_B_NORMAL);
return ade_set_args(L, "s", "LUA ADDITIVE BUTTON CONTROL");
default:
return ade_set_error(L, "s", "");
}
}
ADE_FUNC(getControlInfo, l_Base, NULL, "Gets the control info handle.", "control info", "control info handle")
{
return ade_set_args(L, "o", l_Control_Info.Set(1));
}
ADE_FUNC(setTips, l_Base, "True or false", "Sets whether to display tips of the day the next time the current pilot enters the mainhall.", NULL, NULL)
{
if (Player == NULL)
return ADE_RETURN_NIL;
bool tips = false;
ade_get_args(L, "b", &tips);
if (tips)
Player->tips = 1;
else
Player->tips = 0;
return ADE_RETURN_NIL;
}
ADE_FUNC(getGameDifficulty, l_Base, NULL, "Returns the difficulty level from 1-5, 1 being the lowest, (Very Easy) and 5 being the highest (Insane)", "integer", "Difficulty level as integer")
{
return ade_set_args(L, "i", Game_skill_level+1);
}
ADE_FUNC(postGameEvent, l_Base, "gameevent Event", "Sets current game event. Note that you can crash FreeSpace 2 by posting an event at an improper time, so test extensively if you use it.", "boolean", "True if event was posted, false if passed event was invalid")
{
gameevent_h *gh = NULL;
if(!ade_get_args(L, "o", l_GameEvent.GetPtr(&gh)))
return ade_set_error(L, "b", false);
if(!gh->IsValid())
return ade_set_error(L, "b", false);
if (Om_tracker_flag)
Multi_options_g.protocol = NET_TCP;
psnet_use_protocol(Multi_options_g.protocol);
gameseq_post_event(gh->Get());
return ADE_RETURN_TRUE;
}
ADE_FUNC(XSTR,
l_Base,
"string text, number id",
"Gets the translated version of text with the given id. "
"The uses the tstrings table for performing the translation. Passing -1 as the id will always return the given text.",
"string",
"The translated text") {
const char* text = nullptr;
int id = -1;
if (!ade_get_args(L, "si", &text, &id)) {
return ADE_RETURN_NIL;
}
SCP_string xstr;
sprintf(xstr, "XSTR(\"%s\", %d)", text, id);
SCP_string translated;
lcl_ext_localize(xstr, translated);
return ade_set_args(L, "s", translated.c_str());
}
ADE_FUNC(inMissionEditor, l_Base, nullptr, "Determine if the current script is running in the mission editor (e.g. FRED2). This should be used to control which code paths will be executed even if running in the editor.", "boolean", "true when we are in the mission editor, false otherwise") {
return ade_set_args(L, "b", Fred_running != 0);
}
ADE_FUNC(isEngineVersionAtLeast,
l_Base,
"number major, number minor, number build[, number revision = 0]",
"Checks if the current version of the engine is at least the specified version. This can be used to check if a feature introduced in a later version of the engine is available.",
"boolean",
"true if the version is at least the specified version. false otherwise.") {
int major = 0;
int minor = 0;
int build = 0;
int revision = 0;
if (!ade_get_args(L, "iii|i", &major, &minor, &build, &revision)) {
return ade_set_error(L, "b", false);
}
auto version = gameversion::version(major, minor, build, revision);
return ade_set_args(L, "b", gameversion::check_at_least(version));
}
ADE_FUNC(getCurrentLanguage,
l_Base,
nullptr,
"Determines the language that is being used by the engine. This returns the full name of the language (e.g. \"English\").",
"string",
"The current game language") {
return ade_set_args(L, "s", Lcl_languages[Lcl_current_lang].lang_name);
}
ADE_FUNC(getCurrentLanguageExtension,
l_Base,
nullptr,
"Determines the file extension of the language that is being used by the engine. "
"This returns a short code for the current language that can be used for creating language specific file names (e.g. \"gr\" when the current language is German). "
"This will return an empty string for the default language.",
"string",
"The current game language") {
return ade_set_args(L, "s", Lcl_languages[Lcl_current_lang].lang_ext);
}
//**********SUBLIBRARY: Base/Events
ADE_LIB_DERIV(l_Base_Events, "GameEvents", NULL, "Freespace 2 game events", l_Base);
ADE_INDEXER(l_Base_Events, "number Index/string Name", "Array of game events", "gameevent", "Game event, or invalid gameevent handle if index is invalid")
{
char *name;
if(!ade_get_args(L, "*s", &name))
return ade_set_error(L, "o", l_GameEvent.Set(gameevent_h()));
int idx = gameseq_get_event_idx(name);
if(idx < 0)
{
idx = atoi(name);
//Lua-->FS2
idx--;
if(idx < 0 || idx >= Num_gs_event_text)
return ade_set_error(L, "o", l_GameEvent.Set(gameevent_h()));
}
return ade_set_args(L, "o", l_GameEvent.Set(gameevent_h(idx)));
}
ADE_FUNC(__len, l_Base_Events, NULL, "Number of events", "number", "Number of events")
{
return ade_set_args(L, "i", Num_gs_event_text);
}
//**********SUBLIBRARY: Base/States
ADE_LIB_DERIV(l_Base_States, "GameStates", NULL, "Freespace 2 states", l_Base);
ADE_INDEXER(l_Base_States, "number Index/string Name", "Array of game states", "gamestate", "Game state, or invalid gamestate handle if index is invalid")
{
char *name;
if(!ade_get_args(L, "*s", &name))
return ade_set_error(L, "o", l_GameState.Set(gamestate_h()));
int idx = gameseq_get_state_idx(name);
if(idx < 0)
{
idx = atoi(name);
//Lua-->FS2
idx--;
if(idx < 0 || idx >= Num_gs_state_text)
return ade_set_error(L, "o", l_GameState.Set(gamestate_h()));
}
return ade_set_args(L, "o", l_GameState.Set(gamestate_h(idx)));
}
ADE_FUNC(__len, l_Base_States, NULL, "Number of states", "number", "Number of states")
{
return ade_set_args(L, "i", Num_gs_state_text);
}
}
}