diff --git a/code/scripting/api/libs/async.cpp b/code/scripting/api/libs/async.cpp
index e7bf471dfa6..70fe0d2a913 100644
--- a/code/scripting/api/libs/async.cpp
+++ b/code/scripting/api/libs/async.cpp
@@ -396,8 +396,8 @@ ADE_FUNC(captureGameState,
ADE_FUNC(createLuaState,
l_Async_Context,
- "function() => enumeration",
- "Creates an execution state by storing the passed function and calling that when the state is required.",
+ "function() => enumeration /* CONTEXT_* */",
+ "Creates an execution state by storing the passed function and calling that when the state is required. The function must return a CONTEXT_* enumeration.",
"execution_context",
"The execution context or invalid handle on error")
{
diff --git a/code/scripting/api/libs/audio.cpp b/code/scripting/api/libs/audio.cpp
index 7cfe5749385..b40a63a7f47 100644
--- a/code/scripting/api/libs/audio.cpp
+++ b/code/scripting/api/libs/audio.cpp
@@ -341,7 +341,7 @@ ADE_FUNC(pauseMusic,
ADE_FUNC(openAudioStream,
l_Audio,
- "string fileName, enumeration stream_type /* AUDIOSTREAM_* values */",
+ "string fileName, enumeration stream_type /* AUDIOSTREAM_* */",
"Opens an audio stream of the specified file and type. An audio stream is meant for more long time sounds since "
"they are streamed from the file instead of loaded in its entirety.",
"audio_stream",
diff --git a/code/scripting/api/libs/base.cpp b/code/scripting/api/libs/base.cpp
index 75f8b735727..50d9d91dc83 100644
--- a/code/scripting/api/libs/base.cpp
+++ b/code/scripting/api/libs/base.cpp
@@ -396,8 +396,8 @@ ADE_FUNC(savePlayer, l_Base, "player plr", "Saves the specified player.", "boole
ADE_FUNC(setControlMode,
l_Base,
- "nil|enumeration mode /* LE_*_CONTROL */",
- "Sets the current control mode for the game.",
+ "nil|enumeration mode /* FLIGHT_CONTROL_* */",
+ "Sets the current flight control mode for the game.",
"string",
"Current control mode")
{
@@ -437,8 +437,8 @@ ADE_FUNC(setControlMode,
ADE_FUNC(setButtonControlMode,
l_Base,
- "nil|enumeration mode /* LE_*_BUTTON_CONTROL */",
- "Sets the current control mode for the game.",
+ "nil|enumeration mode /* BUTTON_CONTROL_* */",
+ "Sets the current button control mode for the game.",
"string",
"Current control mode")
{
diff --git a/code/scripting/api/libs/controls.cpp b/code/scripting/api/libs/controls.cpp
index 36e0b24d8bd..630b14b1e5b 100644
--- a/code/scripting/api/libs/controls.cpp
+++ b/code/scripting/api/libs/controls.cpp
@@ -75,9 +75,8 @@ ADE_FUNC(getMouseY, l_Mouse, nullptr, "Gets Mouse Y pos", "number", "Mouse y pos
ADE_FUNC(isMouseButtonDown,
l_Mouse,
- "enumeration buttonCheck1 /* MOUSE_*_BUTTON */, [ enumeration buttonCheck2 /* MOUSE_*_BUTTON */, enumeration "
- "buttonCheck3 /* MOUSE_*_BUTTON */ ]",
- "Returns whether the specified mouse buttons are up or down",
+ "enumeration buttonCheck1 /* MOUSE_* */, [enumeration buttonCheck2 /* MOUSE_* */, enumeration buttonCheck3 /* MOUSE_* */]",
+ "Returns whether the specified MOUSE_* buttons are up or down",
"boolean",
"Whether specified mouse buttons are down, or false if mouse is not initialized yet")
{
@@ -115,8 +114,8 @@ ADE_FUNC(isMouseButtonDown,
ADE_FUNC(mouseButtonDownCount,
l_Mouse,
- "enumeration buttonCheck /* any one of MOUSE_LEFT_BUTTON, MOUSE_RIGHT_BUTTON, MOUSE_MIDDLE_BUTTON, MOUSE_X1_BUTTON, MOUSE_X2_BUTTON */, [ boolean reset_count ]",
- "Returns the pressed count of the specified button. The count is then reset, unless reset_count (which defaults to true) is false.",
+ "enumeration buttonCheck /* MOUSE_* */, [boolean reset_count]",
+ "Returns the pressed count of the specified MOUSE_* button. The count is then reset, unless reset_count (which defaults to true) is false.",
"number",
"The number of frames this button has been pressed, or -1 if the mouse has not been initialized")
{
@@ -315,7 +314,7 @@ ADE_FUNC(AxisInverted, l_Mouse, "number cid, number axis, boolean inverted", "Ge
return ADE_RETURN_FALSE;
}
-ADE_VIRTVAR(FlightCursorMode, l_Mouse, "enumeration FlightMode", "Flight Mode; uses LE_FLIGHTMODE_* enumerations.", "enumeration", "enumeration flight mode")
+ADE_VIRTVAR(FlightCursorMode, l_Mouse, "enumeration /* FLIGHTMODE_* */", "Flight Mode; uses FLIGHTMODE_* enumerations.", "enumeration", "Current flight cursor mode as a FLIGHTMODE_* enumeration")
{
enum_h flightmode_arg;
diff --git a/code/scripting/api/libs/graphics.cpp b/code/scripting/api/libs/graphics.cpp
index 3dd751fcdc1..3222a5624c7 100644
--- a/code/scripting/api/libs/graphics.cpp
+++ b/code/scripting/api/libs/graphics.cpp
@@ -278,7 +278,7 @@ ADE_VIRTVAR(CurrentRenderTarget, l_Graphics, "texture", "Current rendering targe
}
}
-ADE_VIRTVAR(CurrentResizeMode, l_Graphics, "enumeration ResizeMode", "Current resize mode; uses GR_RESIZE_* enumerations. This resize mode will be used by the gr.* drawing methods.", "enumeration", nullptr)
+ADE_VIRTVAR(CurrentResizeMode, l_Graphics, "enumeration /* GR_RESIZE_* */", "Current resize mode; uses GR_RESIZE_* enumerations. This resize mode will be used by the gr.* drawing methods.", "enumeration", nullptr)
{
enum_h resize_arg;
@@ -1510,7 +1510,7 @@ ADE_FUNC(drawString, l_Graphics, "string|boolean Message, [number X1, number Y1,
return drawString_sub(L, false);
}
-ADE_FUNC(drawStringResized, l_Graphics, "enumeration ResizeMode, string|boolean Message, [number X1, number Y1, number X2, number Y2]",
+ADE_FUNC(drawStringResized, l_Graphics, "enumeration ResizeMode /* GR_RESIZE_* */, string|boolean Message, [number X1, number Y1, number X2, number Y2]",
"Draws a string, scaled according to the GR_RESIZE_* parameter. Use x1/y1 to control position, x2/y2 to limit textbox size."
"Text will automatically move onto new lines, if x2/y2 is specified, however the line spacing will probably not be correct."
"Additionally, calling drawString with only a string argument will automatically"
@@ -2046,7 +2046,7 @@ ADE_FUNC(loadModel, l_Graphics, "string Filename", "Loads the model - will not s
return ade_set_args(L, "o", l_Model.Set(model_h(model_num)));
}
-ADE_FUNC(hasViewmode, l_Graphics, "enumeration", "Specifies if the current viemode has the specified flag, see VM_* enumeration", "boolean", "true if flag is present, false otherwise")
+ADE_FUNC(hasViewmode, l_Graphics, "enumeration /* VM_* */", "Specifies if the current viewmode has the specified flag.", "boolean", "true if flag is present, false otherwise")
{
enum_h *type = NULL;
@@ -2145,7 +2145,7 @@ ADE_FUNC(hasViewmode, l_Graphics, "enumeration", "Specifies if the current viemo
return ade_set_args(L, "b", (Viewer_mode & bit) != 0);
}
-ADE_FUNC(setClip, l_Graphics, "number x, number y, number width, number height, [enumeration ResizeMode]", "Sets the clipping region to the specified rectangle. Most drawing functions are able to handle the offset.", "boolean", "true if successful, false otherwise")
+ADE_FUNC(setClip, l_Graphics, "number x, number y, number width, number height, [enumeration /* GR_RESIZE_* */]", "Sets the clipping region to the specified rectangle using GR_RESIZE_* enumerations. Most drawing functions are able to handle the offset.", "boolean", "true if successful, false otherwise")
{
int x, y, width, height;
enum_h resize_arg;
diff --git a/code/scripting/api/libs/hud.cpp b/code/scripting/api/libs/hud.cpp
index 189a78a7174..ef6b3e6d7a8 100644
--- a/code/scripting/api/libs/hud.cpp
+++ b/code/scripting/api/libs/hud.cpp
@@ -260,7 +260,7 @@ ADE_FUNC(getHUDGaugeHandle, l_HUD, "string Name", "Returns a handle to a specifi
return ade_set_args(L, "o", l_HudGauge.Set(gauge));
}
-ADE_FUNC(flashTargetBox, l_HUD, "enumeration section, [number duration_in_milliseconds]", "Flashes a section of the target box with a default duration of " SCP_TOKEN_TO_STR(TBOX_FLASH_DURATION) " milliseconds", nullptr, nullptr)
+ADE_FUNC(flashTargetBox, l_HUD, "enumeration section /* TBOX_* */, [number duration_in_milliseconds]", "Flashes a section of the target box with a default duration of " SCP_TOKEN_TO_STR(TBOX_FLASH_DURATION) " milliseconds", nullptr, nullptr)
{
enum_h section;
int num_args, duration;
diff --git a/code/scripting/api/libs/mission.cpp b/code/scripting/api/libs/mission.cpp
index 395c254fda6..7ca47d0af47 100644
--- a/code/scripting/api/libs/mission.cpp
+++ b/code/scripting/api/libs/mission.cpp
@@ -1018,9 +1018,9 @@ int sendMessage_sub(lua_State* L, const void* sender, int messageSource, int mes
ADE_FUNC(sendMessage,
l_Mission,
- "string|ship sender, message message, [number delay=0.0, enumeration priority = MESSAGE_PRIORITY_NORMAL, boolean "
+ "string|ship sender, message message, [number delay=0.0, enumeration priority = MESSAGE_PRIORITY_NORMAL /* MESSAGE_PRIORITY_* */, boolean "
"fromCommand = false]",
- "Sends a message from the given source or ship with the given priority, or optionally sends it from the "
+ "Sends a message from the given source or ship with the given MESSAGE_PRIORITY_* priority, or optionally sends it from the "
"mission's command source.
"
"If delay is specified, the message will be delayed by the specified time in seconds.
"
"If sender is nil the message will not have a sender. If sender is a ship object the message will be sent from the ship; "
@@ -1229,10 +1229,10 @@ int getBuiltinMessageType(const enum_h* enumValue)
ADE_FUNC(sendBuiltinMessage,
l_Mission,
- "ship sender, ship subject, enumeration|string type_or_type_name",
+ "ship sender, ship subject, enumeration|string type_or_type_name /* BUILTIN_MESSAGE_* */",
"Sends one of the builtin messages from the given source or ship, taking the message subject into account."
"The subject can be nil or it can be the target of the message like a response to a destroy order."
- "The type must be one of the BUILTIN_MESSAGE enumerations or a string matching a custom built-in message defined in messages.tbl.",
+ "The type must be one of the BUILTIN_MESSAGE_* enumerations or a string matching a custom built-in message defined in messages.tbl.",
"boolean",
"true if successful, false otherwise")
{
@@ -1286,9 +1286,9 @@ ADE_FUNC(sendBuiltinMessage,
ADE_FUNC(addMessageToScrollback,
l_Mission,
- "string message, [team|enumeration source=HUD_SOURCE_COMPUTER]",
+ "string message, [team|enumeration source = SCROLLBACK_SOURCE_COMPUTER /* SCROLLBACK_* */]",
"Adds a string to the message log scrollback without sending it as a message first. Source should be either the team handle "
- "or one of the SCROLLBACK_SOURCE enumerations.",
+ "or one of the SCROLLBACK_* enumerations.",
"boolean",
"true if successful, false otherwise")
{
@@ -1857,8 +1857,8 @@ ADE_FUNC(getMissionFilename, l_Mission, NULL, "Gets mission filename", "string",
ADE_FUNC(startMission,
l_Mission,
- "string|enumeration mission /* Filename or MISSION_* enumeration */, [boolean Briefing = true]",
- "Starts the defined mission",
+ "string|enumeration mission /* MISSION_* */, [boolean Briefing = true]",
+ "Starts the defined mission. Pass a filename string or a MISSION_* enumeration.",
"boolean",
"True, or false if the function fails")
{
@@ -2631,7 +2631,7 @@ ADE_FUNC(hasDebriefing,
return ade_set_args(L, "b", !(The_mission.flags[Mission::Mission_Flags::Toggle_debriefing]));
}
-ADE_FUNC(getMusicScore, l_Mission, "enumeration score", "Returns the music.tbl entry name for the specified mission music score", "string", "The name, or nil if the score is invalid")
+ADE_FUNC(getMusicScore, l_Mission, "enumeration score /* SCORE_* */", "Returns the music.tbl entry name for the specified mission music score", "string", "The name, or nil if the score is invalid")
{
enum_h score;
if (!ade_get_args(L, "o", l_Enum.Get(&score)))
@@ -2652,7 +2652,7 @@ ADE_FUNC(getMusicScore, l_Mission, "enumeration score", "Returns the music.tbl e
return ade_set_args(L, "s", name);
}
-ADE_FUNC(setMusicScore, l_Mission, "enumeration score, string name", "Sets the music.tbl entry for the specified mission music score", nullptr, nullptr)
+ADE_FUNC(setMusicScore, l_Mission, "enumeration score /* SCORE_* */, string name", "Sets the music.tbl entry for the specified mission music score", nullptr, nullptr)
{
enum_h score;
const char *name;
diff --git a/code/scripting/api/libs/testing.cpp b/code/scripting/api/libs/testing.cpp
index 37c926006ca..e44d712bba2 100644
--- a/code/scripting/api/libs/testing.cpp
+++ b/code/scripting/api/libs/testing.cpp
@@ -33,7 +33,7 @@ ADE_LIB(l_Testing, "Testing", "ts", "Experimental or testing stuff");
ADE_FUNC(openAudioStreamMem,
l_Testing,
- "string snddata, enumeration stream_type /* AUDIOSTREAM_* values */",
+ "string snddata, enumeration stream_type /* AUDIOSTREAM_* */",
"Opens an audio stream of the specified in-memory file contents and type.",
"audio_stream",
"A handle to the opened stream or invalid on error")
diff --git a/code/scripting/api/libs/ui.cpp b/code/scripting/api/libs/ui.cpp
index 080468d62f4..5f97d18499b 100644
--- a/code/scripting/api/libs/ui.cpp
+++ b/code/scripting/api/libs/ui.cpp
@@ -237,7 +237,7 @@ ADE_FUNC(playElementSound,
return ade_set_args(L, "b", scpui::SoundPlugin::instance()->PlayElementSound(el, event, state));
}
-ADE_FUNC(maybePlayCutscene, l_UserInterface, "enumeration MovieType, boolean RestartMusic, number ScoreIndex", "Plays a cutscene, if one exists, for the appropriate state transition. If RestartMusic is true, then the music score at ScoreIndex will be started after the cutscene plays.", nullptr, "Returns nothing")
+ADE_FUNC(maybePlayCutscene, l_UserInterface, "enumeration MovieType /* MOVIE_* */, boolean RestartMusic, number ScoreIndex", "Plays a cutscene, if one exists, for the appropriate state transition. If RestartMusic is true, then the music score at ScoreIndex will be started after the cutscene plays.", nullptr, "Returns nothing")
{
enum_h movie_type;
bool restart_music = false;
@@ -821,9 +821,9 @@ ADE_FUNC(skipTraining,
ADE_FUNC(commitToMission,
l_UserInterface_Brief,
nullptr,
- "Commits to the current mission with current loadout data, and starts the mission. Returns one of the COMMIT_ enums to indicate any errors.",
+ "Commits to the current mission with current loadout data, and starts the mission.",
"enumeration",
- "the error value")
+ "A COMMIT_* enumeration indicating any errors")
{
commit_pressed_status rc;
@@ -3447,8 +3447,8 @@ ADE_FUNC(setName,
ADE_FUNC(setGameType,
l_UserInterface_MultiStartGame,
- "enumeration type=MULTI_GAME_TYPE_OPEN, [string | number password_or_rank_index]",
- "Sets the game's type and, optionally, the password or rank index.",
+ "enumeration type = MULTI_GAME_TYPE_OPEN /* MULTI_GAME_TYPE_* */, [string | number password_or_rank_index]",
+ "Sets the game type and optionally the password or rank index.",
"boolean",
"True if successful, false otherwise")
{
diff --git a/code/scripting/api/objs/enums.cpp b/code/scripting/api/objs/enums.cpp
index 47ad9ce659c..92a80c52588 100644
--- a/code/scripting/api/objs/enums.cpp
+++ b/code/scripting/api/objs/enums.cpp
@@ -59,8 +59,11 @@ const lua_enum_def_list Enumerations[] = {
{"PARTICLE_SMOKE", LE_PARTICLE_SMOKE, true},
{"PARTICLE_SMOKE2", LE_PARTICLE_SMOKE2, true},
{"PARTICLE_PERSISTENT_BITMAP", LE_PARTICLE_PERSISTENT_BITMAP, true},
+ {"SEXPVAR_PERSIST_CAMPAIGN", LE_SEXPVAR_CAMPAIGN_PERSISTENT, true},
{"SEXPVAR_CAMPAIGN_PERSISTENT", LE_SEXPVAR_CAMPAIGN_PERSISTENT, true},
+ {"SEXPVAR_PERSIST_NONE", LE_SEXPVAR_NOT_PERSISTENT, true},
{"SEXPVAR_NOT_PERSISTENT", LE_SEXPVAR_NOT_PERSISTENT, true},
+ {"SEXPVAR_PERSIST_PLAYER", LE_SEXPVAR_PLAYER_PERSISTENT, true},
{"SEXPVAR_PLAYER_PERSISTENT", LE_SEXPVAR_PLAYER_PERSISTENT, true},
{"SEXPVAR_TYPE_NUMBER", LE_SEXPVAR_TYPE_NUMBER, true},
{"SEXPVAR_TYPE_STRING", LE_SEXPVAR_TYPE_STRING, true},
@@ -68,17 +71,24 @@ const lua_enum_def_list Enumerations[] = {
{"TEXTURE_DYNAMIC", LE_TEXTURE_DYNAMIC, true},
{"LOCK", LE_LOCK, true},
{"UNLOCK", LE_UNLOCK, true},
+ {"SHIELD_NONE", LE_NONE, true},
{"NONE", LE_NONE, true},
{"SHIELD_FRONT", LE_SHIELD_FRONT, true},
{"SHIELD_LEFT", LE_SHIELD_LEFT, true},
{"SHIELD_RIGHT", LE_SHIELD_RIGHT, true},
{"SHIELD_BACK", LE_SHIELD_BACK, true},
{"MISSION_REPEAT", LE_MISSION_REPEAT, true},
+ {"FLIGHT_CONTROL_NORMAL", LE_NORMAL_CONTROLS, true},
{"NORMAL_CONTROLS", LE_NORMAL_CONTROLS, true},
+ {"FLIGHT_CONTROL_LUA_STEERING", LE_LUA_STEERING_CONTROLS, true},
{"LUA_STEERING_CONTROLS", LE_LUA_STEERING_CONTROLS, true},
+ {"FLIGHT_CONTROL_LUA_FULL", LE_LUA_FULL_CONTROLS, true},
{"LUA_FULL_CONTROLS", LE_LUA_FULL_CONTROLS, true},
+ {"BUTTON_CONTROL_NORMAL", LE_NORMAL_BUTTON_CONTROLS, true},
{"NORMAL_BUTTON_CONTROLS", LE_NORMAL_BUTTON_CONTROLS, true},
+ {"BUTTON_CONTROL_LUA_ADDITIVE", LE_LUA_ADDITIVE_BUTTON_CONTROL, true},
{"LUA_ADDITIVE_BUTTON_CONTROL", LE_LUA_ADDITIVE_BUTTON_CONTROL, true},
+ {"BUTTON_CONTROL_LUA_OVERRIDE", LE_LUA_OVERRIDE_BUTTON_CONTROL, true},
{"LUA_OVERRIDE_BUTTON_CONTROL", LE_LUA_OVERRIDE_BUTTON_CONTROL, true},
{"VM_INTERNAL", LE_VM_INTERNAL, true},
{"VM_EXTERNAL", LE_VM_EXTERNAL, true},
@@ -148,10 +158,15 @@ const lua_enum_def_list Enumerations[] = {
{"SCORE_DEBRIEFING_AVERAGE", LE_SCORE_DEBRIEFING_AVERAGE, true},
{"SCORE_DEBRIEFING_FAILURE", LE_SCORE_DEBRIEFING_FAILURE, true},
{"SCORE_FICTION_VIEWER", LE_SCORE_FICTION_VIEWER, true},
+ {"SHIP_STATUS_INVALID", LE_INVALID, true},
{"INVALID", LE_INVALID, true},
+ {"SHIP_STATUS_NOT_YET_PRESENT", LE_NOT_YET_PRESENT, true},
{"NOT_YET_PRESENT", LE_NOT_YET_PRESENT, true},
+ {"SHIP_STATUS_PRESENT", LE_PRESENT, true},
{"PRESENT", LE_PRESENT, true},
+ {"SHIP_STATUS_DEATH_ROLL", LE_DEATH_ROLL, true},
{"DEATH_ROLL", LE_DEATH_ROLL, true},
+ {"SHIP_STATUS_EXITED", LE_EXITED, true},
{"EXITED", LE_EXITED, true},
{"DC_IS_HULL", LE_DC_IS_HULL, (1 << 0), true},
{"DC_VAPORIZE", LE_DC_VAPORIZE, (1 << 1), true},
@@ -274,6 +289,459 @@ const lua_enum_def_list Enumerations[] = {
const size_t Num_enumerations = sizeof(Enumerations) / sizeof(lua_enum_def_list);
+struct deprecated_enum_name_info {
+ lua_enum value;
+ const char* replacement;
+ gameversion::version deprecated_since;
+};
+
+static const SCP_unordered_map Deprecated_enumeration_names = {
+ // Deprecated due to renaming during the great enum cleanup of 2026
+ {"NONE", {LE_NONE, "SHIELD_NONE", gameversion::version(26, 0)}},
+ {"NORMAL_CONTROLS", {LE_NORMAL_CONTROLS, "FLIGHT_CONTROL_NORMAL", gameversion::version(26, 0)}},
+ {"LUA_STEERING_CONTROLS", {LE_LUA_STEERING_CONTROLS, "FLIGHT_CONTROL_LUA_STEERING", gameversion::version(26, 0)}},
+ {"LUA_FULL_CONTROLS", {LE_LUA_FULL_CONTROLS, "FLIGHT_CONTROL_LUA_FULL", gameversion::version(26, 0)}},
+ {"NORMAL_BUTTON_CONTROLS", {LE_NORMAL_BUTTON_CONTROLS, "BUTTON_CONTROL_NORMAL", gameversion::version(26, 0)}},
+ {"LUA_ADDITIVE_BUTTON_CONTROL", {LE_LUA_ADDITIVE_BUTTON_CONTROL, "BUTTON_CONTROL_LUA_ADDITIVE", gameversion::version(26, 0)}},
+ {"LUA_OVERRIDE_BUTTON_CONTROL", {LE_LUA_OVERRIDE_BUTTON_CONTROL, "BUTTON_CONTROL_LUA_OVERRIDE", gameversion::version(26, 0)}},
+ {"INVALID", {LE_INVALID, "SHIP_STATUS_INVALID", gameversion::version(26, 0)}},
+ {"NOT_YET_PRESENT", {LE_NOT_YET_PRESENT, "SHIP_STATUS_NOT_YET_PRESENT", gameversion::version(26, 0)}},
+ {"PRESENT", {LE_PRESENT, "SHIP_STATUS_PRESENT", gameversion::version(26, 0)}},
+ {"DEATH_ROLL", {LE_DEATH_ROLL, "SHIP_STATUS_DEATH_ROLL", gameversion::version(26, 0)}},
+ {"EXITED", {LE_EXITED, "SHIP_STATUS_EXITED", gameversion::version(26, 0)}},
+ {"SEXPVAR_CAMPAIGN_PERSISTENT", {LE_SEXPVAR_CAMPAIGN_PERSISTENT, "SEXPVAR_PERSIST_CAMPAIGN", gameversion::version(26, 0)}},
+ {"SEXPVAR_NOT_PERSISTENT", {LE_SEXPVAR_NOT_PERSISTENT, "SEXPVAR_PERSIST_NONE", gameversion::version(26, 0)}},
+ {"SEXPVAR_PLAYER_PERSISTENT", {LE_SEXPVAR_PLAYER_PERSISTENT, "SEXPVAR_PERSIST_PLAYER", gameversion::version(26, 0)}},
+ // Previously this was a manual deprecation and is now moved moved here with version 26.0.0 because the old way never actually errored
+ {"VM_EXTERNAL_CAMERA_LOCKED", {LE_VM_EXTERNAL_CAMERA_LOCKED, "VM_CAMERA_LOCKED", gameversion::version(26, 0)}},
+ // These target enums are unused - no Lua API function accepts them
+ {"LOCK", {LE_LOCK, "nothing (this enum was never implemented)", gameversion::version(26, 0)}},
+ {"UNLOCK", {LE_UNLOCK, "nothing (this enum was never implemented)", gameversion::version(26, 0)}},
+ // These cfile enums were never implemented — no Lua API function accepts them
+ {"CFILE_TYPE_NORMAL", {LE_CFILE_TYPE_NORMAL, "nothing (these enums were never implemented)", gameversion::version(26, 0)}},
+ {"CFILE_TYPE_MEMORY_MAPPED", {LE_CFILE_TYPE_MEMORY_MAPPED, "nothing (these enums were never implemented)", gameversion::version(26, 0)}},
+ // Deprecated/unused particle types
+ {"PARTICLE_DEBUG", {LE_PARTICLE_DEBUG, "nothing (debug particles were removed in FSO 25.0)", gameversion::version(25, 0)}},
+ {"PARTICLE_PERSISTENT_BITMAP", {LE_PARTICLE_PERSISTENT_BITMAP, "PARTICLE_BITMAP via createPersistentParticle (this enum was never implemented)", gameversion::version(26, 0)}}
+};
+
+static std::optional get_deprecated_enum_info(const SCP_string& enum_name) {
+ auto deprecated_enum = Deprecated_enumeration_names.find(enum_name);
+ if (deprecated_enum != Deprecated_enumeration_names.end()) {
+ return deprecated_enum->second;
+ }
+
+ return std::nullopt;
+}
+
+bool is_deprecated_enum_name(const char* enum_name) {
+ return enum_name != nullptr && Deprecated_enumeration_names.find(enum_name) != Deprecated_enumeration_names.end();
+}
+
+std::optional get_enum_group_info(const char* enum_name) {
+ if (enum_name == nullptr) {
+ return std::nullopt;
+ }
+
+ auto starts = [enum_name](const char* prefix) { return strncmp(enum_name, prefix, strlen(prefix)) == 0; };
+
+ static const SCP_vector Enum_groups = {
+ {"ALPHABLEND_", "alphablend", "Alpha Blending", "Alpha blending modes used by rendering functions."},
+ {"MOUSE_", "mouse-buttons", "Mouse Buttons", "Mouse button constants."},
+ {"FLIGHTMODE_", "flight-modes", "Flight Modes", "Primary flight cursor/ship lock modes."},
+ {"ORDER_", "orders", "Orders", "AI and command order constants."},
+ {"PARTICLE_", "particles", "Particle Types", "Particle rendering and creation types."},
+ {"SEXPVAR_TYPE_", "sexpvar-type", "SEXP Variable Type", "SEXP variable value type constants."},
+ {"SEXPVAR_PERSIST_", "sexpvar-persist", "SEXP Variable Persistence", "SEXP variable persistence level constants."},
+ {"TEXTURE_", "textures", "Texture Sources", "Texture handle source types."},
+ {"MISSION_", "mission-flow", "Mission Flow", "Mission-level control and mission selection constants."},
+ {"SHIELD_", "shield-quadrants", "Shield Quadrants", "Shield quadrant constants."},
+ {"FLIGHT_CONTROL_", "flight-controls", "Flight Control Mode", "Specifies whether steering is handled by normal controls or Lua control modes."},
+ {"BUTTON_CONTROL_", "button-controls", "Button Control Mode", "Defines how Lua interacts with normal button input handling."},
+ {"VM_", "view-modes", "View Modes", "View and camera modes for rendering/player perspective."},
+ {"MESSAGE_PRIORITY_", "message-priority", "Message Priority", "Mission message priority levels."},
+ {"OPTION_TYPE_", "option-types", "Option Types", "Option UI and value representation types."},
+ {"AUDIOSTREAM_", "audio-stream-types", "Audio Stream Types", "Audio stream categories."},
+ {"CONTEXT_", "execution-context", "Execution Context", "Lua execution context state values."},
+ {"FIREBALL_", "fireball-types", "Fireball Types", "Fireball effect types."},
+ {"GR_RESIZE_", "resize-modes", "Resize Modes", "Graphics resize mode constants."},
+ {"OS_", "object-sound", "Object Sound", "Object sound flags and sound slots."},
+ {"MOVIE_", "movies", "Movie Events", "Campaign/mission movie event positions."},
+ {"TBOX_", "targetbox-flash", "Targetbox Flash", "Targetbox flashing indicator selectors."},
+ {"LUAAI_", "luaai-goals", "Lua AI Goal State", "Lua AI achievability state values."},
+ {"SCORE_", "score-events", "Score Events", "Identifies a music score slot for a specific game screen."},
+ {"SHIP_STATUS_", "ship-status", "Ship Presence/State", "Describes high-level ship registry presence and lifecycle state."},
+ {"DC_", "object-create-flags", "Object Creation Flags", "Flags that modify object creation behavior."},
+ {"RPC_", "rpc", "Remote Procedure Call", "RPC routing and reliability mode constants."},
+ {"HOTKEY_", "hotkey-lines", "Hotkey Lines", "Hotkey list line type constants."},
+ {"SCROLLBACK_", "scrollback-sources", "Scrollback Sources", "Mission scrollback/source category constants."},
+ {"MULTI_TYPE_", "multi-types", "Multiplayer Mission Types", "Multiplayer mission type constants."},
+ {"MULTI_OPTION_", "multi-options", "Multiplayer Options", "Multiplayer option scope/permission constants."},
+ {"MULTI_GAME_TYPE_", "multi-game-types", "Multiplayer Game Visibility", "Multiplayer game visibility/filter constants."},
+ {"SEXP_", "sexp-result", "SEXP Results", "SEXP evaluation result state constants."},
+ {"COMMIT_", "commit-status", "Loadout Commit Status", "Loadout/briefing commit result constants."},
+ {"SQUAD_MESSAGE_", "squad-messages", "Squad Messages", "Wingman command/squad message constants."},
+ {"BUILTIN_MESSAGE_", "builtin-messages", "Built-in Messages", "Built-in message event constants."}
+ };
+ for (const auto& group : Enum_groups) {
+ if (starts(group.prefix)) {
+ return group;
+ }
+ }
+
+ return std::nullopt;
+}
+
+static const SCP_unordered_map Enum_descriptions = {
+ // ALPHABLEND
+ {"ALPHABLEND_NONE", "Always uses standard alpha blending (Alpha * Src + (1 - Alpha) * Dst). Opacity controls transparency."},
+ {"ALPHABLEND_FILTER", "Adaptive blending. For bitmaps with an alpha channel, behaves identically to ALPHABLEND_NONE. For bitmaps without an alpha channel, uses additive blending where the bitmap is added to the background with its intensity scaled by opacity."},
+
+ // MOUSE
+ {"MOUSE_LEFT_BUTTON", "The left mouse button click."},
+ {"MOUSE_RIGHT_BUTTON", "The right mouse button click."},
+ {"MOUSE_MIDDLE_BUTTON", "The middle mouse button click. Scroll wheel movement does not trigger this."},
+ {"MOUSE_X1_BUTTON", "The first extra mouse button (typically the rear side/thumb button). Only available on hardware that provides it."},
+ {"MOUSE_X2_BUTTON", "The second extra mouse button (typically the forward side/thumb button). Only available on hardware that provides it."},
+
+ // FLIGHTMODE
+ {"FLIGHTMODE_FLIGHTCURSOR", "Player inputs move a cursor within a cone in front of the ship; the ship turns toward the cursor.."},
+ {"FLIGHTMODE_SHIPLOCKED", "Player pitch and heading inputs directly rotate the ship. This is the standard flight control mode."},
+
+ // ORDER
+ {"ORDER_ATTACK", "Attack the target. Behavior depends on target type: attacks a ship, chases a weapon, or destroys a subsystem."},
+ {"ORDER_ATTACK_WING", "Attack all ships in the wing that the target ship belongs to."},
+ {"ORDER_ATTACK_SHIP_CLASS", "Attack all ships of the specified ship class."},
+ {"ORDER_ATTACK_SHIP_TYPE", "Attack all ships of the specified ship type."},
+ {"ORDER_ATTACK_ANY", "Attack any enemy ship in the mission."},
+ {"ORDER_DEPART", "Warp out of the mission."},
+ {"ORDER_DISABLE", "Destroy the target ship's engines to disable it. Purges conflicting goals from all ships in the mission."},
+ {"ORDER_DISABLE_TACTICAL", "Destroy the target ship's engines to disable it. Does not purge any other goals."},
+ {"ORDER_DISARM", "Destroy the target ship's turrets to disarm it. Purges conflicting goals from all ships in the mission."},
+ {"ORDER_DISARM_TACTICAL", "Destroy the target ship's turrets to disarm it. Does not purge any other goals."},
+ {"ORDER_DOCK", "Dock with the target ship."},
+ {"ORDER_EVADE", "Actively fly away from and evade the target ship."},
+ {"ORDER_FLY_TO", "Fly toward the target ship; goal completes when within range."},
+ {"ORDER_FORM_ON_WING", "Fly in formation on the wing of the target ship."},
+ {"ORDER_GUARD", "Patrol around and protect the target ship."},
+ {"ORDER_GUARD_WING", "Patrol around and protect the entire wing that the target ship belongs to."},
+ {"ORDER_IGNORE_SHIP", "Stop attacking the target ship and purge conflicting goals from all other ships in the mission."},
+ {"ORDER_IGNORE_SHIP_NEW", "Stop attacking the target ship. Only removes conflicting goals from this ship, not others."},
+ {"ORDER_KEEP_SAFE_DISTANCE", "Maintain a minimum safe distance from the target ship."},
+ {"ORDER_PLAY_DEAD", "Ship drifts inertially and ignores all inputs including hits. Clears all other goals on the ship when issued."},
+ {"ORDER_PLAY_DEAD_PERSISTENT", "Ship drifts inertially and ignores all inputs including hits. Does not clear other goals when issued; queued goals are preserved."},
+ {"ORDER_REARM", "Fly to the target support ship to rearm and repair."},
+ {"ORDER_STAY_NEAR", "Maintain ongoing proximity to the target ship."},
+ {"ORDER_STAY_STILL", "Stop all movement and hold the current position."},
+ {"ORDER_UNDOCK", "Undock from the target ship."},
+ {"ORDER_WAYPOINTS", "Follow the target waypoint path, looping back to the start when complete."},
+ {"ORDER_WAYPOINTS_ONCE", "Follow the target waypoint path once and stop at the final waypoint."},
+ {"ORDER_LUA", "Execute a Lua-defined custom AI goal."},
+
+ // PARTICLE
+ {"PARTICLE_BITMAP", "Renders a particle using a custom texture supplied via the Texture parameter."},
+ {"PARTICLE_FIRE", "Renders a particle using the built-in fire animation (particleexp01)."},
+ {"PARTICLE_SMOKE", "Renders a particle using the first built-in smoke animation (particlesmoke01)."},
+ {"PARTICLE_SMOKE2", "Renders a particle using the second built-in smoke animation (particlesmoke02)."},
+
+ // SEXPVAR_PERSIST
+ {"SEXPVAR_PERSIST_NONE", "Variable is reset to its initial value at the start of the mission."},
+ {"SEXPVAR_PERSIST_CAMPAIGN", "Variable is saved to the campaign save file and resets when the campaign is restarted."},
+ {"SEXPVAR_PERSIST_PLAYER", "Variable is saved to the player save file and never resets."},
+
+ // SEXPVAR_TYPE
+ {"SEXPVAR_TYPE_NUMBER", "SEXP variable holds an integer numeric value. Floats are not supported."},
+ {"SEXPVAR_TYPE_STRING", "SEXP variable holds a string value."},
+
+ // TEXTURE
+ {"TEXTURE_STATIC", "Render target texture written to infrequently. Use when the texture content rarely changes between frames."},
+ {"TEXTURE_DYNAMIC", "Render target texture written to frequently, e.g. every frame. This is the default for gr.createTexture()."},
+
+ // MISSION
+ {"MISSION_REPEAT", "Sentinel value for mn.startMission(): restarts the most recently played mission instead of specifying a filename."},
+
+ // SHIELD
+ {"SHIELD_NONE", "Refers to the entire shield as a whole rather than a specific quadrant. Gets or sets total shield strength across all quadrants."},
+ {"SHIELD_FRONT", "The front shield quadrant."},
+ {"SHIELD_LEFT", "The left shield quadrant."},
+ {"SHIELD_RIGHT", "The right shield quadrant."},
+ {"SHIELD_BACK", "The rear shield quadrant."},
+
+ // FLIGHT_CONTROL
+ {"FLIGHT_CONTROL_NORMAL", "Standard engine handles all steering and flight controls."},
+ {"FLIGHT_CONTROL_LUA_STEERING", "Lua overrides rotational inputs (pitch, heading, bank); the engine still handles throttle and lateral/vertical translation."},
+ {"FLIGHT_CONTROL_LUA_FULL", "Lua overrides all movement axes including pitch, heading, bank, throttle, and lateral/vertical translation. Weapon firing inputs are not affected."},
+
+ // BUTTON_CONTROL
+ {"BUTTON_CONTROL_NORMAL", "Standard engine processes all button inputs."},
+ {"BUTTON_CONTROL_LUA_ADDITIVE", "Lua button inputs are processed alongside normal engine button inputs."},
+ {"BUTTON_CONTROL_LUA_OVERRIDE", "Lua button processing replaces normal engine button input handling entirely."},
+
+ // VM
+ {"VM_INTERNAL", "Cockpit (internal) view. True when no external view flags are active; camera lock and centering state are excluded from this check."},
+ {"VM_EXTERNAL", "View is external to the cockpit. A base flag combined with others such as VM_CHASE or VM_OTHER_SHIP."},
+ {"VM_TRACK", "The external camera rotates to face the currently targeted ship or subsystem."},
+ {"VM_DEAD_VIEW", "Camera view used when the player ship has been destroyed."},
+ {"VM_CHASE", "Chase camera positioned behind and above the player ship."},
+ {"VM_OTHER_SHIP", "Camera positioned on the player's currently targeted ship."},
+ {"VM_CAMERA_LOCKED", "The player does not have manual control of the camera; it is managed by the engine or scripting. Often set alongside padlock and external view flags."},
+ {"VM_WARP_CHASE", "Camera view during the player's warp-out sequence; the camera remains at the departure point as the ship accelerates away."},
+ {"VM_PADLOCK_UP", "Padlock quick-look view directed upward."},
+ {"VM_PADLOCK_REAR", "Padlock quick-look view directed toward the rear."},
+ {"VM_PADLOCK_LEFT", "Padlock quick-look view directed to the left."},
+ {"VM_PADLOCK_RIGHT", "Padlock quick-look view directed to the right."},
+ {"VM_WARPIN_ANCHOR", "Stationary camera anchor point used during a warp-in sequence."},
+ {"VM_TOPDOWN", "Top-down overhead camera looking down at the player ship."},
+ {"VM_FREECAMERA", "A scripted camera not attached to any ship or object, typically set by a SEXP or Lua camera call."},
+ {"VM_CENTERING", "The cockpit view angle is springing back to the forward-facing orientation after freelook or padlock was released."},
+
+ // MESSAGE_PRIORITY
+ {"MESSAGE_PRIORITY_LOW", "Lowest priority. Message is dropped if the sender has been destroyed or departed. Will not interrupt messages that are currently playing."},
+ {"MESSAGE_PRIORITY_NORMAL", "Normal priority. Message is dropped if the sender has been destroyed or departed. Interrupts lower-priority messages currently playing."},
+ {"MESSAGE_PRIORITY_HIGH", "Highest priority. If the sender has been destroyed or departed, the message plays anyway from Terran Command. Interrupts lower-priority messages currently playing."},
+
+ // OPTION_TYPE
+ {"OPTION_TYPE_SELECTION", "Option has a fixed set of discrete values to choose from, such as a dropdown."},
+ {"OPTION_TYPE_RANGE", "Option has a continuous numeric range with interpolation, such as a slider."},
+
+ // AUDIOSTREAM
+ {"AUDIOSTREAM_EVENTMUSIC", "Stream type for in-mission dynamic event music. Volume is controlled by the music volume setting."},
+ {"AUDIOSTREAM_MENUMUSIC", "Stream type for background music in menus and briefings, such as the main hall, credits, and briefing screens. Volume follows the music volume setting."},
+ {"AUDIOSTREAM_VOICE", "Stream type for spoken voice audio such as mission briefings, training narration, and debriefs. Volume is controlled by the voice volume setting."},
+
+ // CONTEXT
+ {"CONTEXT_VALID", "The Lua execution context is running normally."},
+ {"CONTEXT_SUSPENDED", "The context exists but is not currently active; the executor will retry later. For example, a game state that is on the stack but not currently at the top."},
+ {"CONTEXT_INVALID", "The Lua execution context has been destroyed or is unusable."},
+
+ // FIREBALL
+ {"FIREBALL_MEDIUM_EXPLOSION", "A medium-sized explosion fireball effect."},
+ {"FIREBALL_LARGE_EXPLOSION", "A large explosion fireball effect."},
+ {"FIREBALL_WARP_EFFECT", "A warp portal effect used for ship warp-in and warp-out sequences."},
+
+ // MOVIE
+ {"MOVIE_PRE_FICTION", "Plays just before the fiction viewer game state."},
+ {"MOVIE_PRE_CMD_BRIEF", "Plays just before the command briefing game state."},
+ {"MOVIE_PRE_BRIEF", "Plays just before the briefing game state."},
+ {"MOVIE_PRE_GAME", "Plays just before the mission starts after Accept has been pressed."},
+ {"MOVIE_PRE_DEBRIEF", "Plays just before the debriefing game state."},
+ {"MOVIE_POST_DEBRIEF", "Plays when the debriefing has been accepted but before exiting the mission."},
+ {"MOVIE_END_CAMPAIGN", "Plays when the campaign has been completed."},
+
+ // GR_RESIZE
+ {"GR_RESIZE_NONE", "Coordinates are raw pixels with no scaling applied."},
+ {"GR_RESIZE_FULL", "Scale to fill the full screen dimensions."},
+ {"GR_RESIZE_FULL_CENTER", "Scale to fill the full screen, centered within the viewport."},
+ {"GR_RESIZE_MENU", "Coordinates use the standard UI/menu coordinate space."},
+ {"GR_RESIZE_MENU_ZOOMED", "Menu coordinate space that extends into the full display area, including any letterbox or pillarbox borders beyond the standard menu boundary."},
+ {"GR_RESIZE_MENU_NO_OFFSET", "Menu coordinate space without positional offset applied."},
+
+ // OS (object sound slots/flags)
+ {"OS_NONE", "No flags. Assigns a basic persistent sound with default distance attenuation."},
+ {"OS_MAIN", "Sound for which attenuation does not apply within the object's radius. Typically used for primary continuous sounds such as engine idle loops."},
+ {"OS_ENGINE", "Secondary engine sound, typically tied to throttle level."},
+ {"OS_TURRET_BASE_ROTATION", "Sound played while a turret base rotates."},
+ {"OS_TURRET_GUN_ROTATION", "Sound played while a turret gun barrel rotates."},
+ {"OS_SUBSYS_ALIVE", "Continuous sound played while the subsystem is operational."},
+ {"OS_SUBSYS_DEAD", "Continuous sound that plays only while the subsystem is destroyed (has zero hit points)."},
+ {"OS_SUBSYS_DAMAGED", "Sound whose volume scales proportionally with remaining subsystem health; full volume at full health, silent when destroyed."},
+ {"OS_SUBSYS_ROTATION", "Sound played during a subsystem rotation animation."},
+ {"OS_PLAY_ON_PLAYER", "Allow this sound to play even when the source object is the player's own ship, bypassing normal player-ship audio suppression in cockpit view."},
+ {"OS_LOOPING_DISABLED", "Prevent the sound from looping after it finishes playing."},
+
+ // TBOX_FLASH
+ {"TBOX_FLASH_NAME", "The target name section of the target box."},
+ {"TBOX_FLASH_CARGO", "The cargo information section of the target box."},
+ {"TBOX_FLASH_HULL", "The hull integrity section of the target box."},
+ {"TBOX_FLASH_STATUS", "The target status section of the target box."},
+ {"TBOX_FLASH_SUBSYS", "The targeted subsystem section of the target box."},
+
+ // DC (object creation flags)
+ {"DC_IS_HULL", "Mark the debris piece as a hull fragment, using a specific ship geometry submodel with hull-appropriate physics and lifetime."},
+ {"DC_VAPORIZE", "For non-hull debris, use the vaporize-effect model instead of the generic debris model and extend the piece's lifetime."},
+ {"DC_SET_VELOCITY", "Apply explosion-based velocity to the debris, adding a radial kick from the explosion center to the inherited source ship velocity."},
+ {"DC_FIRE_HOOK", "Fire the OnDebrisCreated scripting hook after the debris piece is created."},
+
+ // RPC
+ {"RPC_SERVER", "Send the RPC call to the server only."},
+ {"RPC_CLIENTS", "Send the RPC call to all connected clients."},
+ {"RPC_BOTH", "Send the RPC call to both the server and all clients."},
+ {"RPC_RELIABLE", "Use reliable delivery; packet is guaranteed to arrive."},
+ {"RPC_ORDERED", "Use sequenced delivery over unreliable transport; out-of-order or stale packets are discarded so only the most recent call is processed."},
+ {"RPC_UNRELIABLE", "Use unreliable delivery; fastest option but packets may be dropped."},
+
+ // SEXP results
+ {"SEXP_TRUE", "SEXP evaluated to a true result."},
+ {"SEXP_FALSE", "SEXP evaluated to a false result."},
+ {"SEXP_KNOWN_FALSE", "SEXP is permanently false and will never become true."},
+ {"SEXP_KNOWN_TRUE", "SEXP is permanently true and will never become false."},
+ {"SEXP_UNKNOWN", "The SEXP result is indeterminate and cannot yet be resolved."},
+ {"SEXP_NAN", "Numeric result is unavailable because a referenced ship or wing has not yet arrived. The value may become valid later once the ship arrives."},
+ {"SEXP_NAN_FOREVER", "SEXP will never produce a valid numeric result."},
+ {"SEXP_CANT_EVAL", "The SEXP cannot yet be evaluated, typically because a referenced object does not yet exist. Acts like false until conditions are met."},
+
+ // COMMIT (loadout validation results)
+ {"COMMIT_SUCCESS", "Loadout validation passed; the mission is ready to launch."},
+ {"COMMIT_FAIL", "Generic loadout validation failure."},
+ {"COMMIT_PLAYER_NO_WEAPONS", "Player ship has no weapons assigned."},
+ {"COMMIT_NO_REQUIRED_WEAPON", "A weapon required by the mission is missing from the loadout."},
+ {"COMMIT_NO_REQUIRED_WEAPON_MULTIPLE", "Multiple mission-required weapons are missing from the loadout."},
+ {"COMMIT_BANK_GAP_ERROR", "Weapon banks contain gaps; empty slots appear between assigned weapons."},
+ {"COMMIT_PLAYER_NO_SLOT", "Player has no ship slot assigned in the briefing."},
+ {"COMMIT_MULTI_PLAYERS_NO_SHIPS", "Not all multiplayer players have been assigned to their ship slots yet."},
+ {"COMMIT_MULTI_NOT_ALL_ASSIGNED", "Not all multiplayer pilots have been assigned to a ship slot."},
+ {"COMMIT_MULTI_NO_PRIMARY", "A multiplayer ship has no primary weapon assigned."},
+ {"COMMIT_MULTI_NO_SECONDARY", "A multiplayer ship has no secondary weapon assigned."},
+
+ // MULTI_OPTION
+ {"MULTI_OPTION_RANK", "Restricts the action to the highest-ranking player(s) in the game. Used by NetGame.Orders and NetGame.EndMission."},
+ {"MULTI_OPTION_LEAD", "Restricts the action to wing or team leaders only. Used by NetGame.Orders and NetGame.EndMission."},
+ {"MULTI_OPTION_ANY", "Allows any non-observer player to perform the action. Used by NetGame.Orders and NetGame.EndMission."},
+ {"MULTI_OPTION_HOST", "Restricts the action to the game host only. Used by NetGame.Orders and NetGame.EndMission."},
+
+ // LUAAI
+ {"LUAAI_ACHIEVABLE", "The Lua AI goal can be executed immediately."},
+ {"LUAAI_NOT_YET_ACHIEVABLE", "The Lua AI goal is valid but cannot be started yet."},
+ {"LUAAI_UNACHIEVABLE", "The Lua AI goal can never be achieved and will be cancelled."},
+
+ // SCORE
+ {"SCORE_BRIEFING", "Music score slot for the mission briefing screen."},
+ {"SCORE_DEBRIEFING_SUCCESS", "Music score slot for the debriefing screen when the mission was successful."},
+ {"SCORE_DEBRIEFING_AVERAGE", "Music score slot for the debriefing screen when the mission result was average."},
+ {"SCORE_DEBRIEFING_FAILURE", "Music score slot for the debriefing screen when the mission failed."},
+ {"SCORE_FICTION_VIEWER", "Music score slot for the fiction viewer screen."},
+
+ // SHIP_STATUS
+ {"SHIP_STATUS_INVALID", "The ship registry entry has not been initialized yet."},
+ {"SHIP_STATUS_NOT_YET_PRESENT", "The ship is on the arrival list but has not yet arrived in-mission."},
+ {"SHIP_STATUS_PRESENT", "The ship is currently in-mission; its object and ship pointers are valid."},
+ {"SHIP_STATUS_DEATH_ROLL", "The ship has been destroyed but is still in its death roll; its object and ship pointers remain valid."},
+ {"SHIP_STATUS_EXITED", "The ship has been destroyed, departed, or vanished; its object and ship pointers are no longer valid."},
+
+ // BUILTIN_MESSAGE
+ {"BUILTIN_MESSAGE_ATTACK_TARGET", "Confirmation sent by a wingman acknowledging an Attack order."},
+ {"BUILTIN_MESSAGE_DISABLE_TARGET", "Confirmation sent by a wingman acknowledging a Disable order."},
+ {"BUILTIN_MESSAGE_DISARM_TARGET", "Confirmation sent by a wingman acknowledging a Disarm order."},
+ {"BUILTIN_MESSAGE_ATTACK_SUBSYSTEM", "Confirmation sent by a wingman acknowledging an order to destroy a specific subsystem."},
+ {"BUILTIN_MESSAGE_PROTECT_TARGET", "Confirmation sent by a wingman acknowledging a Protect order."},
+ {"BUILTIN_MESSAGE_FORM_ON_MY_WING", "Confirmation sent by a wingman acknowledging a Form on Wing order."},
+ {"BUILTIN_MESSAGE_COVER_ME", "Confirmation sent by a wingman acknowledging a Cover Me order."},
+ {"BUILTIN_MESSAGE_IGNORE", "Confirmation sent by a wingman acknowledging an Ignore order."},
+ {"BUILTIN_MESSAGE_ENGAGE", "Confirmation sent by a wingman acknowledging an Engage Enemy order."},
+ {"BUILTIN_MESSAGE_WARP_OUT", "Confirmation sent by a wingman acknowledging a Depart order."},
+ {"BUILTIN_MESSAGE_DOCK_YES", "Sent by a ship when it begins a docking sequence."},
+ {"BUILTIN_MESSAGE_YESSIR", "Generic affirmative acknowledgment sent by a wingman when complying with an order."},
+ {"BUILTIN_MESSAGE_NOSIR", "Generic refusal sent by a wingman when an order cannot be carried out."},
+ {"BUILTIN_MESSAGE_NO_TARGET", "Sent by a wingman when the order requires a target but no valid target is available."},
+ {"BUILTIN_MESSAGE_CHECK_6", "Warning sent by a wingman when an enemy fighter or bomber is attacking the player from behind."},
+ {"BUILTIN_MESSAGE_PLAYER_DIED", "Sent by a wingman when the player enters the death roll."},
+ {"BUILTIN_MESSAGE_PRAISE", "Compliment sent by a wingman when the player destroys an enemy ship."},
+ {"BUILTIN_MESSAGE_HIGH_PRAISE", "Enhanced compliment sent by a wingman when the player has accumulated more than ten kills in the mission. Falls back to BUILTIN_MESSAGE_PRAISE."},
+ {"BUILTIN_MESSAGE_BACKUP", "Sent by a ship from a newly arrived friendly wing announcing support."},
+ {"BUILTIN_MESSAGE_HELP", "Distress call sent by a wingman when their hull or shields are critically low."},
+ {"BUILTIN_MESSAGE_WINGMAN_SCREAM", "Death cry sent by a wingman as they are destroyed."},
+ {"BUILTIN_MESSAGE_PRAISE_SELF", "Boast sent by a wingman when they destroy an enemy ship."},
+ {"BUILTIN_MESSAGE_REARM_REQUEST", "Request sent by a wingman when their secondary missile ammunition falls below fifty percent."},
+ {"BUILTIN_MESSAGE_REPAIR_REQUEST", "Request sent by a wingman when their hull integrity is critically low or a subsystem is disabled."},
+ {"BUILTIN_MESSAGE_PRIMARIES_LOW", "Alert sent by a wingman when their ballistic primary weapon ammunition falls below thirty percent. Sent at most once per ship per mission."},
+ {"BUILTIN_MESSAGE_REARM_PRIMARIES", "Request sent by a wingman for primary ballistic ammunition resupply. Falls back to BUILTIN_MESSAGE_REARM_REQUEST."},
+ {"BUILTIN_MESSAGE_REARM_WARP", "Sent by a support ship as it warps in to provide repair or rearm service."},
+ {"BUILTIN_MESSAGE_ON_WAY", "Sent by a support ship confirming it is en route to perform repairs or rearming."},
+ {"BUILTIN_MESSAGE_ALREADY_ON_WAY", "Sent by a support ship when the player requests rearm but it is already en route. Falls back to BUILTIN_MESSAGE_ON_WAY."},
+ {"BUILTIN_MESSAGE_REPAIR_DONE", "Sent by a support ship when it completes repair or rearm service."},
+ {"BUILTIN_MESSAGE_REPAIR_ABORTED", "Sent by a support ship when its repair or rearm operation is interrupted."},
+ {"BUILTIN_MESSAGE_SUPPORT_KILLED", "Sent by Command when the support ship is destroyed."},
+ {"BUILTIN_MESSAGE_ALL_ALONE", "Sent by Command when the player is the last surviving friendly ship in the mission."},
+ {"BUILTIN_MESSAGE_ARRIVE_ENEMY", "Warning sent when a new enemy wing arrives in the mission."},
+ {"BUILTIN_MESSAGE_OOPS", "Sent by a wingman when they are hit by friendly fire."},
+ {"BUILTIN_MESSAGE_HAMMER_SWINE", "Sent by a wingman when the player is identified as a traitor due to repeated friendly fire."},
+ {"BUILTIN_MESSAGE_AWACS_75", "Warning sent by an AWACS ship when its hull integrity drops below seventy-five percent."},
+ {"BUILTIN_MESSAGE_AWACS_25", "Warning sent by an AWACS ship when its hull integrity drops below twenty-five percent."},
+ {"BUILTIN_MESSAGE_STRAY_WARNING", "Repeating warning sent by Command when the player strays outside the mission boundary."},
+ {"BUILTIN_MESSAGE_STRAY_WARNING_FINAL", "Final warning sent by Command immediately before the player is destroyed for straying too far from the mission area."},
+ {"BUILTIN_MESSAGE_INSTRUCTOR_HIT", "Sent during training missions when the player hits the instructor ship with friendly fire."},
+ {"BUILTIN_MESSAGE_INSTRUCTOR_ATTACK", "Sent during training missions when the player directly attacks the instructor ship."},
+ {"BUILTIN_MESSAGE_ALL_CLEAR", "Indicates the area is clear of enemies. Not currently triggered by the engine."},
+ {"BUILTIN_MESSAGE_PERMISSION", "Permission-related response. Not currently triggered by the engine."},
+ {"BUILTIN_MESSAGE_STRAY", "Intended as an initial stray warning. Not currently triggered by the engine."},
+
+ // SQUAD_MESSAGE
+ {"SQUAD_MESSAGE_ATTACK_TARGET", "Order the wingman to attack the player's current target. Removes the target's Protected flag if the ship type permits."},
+ {"SQUAD_MESSAGE_DISABLE_TARGET", "Order the wingman to destroy the target's engines, immobilizing it without destroying the ship."},
+ {"SQUAD_MESSAGE_DISARM_TARGET", "Order the wingman to destroy the target's turrets, neutralizing its weapons while leaving the ship mobile."},
+ {"SQUAD_MESSAGE_PROTECT_TARGET", "Order the wingman to guard and protect the player's current friendly target."},
+ {"SQUAD_MESSAGE_IGNORE_TARGET", "Order the wingman to stop attacking the player's current enemy target."},
+ {"SQUAD_MESSAGE_FORMATION", "Order the wingman to fly in formation on the player's wing."},
+ {"SQUAD_MESSAGE_COVER_ME", "Order the wingman to guard and protect the player."},
+ {"SQUAD_MESSAGE_ENGAGE_ENEMY", "Order the wingman to attack any enemy ship. No target is required."},
+ {"SQUAD_MESSAGE_CAPTURE_TARGET", "Order the wingman to dock with and capture the player's current enemy target. Sets the Protected flag on the target to prevent accidental destruction."},
+ {"SQUAD_MESSAGE_REARM_REPAIR_ME", "Order the designated support ship to rearm and repair the player. Cannot be sent to wings."},
+ {"SQUAD_MESSAGE_ABORT_REARM_REPAIR", "Order the designated support ship to abort an in-progress rearm and repair. Cannot be sent to wings."},
+ {"SQUAD_MESSAGE_STAY_NEAR_ME", "Order a support ship to remain within close range of the player. Cannot be sent to wings."},
+ {"SQUAD_MESSAGE_STAY_NEAR_TARGET", "Order a support ship to remain within close range of the player's current target. Cannot be sent to wings."},
+ {"SQUAD_MESSAGE_KEEP_SAFE_DIST", "Order a support ship to maintain a safe distance from the player. Cannot be sent to wings."},
+ {"SQUAD_MESSAGE_DEPART", "Order the wingman or wing to warp out of the mission."},
+ {"SQUAD_MESSAGE_DISABLE_SUBSYSTEM", "Order the wingman to destroy the player's currently targeted subsystem on an enemy ship."},
+ {"SQUAD_MESSAGE_LUA_AI", "Issues a custom Lua AI order. Not a standard squad menu command; used programmatically to invoke scripted AI behaviors."},
+
+ // MULTI_GAME_TYPE
+ {"MULTI_GAME_TYPE_OPEN", "Game is open to all players with no join restrictions."},
+ {"MULTI_GAME_TYPE_PASSWORD", "Game requires players to provide the correct password to join. Pass the password string as the second argument to setGameType()."},
+ {"MULTI_GAME_TYPE_RANK_ABOVE", "Only players at or above a specified rank may join. Pass the rank index as the second argument to setGameType()."},
+ {"MULTI_GAME_TYPE_RANK_BELOW", "Only players at or below a specified rank may join. Pass the rank index as the second argument to setGameType()."},
+
+ // MULTI_TYPE
+ {"MULTI_TYPE_COOP", "Cooperative multiplayer mode. All players form a single team and play together against AI opposition."},
+ {"MULTI_TYPE_TEAM", "Team vs. Team multiplayer mode. Players are divided into two competing teams. See also MULTI_TYPE_SQUADWAR for the ranked variant."},
+ {"MULTI_TYPE_DOGFIGHT", "Free-for-all multiplayer mode. All players compete individually against each other for score."},
+ {"MULTI_TYPE_SQUADWAR", "Squad War mode. A ranked, PXO tracker-integrated variant of Team vs. Team play. This is a runtime-only mode with no corresponding mission file flag; it can only be active when the mission supports MULTI_TYPE_TEAM."},
+
+ // SCROLLBACK_SOURCE
+ {"SCROLLBACK_SOURCE_COMPUTER", "Standard HUD system messages. Displayed in normal text color in the scrollback viewer."},
+ {"SCROLLBACK_SOURCE_TRAINING", "Training mission narration and instructor messages. Displayed in bright blue text."},
+ {"SCROLLBACK_SOURCE_HIDDEN", "Message is stored in the scrollback log but not rendered in the scrollback viewer; invisible to the player during normal play."},
+ {"SCROLLBACK_SOURCE_IMPORTANT", "Critical mission notification. Displayed in bright white text."},
+ {"SCROLLBACK_SOURCE_FAILED", "A mission objective has failed. Displayed in bright white text with a red circle icon in the scrollback viewer."},
+ {"SCROLLBACK_SOURCE_SATISFIED", "A mission objective has been completed. Displayed in bright white text with a green circle icon in the scrollback viewer."},
+ {"SCROLLBACK_SOURCE_COMMAND", "A message from Terran Command or the mission's commanding authority. Displayed in bright white text."},
+ {"SCROLLBACK_SOURCE_NETPLAYER", "A chat message or communication from a multiplayer network player. Text color is determined by the player's IFF team."},
+
+ // HOTKEY_LINE
+ {"HOTKEY_LINE_NONE", "Sentinel value marking the end of the active hotkey list. Lines at this index and beyond are unused. Not encountered during normal iteration using the standard length operator."},
+ {"HOTKEY_LINE_HEADING", "A non-interactive section header row in the hotkey list, such as 'Friendly Ships' or 'Enemy Ships'. Cannot be selected or assigned a hotkey."},
+ {"HOTKEY_LINE_WING", "A wing (squadron) entry in the hotkey list. Can be expanded to show its constituent ships as HOTKEY_LINE_SUBSHIP entries beneath it, or collapsed to hide them."},
+ {"HOTKEY_LINE_SHIP", "An individual ship that is not part of any wing; appears as a top-level entry in the hotkey list."},
+ {"HOTKEY_LINE_SUBSHIP", "An individual ship that belongs to a wing, displayed as an indented child entry beneath its parent HOTKEY_LINE_WING entry when the wing is expanded."},
+};
+
+const char* get_enum_description(const char* enum_name) {
+ if (enum_name == nullptr) {
+ return nullptr;
+ }
+ auto it = Enum_descriptions.find(enum_name);
+ if (it != Enum_descriptions.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+static void maybe_warn_deprecated_enum(lua_State* L, const enum_h* e) {
+ if (e == nullptr || !e->isValid()) {
+ return;
+ }
+ auto deprecated_info = get_deprecated_enum_info(e->getName());
+ if (deprecated_info) {
+ const auto& deprecation_version = deprecated_info->deprecated_since;
+ if (mod_supports_version(deprecation_version.major, deprecation_version.minor, deprecation_version.build)) {
+ LuaError(L, "Enumeration '%s' is deprecated since version %s and cannot be used if the mod targets that version or higher. Use '%s' instead.",
+ e->getName().c_str(), gameversion::format_version(deprecation_version).c_str(), deprecated_info->replacement);
+ } else {
+ Warning(LOCATION, "Enumeration '%s' is deprecated from version %s and should be replaced with '%s'.",
+ e->getName().c_str(), gameversion::format_version(deprecation_version).c_str(), deprecated_info->replacement);
+ }
+ }
+}
+
enum_h::enum_h() {
index = ENUM_INVALID;
@@ -388,6 +856,8 @@ ADE_FUNC(__newindex,
return ade_set_error(L, "o", l_Enum.Set(enum_h()));
}
+ maybe_warn_deprecated_enum(L, e2);
+
if (!e1->is_constant) {
e1->index = e2->index;
}
@@ -406,6 +876,8 @@ ADE_FUNC(__tostring,
return ade_set_args(L, "s", "");
}
+ maybe_warn_deprecated_enum(L, e);
+
if (!e->isValid()) {
return ade_set_args(L, "s", "");
}
@@ -430,6 +902,9 @@ ADE_FUNC(__eq,
return ade_set_error(L, "o", l_Enum.Set(enum_h()));
}
+ maybe_warn_deprecated_enum(L, e1);
+ maybe_warn_deprecated_enum(L, e2);
+
if (e1 == nullptr || e2 == nullptr) {
return ADE_RETURN_FALSE;
}
@@ -450,6 +925,9 @@ ADE_FUNC(__add,
return ade_set_error(L, "o", l_Enum.Set(enum_h()));
}
+ maybe_warn_deprecated_enum(L, e1);
+ maybe_warn_deprecated_enum(L, e2);
+
if (e1 == nullptr || e2 == nullptr || !e1->isValid() || !e2->isValid() || !e1->value ||!e2->value) {
return ade_set_error(L, "o", l_Enum.Set(enum_h()));
}
@@ -470,6 +948,9 @@ ADE_FUNC(__mul,
return ade_set_error(L, "o", l_Enum.Set(enum_h()));
}
+ maybe_warn_deprecated_enum(L, e1);
+ maybe_warn_deprecated_enum(L, e2);
+
if (e1 == nullptr || e2 == nullptr || !e1->isValid() || !e2->isValid() || !e1->value || !e2->value) {
return ade_set_error(L, "o", l_Enum.Set(enum_h()));
}
@@ -484,6 +965,8 @@ ADE_VIRTVAR_DEPRECATED(IntValue, l_Enum, "enumeration", "Internal value of the e
return ade_set_args(L, "i", -1);
}
+ maybe_warn_deprecated_enum(L, e);
+
if (ADE_SETTING_VAR) {
LuaError(L, "IntValue is read only!");
return ADE_RETURN_NIL;
@@ -499,6 +982,8 @@ ADE_VIRTVAR(Value, l_Enum, "enumeration", "Internal bitfield value of the enum.
return ade_set_args(L, "i", -1);
}
+ maybe_warn_deprecated_enum(L, e);
+
if (ADE_SETTING_VAR) {
LuaError(L, "Value is read only!");
return ADE_RETURN_NIL;
diff --git a/code/scripting/api/objs/enums.h b/code/scripting/api/objs/enums.h
index 08895afd540..933b00075aa 100644
--- a/code/scripting/api/objs/enums.h
+++ b/code/scripting/api/objs/enums.h
@@ -273,6 +273,7 @@ enum lua_enum : int32_t {
ENUM_INVALID
};
+
struct lua_enum_def_list : public flag_def_list_new {
std::optional value;
constexpr lua_enum_def_list(const char* enum_name, lua_enum flag, bool used) : flag_def_list_new{ enum_name, flag, used, false }, value(std::nullopt) {}
@@ -282,6 +283,18 @@ struct lua_enum_def_list : public flag_def_list_new {
extern const lua_enum_def_list Enumerations[];
extern const size_t Num_enumerations;
+struct enum_group_info {
+ const char* prefix;
+ const char* id;
+ const char* title;
+ const char* description;
+};
+
+bool is_deprecated_enum_name(const char* enum_name);
+std::optional get_enum_group_info(const char* enum_name);
+const char* get_enum_description(const char* enum_name);
+
+
struct enum_h {
private:
enum class last_combine_op { NATIVE, AND, OR };
diff --git a/code/scripting/api/objs/execution_context.cpp b/code/scripting/api/objs/execution_context.cpp
index 8398a64430e..36121615d71 100644
--- a/code/scripting/api/objs/execution_context.cpp
+++ b/code/scripting/api/objs/execution_context.cpp
@@ -25,7 +25,7 @@ ADE_FUNC(determineState,
nullptr,
"Determines the current state of the context.",
"enumeration",
- "One of the CONTEXT_ enumerations")
+ "One of the CONTEXT_* enumerations")
{
execution_context_h* context = nullptr;
if (!ade_get_args(L, "o", l_ExecutionContext.GetPtr(&context))) {
diff --git a/code/scripting/api/objs/fireball.cpp b/code/scripting/api/objs/fireball.cpp
index 4f5d42df770..afd74d0c7bb 100644
--- a/code/scripting/api/objs/fireball.cpp
+++ b/code/scripting/api/objs/fireball.cpp
@@ -35,7 +35,7 @@ ADE_VIRTVAR(Class, l_Fireball, "fireballclass", "Fireball's class", "fireballcla
return ade_set_args(L, "o", l_Fireballclass.Set(fb->fireball_info_index));
}
-ADE_VIRTVAR(RenderType, l_Fireball, "enumeration", "Fireball's render type", "enumeration", "Fireball rendertype, or handle to invalid enum if fireball handle is invalid or a bad enum was given")
+ADE_VIRTVAR(RenderType, l_Fireball, "enumeration", "Fireball's render type; uses FIREBALL_* enumerations.", "enumeration", "Fireball render type as a FIREBALL_* enumeration, or handle to invalid enum if fireball handle is invalid or a bad enum was given")
{
object_h* oh = NULL;
enum_h type;
diff --git a/code/scripting/api/objs/missionhotkey.cpp b/code/scripting/api/objs/missionhotkey.cpp
index f03786fb3f8..c207f2fa90c 100644
--- a/code/scripting/api/objs/missionhotkey.cpp
+++ b/code/scripting/api/objs/missionhotkey.cpp
@@ -60,9 +60,9 @@ ADE_VIRTVAR(Text, l_Hotkey, nullptr, "The text of this hotkey line", "string", "
ADE_VIRTVAR(Type,
l_Hotkey,
nullptr,
- "The type of this hotkey line: HOTKEY_LINE_NONE, HOTKEY_LINE_HEADING, HOTKEY_LINE_WING, HOTKEY_LINE_SHIP, or HOTKEY_LINE_SUBSHIP.",
+ "The type of this hotkey line.",
"enumeration",
- "The type")
+ "A HOTKEY_* enumeration")
{
hotkey_h current;
lua_enum eh_idx = ENUM_INVALID;
diff --git a/code/scripting/api/objs/multi_objects.cpp b/code/scripting/api/objs/multi_objects.cpp
index b0788ac803f..5ab8c27cb4d 100644
--- a/code/scripting/api/objs/multi_objects.cpp
+++ b/code/scripting/api/objs/multi_objects.cpp
@@ -626,9 +626,9 @@ ADE_VIRTVAR(Tracker,
ADE_VIRTVAR(Type,
l_NetMission,
nullptr,
- "The type of mission. Can be MULTI_TYPE_COOP, MULTI_TYPE_TEAM, or MULTI_TYPE_DOGFIGHT",
+ "The type of mission.",
"enumeration",
- "the type")
+ "A MULTI_TYPE_* enumeration")
{
net_mission_h current;
lua_enum eh_idx = ENUM_INVALID;
@@ -802,9 +802,9 @@ ADE_VIRTVAR(Tracker,
ADE_VIRTVAR(Type,
l_NetCampaign,
nullptr,
- "The type of mission. Can be MULTI_TYPE_COOP, MULTI_TYPE_TEAM, or MULTI_TYPE_DOGFIGHT",
+ "The type of mission.",
"enumeration",
- "the type")
+ "A MULTI_TYPE_* enumeration")
{
net_campaign_h current;
lua_enum eh_idx = ENUM_INVALID;
@@ -1001,10 +1001,10 @@ ADE_VIRTVAR(HostModifiesShips, l_NetGame, "boolean HostModifies", "Whether or no
ADE_VIRTVAR(Orders,
l_NetGame,
- "enumeration Type",
- "Who can give orders during the game. Will be one of the MULTI_OPTION enums. Returns nil if there's an error.",
"enumeration",
- "the option type")
+ "Who can give orders during the game. Will be one of the MULTI_OPTION_* enumerations. Returns nil if there's an error.",
+ "enumeration",
+ "A MULTI_OPTION_* enumeration")
{
net_game_h current;
enum_h* eh_idx = nullptr;
@@ -1043,10 +1043,10 @@ ADE_VIRTVAR(Orders,
ADE_VIRTVAR(EndMission,
l_NetGame,
- "enumeration Type",
- "Who can end the game. Will be one of the MULTI_OPTION enums. Returns nil if there's an error.",
"enumeration",
- "the option type")
+ "Who can end the game. Will be one of the MULTI_OPTION_* enumerations. Returns nil if there's an error.",
+ "enumeration",
+ "A MULTI_OPTION_* enumeration")
{
net_game_h current;
enum_h* eh_idx = nullptr;
@@ -1193,7 +1193,7 @@ ADE_VIRTVAR(Locked, l_NetGame, "boolean", "Whether or not the loadouts have been
return ade_set_args(L, "b", static_cast(multi_ts_is_locked()));
}
-ADE_VIRTVAR(Type, l_NetGame, "enumeration Type", "The current game type. Will be one of the MULTI_TYPE enums. Returns nil if there's an error.", "enumeration", "the game type")
+ADE_VIRTVAR(Type, l_NetGame, "enumeration", "The current game type. Will be one of the MULTI_TYPE_* enumerations. Returns nil if there's an error.", "enumeration", "The game type as a MULTI_TYPE_* enumeration")
{
net_game_h current;
enum_h *eh_idx = nullptr;
diff --git a/code/scripting/api/objs/object.cpp b/code/scripting/api/objs/object.cpp
index 825e2045dc2..f6b2b409546 100644
--- a/code/scripting/api/objs/object.cpp
+++ b/code/scripting/api/objs/object.cpp
@@ -650,7 +650,7 @@ ADE_FUNC(addPostMoveHook, l_Object, "function(object object) => void callback",
}
ADE_FUNC(assignSound, l_Object, "soundentry GameSnd, [vector Offset=nil, enumeration Flags=OS_NONE, subsystem Subsys=nil]",
- "Assigns a sound to this object, with optional offset, sound flags (OS_XXXX), and associated subsystem.",
+ "Assigns a sound to this object, with optional offset, sound flags (OS_*), and associated subsystem.",
"number",
"Returns the index of the sound on this object, or -1 if a sound could not be assigned.")
{
diff --git a/code/scripting/api/objs/option.cpp b/code/scripting/api/objs/option.cpp
index 069b0f09bcf..05449218705 100644
--- a/code/scripting/api/objs/option.cpp
+++ b/code/scripting/api/objs/option.cpp
@@ -111,7 +111,7 @@ ADE_VIRTVAR(Category, l_Option, nullptr, "The category of this option. (read-onl
return ade_set_args(L, "s", opt->get()->getCategory().c_str());
}
ADE_VIRTVAR(Type, l_Option, nullptr, "The type of this option. One of the OPTION_TYPE_* values. (read-only)",
- "enumeration", "The enum or nil on error")
+ "enumeration", "An OPTION_TYPE_* enumeration, or nil on error")
{
option_h* opt;
if (!ade_get_args(L, "o", l_Option.GetPtr(&opt))) {
diff --git a/code/scripting/api/objs/rpc.cpp b/code/scripting/api/objs/rpc.cpp
index b4ee1452524..d2b97355256 100644
--- a/code/scripting/api/objs/rpc.cpp
+++ b/code/scripting/api/objs/rpc.cpp
@@ -51,7 +51,7 @@ ADE_FUNC(__newindex, l_RPC, "function(any arg) => void rpc_body", "Sets the func
return ade_set_args(L, "u", rpc->func);
}
-ADE_FUNC(__call, l_RPC, "[any = nil, enumeration recipient = default /* as set on RPC creation */]", "Calls the RPC on the specified recipients with the given argument.", "boolean", "True, if RPC call happened (not a guarantee for arrival at the recipient!)")
+ADE_FUNC(__call, l_RPC, "[any = nil, enumeration recipient /* RPC_* */]", "Calls the RPC on the specified RPC_* recipients with the given argument. The recipient defaults to what was set on RPC creation.", "boolean", "True, if RPC call happened (not a guarantee for arrival at the recipient!)")
{
rpc_h rpc;
luacpp::LuaValue argument;
diff --git a/code/scripting/api/objs/sexpvar.cpp b/code/scripting/api/objs/sexpvar.cpp
index 3188dcb4adf..0a8ea4718d4 100644
--- a/code/scripting/api/objs/sexpvar.cpp
+++ b/code/scripting/api/objs/sexpvar.cpp
@@ -28,7 +28,7 @@ ADE_VIRTVAR(Name, l_SEXPVariable, "string", "SEXP Variable name.", "string", "SE
return ade_set_args(L, "s", sv->variable_name);
}
-ADE_VIRTVAR(Persistence, l_SEXPVariable, "enumeration", "SEXP Variable persistence, uses SEXPVAR_*_PERSISTENT enumerations", "enumeration", "SEXPVAR_*_PERSISTENT enumeration, or invalid numeration if handle is invalid")
+ADE_VIRTVAR(Persistence, l_SEXPVariable, "enumeration", "SEXP Variable persistence level, uses SEXPVAR_PERSIST_* enumerations", "enumeration", "A SEXPVAR_PERSIST_* enumeration, or invalid enumeration if handle is invalid")
{
sexpvar_h *svh = NULL;
enum_h *type = NULL;
@@ -70,7 +70,7 @@ ADE_VIRTVAR(Persistence, l_SEXPVariable, "enumeration", "SEXP Variable persisten
return ade_set_args(L, "o", l_Enum.Set(ren));
}
-ADE_VIRTVAR(Type, l_SEXPVariable, "enumeration", "SEXP Variable type, uses SEXPVAR_TYPE_* enumerations", "enumeration", "SEXPVAR_TYPE_* enumeration, or invalid numeration if handle is invalid")
+ADE_VIRTVAR(Type, l_SEXPVariable, "enumeration", "SEXP Variable value type, uses SEXPVAR_TYPE_* enumerations", "enumeration", "A SEXPVAR_TYPE_* enumeration, or invalid enumeration if handle is invalid")
{
sexpvar_h *svh = NULL;
enum_h *type = NULL;
diff --git a/code/scripting/api/objs/shields.cpp b/code/scripting/api/objs/shields.cpp
index c6c255e8e83..6485ac99e90 100644
--- a/code/scripting/api/objs/shields.cpp
+++ b/code/scripting/api/objs/shields.cpp
@@ -22,7 +22,7 @@ ADE_FUNC(__len, l_Shields, nullptr, "Number of shield segments", "number", "Numb
return ade_set_args(L, "i", static_cast(objh->objp()->shield_quadrant.size()));
}
-ADE_INDEXER(l_Shields, "enumeration/number", "Gets or sets shield segment strength. Use \"SHIELD_*\" enumerations (for standard 4-quadrant shields) or index of a specific segment, or NONE for the entire shield", "number", "Segment/shield strength, or 0 if handle is invalid")
+ADE_INDEXER(l_Shields, "enumeration/number", "Gets or sets shield segment strength. Use \"SHIELD_*\" enumerations (for standard 4-quadrant shields) or index of a specific segment, or SHIELD_NONE for the entire shield", "number", "Segment/shield strength, or 0 if handle is invalid")
{
object_h *objh;
float nval = -1.0f;
diff --git a/code/scripting/api/objs/ship.cpp b/code/scripting/api/objs/ship.cpp
index 3af4baf9697..e2a64ba444f 100644
--- a/code/scripting/api/objs/ship.cpp
+++ b/code/scripting/api/objs/ship.cpp
@@ -1332,8 +1332,8 @@ extern int sendMessage_sub(lua_State* L, const void* sender, int messageSource,
ADE_FUNC(sendMessage,
l_Ship,
- "message message, [number delay=0.0, enumeration priority = MESSAGE_PRIORITY_NORMAL]",
- "Sends a message from the given ship with the given priority.
"
+ "message message, [number delay=0.0, enumeration priority = MESSAGE_PRIORITY_NORMAL /* MESSAGE_PRIORITY_* */]",
+ "Sends a message from the given ship with the given MESSAGE_PRIORITY_* priority.
"
"If delay is specified, the message will be delayed by the specified time in seconds.",
"boolean",
"true if successful, false otherwise")
@@ -1690,7 +1690,7 @@ ADE_FUNC(clearOrders, l_Ship, NULL, "Clears a ship's orders list", "boolean", "T
return ADE_RETURN_TRUE;
}
-ADE_FUNC(giveOrder, l_Ship, "enumeration Order, [object Target=nil, subsystem TargetSubsystem=nil, number Priority=1.0, shipclass TargetShipclass=nil, shiptype TargetShiptype=nil]", "Uses the goal code to execute orders. NOTE: This function uses a scale from 0.0-1.0 (up to 2.0) rather than the usual 0-100 (up to 200)", "boolean", "True if order was given, otherwise false or nil")
+ADE_FUNC(giveOrder, l_Ship, "enumeration Order /* ORDER_* */, [object Target=nil, subsystem TargetSubsystem=nil, number Priority=1.0, shipclass TargetShipclass=nil, shiptype TargetShiptype=nil]", "Uses the goal code to execute orders. NOTE: This function uses a scale from 0.0-1.0 (up to 2.0) rather than the usual 0-100 (up to 200)", "boolean", "True if order was given, otherwise false or nil")
{
object_h *objh = NULL;
enum_h *eh = NULL;
diff --git a/code/scripting/api/objs/ship_registry_entry.cpp b/code/scripting/api/objs/ship_registry_entry.cpp
index d8aeabce01f..1b31821712e 100644
--- a/code/scripting/api/objs/ship_registry_entry.cpp
+++ b/code/scripting/api/objs/ship_registry_entry.cpp
@@ -41,7 +41,7 @@ ADE_FUNC(isValid, l_ShipRegistryEntry, nullptr, "Detects whether handle is valid
return ADE_RETURN_TRUE;
}
-ADE_VIRTVAR(Status, l_ShipRegistryEntry, nullptr, "Status of ship", "enumeration", "INVALID, NOT_YET_PRESENT, PRESENT, DEATH_ROLL, EXITED, or nil if handle is invalid")
+ADE_VIRTVAR(Status, l_ShipRegistryEntry, nullptr, "Status of ship", "enumeration", "A SHIP_STATUS_* enumeration, or nil if handle is invalid")
{
int idx;
if (!ade_get_args(L, "o", l_ShipRegistryEntry.Get(&idx)))
diff --git a/code/scripting/doc_html.cpp b/code/scripting/doc_html.cpp
index 9c47a0fea1b..d63657d23b4 100644
--- a/code/scripting/doc_html.cpp
+++ b/code/scripting/doc_html.cpp
@@ -1,7 +1,41 @@
#include "doc_html.h"
+#include "scripting/api/objs/enums.h"
+#include
namespace scripting {
namespace {
+SCP_string link_enum_group_references(const SCP_string& text) {
+ SCP_string out;
+ SCP_string token;
+ for (size_t i = 0; i <= text.size(); ++i) {
+ const auto ch = (i < text.size()) ? text[i] : ' ';
+ if (std::isalnum(static_cast(ch)) || ch == '_' || ch == '*') {
+ token.push_back(ch);
+ continue;
+ }
+ if (!token.empty()) {
+ SCP_string lookup = token;
+ while (!lookup.empty() && (lookup.back() == '*' || lookup.back() == ',' || lookup.back() == '.' || lookup.back() == ')' || lookup.back() == ']')) {
+ lookup.pop_back();
+ }
+ auto group = api::get_enum_group_info(lookup.c_str());
+ if (group) {
+ out += "id;
+ out += "\">";
+ out += token;
+ out += "";
+ } else {
+ out += token;
+ }
+ token.clear();
+ }
+ if (i < text.size()) {
+ out.push_back(ch);
+ }
+ }
+ return out;
+}
void ade_output_toc(FILE* fp, const std::unique_ptr& el)
{
@@ -25,8 +59,10 @@ void ade_output_toc(FILE* fp, const std::unique_ptr& el)
}
fputs("", fp);
- if (!el->description.empty())
- fprintf(fp, " - %s\n", el->description.c_str());
+ if (!el->description.empty()) {
+ auto description = link_enum_group_references(el->description);
+ fprintf(fp, " - %s\n", description.c_str());
+ }
fputs("\n", fp);
}
@@ -196,12 +232,12 @@ void output_argument_list(FILE* fp, const DocumentationElementFunction::argument
fprintf(fp, " %s", arg.name.c_str());
if (!arg.def_val.empty()) {
- fprintf(fp, " = %s", arg.def_val.c_str());
+ fprintf(fp, " = %s", link_enum_group_references(arg.def_val).c_str());
}
}
if (!arg.comment.empty()) {
- fprintf(fp, " (%s)", arg.comment.c_str());
+ fprintf(fp, " (%s)", link_enum_group_references(arg.comment).c_str());
}
}
@@ -209,7 +245,7 @@ void output_argument_list(FILE* fp, const DocumentationElementFunction::argument
fputs("]", fp);
}
} else {
- fprintf(fp, "%s", overload.simple.c_str());
+ fprintf(fp, "%s", link_enum_group_references(overload.simple).c_str());
}
}
@@ -285,7 +321,8 @@ void OutputElement(FILE* fp,
//***Description
if (!el->description.empty()) {
- fprintf(fp, "%s\n", el->description.c_str());
+ auto description = link_enum_group_references(el->description);
+ fprintf(fp, "%s\n", description.c_str());
}
break;
}
@@ -343,7 +380,8 @@ void OutputElement(FILE* fp,
//***Description
if (!el->description.empty()) {
- fprintf(fp, "%s\n", el->description.c_str());
+ auto description = link_enum_group_references(el->description);
+ fprintf(fp, "%s\n", description.c_str());
}
if (el->deprecationVersion.isValid()) {
@@ -365,7 +403,8 @@ void OutputElement(FILE* fp,
//***Result: ReturnDescription
if (!funcEl->returnDocumentation.empty()) {
- fprintf(fp, "Returns: %s\n", funcEl->returnDocumentation.c_str());
+ auto returns = link_enum_group_references(funcEl->returnDocumentation);
+ fprintf(fp, "Returns: %s\n", returns.c_str());
} else {
fputs("Returns: Nothing\n", fp);
}
@@ -395,11 +434,16 @@ void OutputElement(FILE* fp,
fputs("\n", fp);
//***Description
- if (!propEl->description.empty())
- fprintf(fp, "%s\n", propEl->description.c_str());
+ if (!propEl->description.empty()) {
+ auto description = link_enum_group_references(propEl->description);
+ fprintf(fp, "%s\n", description.c_str());
+ }
if (!propEl->returnDocumentation.empty())
- fprintf(fp, "Value: %s\n", propEl->returnDocumentation.c_str());
+ {
+ auto value = link_enum_group_references(propEl->returnDocumentation);
+ fprintf(fp, "Value: %s\n", value.c_str());
+ }
break;
}
default:
@@ -441,7 +485,7 @@ static void output_hook_variable_list(FILE* fp, const Container& vars)
fputs("", fp);
ade_output_type_link(fp, param.type);
fprintf(fp, " %s", param.name);
- fprintf(fp, "Description: %s", param.description);
+ fprintf(fp, "Description: %s", link_enum_group_references(param.description).c_str());
}
fputs("", fp);
}
@@ -561,13 +605,31 @@ void output_html_doc(const ScriptingDocumentation& doc, const SCP_string& filena
//***Enumerations
fprintf(fp, "Enumerations
");
+ SCP_unordered_map> enum_groups;
+ SCP_vector enum_group_order;
for (const auto& enumeration : doc.enumerations) {
- // Cyborg17 -- Omit the deprecated flag
- if (enumeration.name == "VM_EXTERNAL_CAMERA_LOCKED") {
- continue;
+ auto key = enumeration.group_id.empty() ? SCP_string("ungrouped") : enumeration.group_id;
+ if (enum_groups.find(key) == enum_groups.end()) {
+ enum_group_order.push_back(key);
+ }
+ enum_groups[key].push_back(&enumeration);
+ }
+ for (const auto& group_id : enum_group_order) {
+ const auto* first_enum = enum_groups[group_id].front();
+ const auto& group_title = first_enum->group_title.empty() ? SCP_string("Ungrouped Enumerations") : first_enum->group_title;
+ const auto& group_description = first_enum->group_description.empty() ? SCP_string("No group description found. Add a matching prefix entry to get_enum_group_info() in enums.cpp.") : first_enum->group_description;
+ fprintf(fp, "%s
", group_id.c_str(), group_title.c_str());
+ fprintf(fp, "%s", group_description.c_str());
+ fputs("", fp);
+ for (const auto* enumeration : enum_groups[group_id]) {
+ if (!enumeration->description.empty()) {
+ fprintf(fp, "- %s -; %s
",
+ enumeration->name.c_str(), enumeration->description.c_str());
+ } else {
+ fprintf(fp, "- %s
", enumeration->name.c_str());
+ }
}
- // WMC - For now, print to the file without the description.
- fprintf(fp, "- %s
", enumeration.name.c_str());
+ fputs("
", fp);
}
fputs("