Skip to content

Commit 52455bb

Browse files
authored
Merge pull request #5009 from MjnMixael/dynamic_sexp_enum
Dynamic sexp enum
2 parents 76b301b + 25a4f66 commit 52455bb

File tree

9 files changed

+237
-114
lines changed

9 files changed

+237
-114
lines changed

code/parse/sexp.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,8 @@ sexp_ai_goal_link Sexp_ai_goal_links[] = {
889889
{ AI_GOAL_REARM_REPAIR, OP_AI_REARM_REPAIR },
890890
};
891891

892+
SCP_vector<dynamic_sexp_enum_list> Dynamic_enums;
893+
892894
void sexp_set_skybox_model_preload(const char *name); // taylor
893895
int Num_skybox_flags = 6;
894896
const char *Skybox_flags[] = {
@@ -3948,7 +3950,17 @@ int check_sexp_syntax(int node, int return_type, int recursive, int *bad_node, i
39483950
break;
39493951

39503952
default:
3951-
Error(LOCATION, "Unhandled argument format");
3953+
if (Dynamic_enums.size() > 0) {
3954+
if ((type - First_available_opf_id) < (int)Dynamic_enums.size()) {
3955+
if (type2 != SEXP_ATOM_STRING)
3956+
return SEXP_CHECK_TYPE_MISMATCH;
3957+
} else {
3958+
Error(LOCATION, "Unhandled argument format");
3959+
}
3960+
} else {
3961+
Error(LOCATION, "Unhandled argument format");
3962+
}
3963+
39523964
}
39533965

39543966
node = Sexp_nodes[node].rest;

code/parse/sexp.h

Lines changed: 116 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -27,109 +27,122 @@ struct ship_obj;
2727
#define MAX_SEXP_VARIABLES 250
2828

2929
// Operator argument formats (data types of an argument)
30-
#define OPF_NONE 1 // argument cannot exist at this position if it's this
31-
#define OPF_NULL 2 // no value. Can still be used for type matching, however
32-
#define OPF_BOOL 3
33-
#define OPF_NUMBER 4
34-
#define OPF_SHIP 5
35-
#define OPF_WING 6
36-
#define OPF_SUBSYSTEM 7
37-
#define OPF_POINT 8 // either a 3d point in space, or a waypoint name
38-
#define OPF_IFF 9
39-
#define OPF_AI_GOAL 10 // special to match ai goals
40-
#define OPF_DOCKER_POINT 11 // docking point on docker ship
41-
#define OPF_DOCKEE_POINT 12 // docking point on dockee ship
42-
#define OPF_MESSAGE 13 // the name (id) of a message in Messages[] array
43-
#define OPF_WHO_FROM 14 // who sent the message -- doesn't necessarily have to be a ship!!!
44-
#define OPF_PRIORITY 15 // priority for messages
45-
#define OPF_WAYPOINT_PATH 16 // name of a waypoint
46-
#define OPF_POSITIVE 17 // positive number or zero
47-
#define OPF_MISSION_NAME 18 // name of a mission for various mission related things
48-
#define OPF_SHIP_POINT 19 // a waypoint or a ship
49-
#define OPF_GOAL_NAME 20 // name of goal (or maybe event?) from a mission
50-
#define OPF_SHIP_WING 21 // either a ship or wing name (they don't conflict)
51-
#define OPF_SHIP_WING_WHOLETEAM 22 // Karajorma - Ship, wing or an entire team's worth of ships
52-
#define OPF_SHIP_WING_SHIPONTEAM_POINT 23 // name of a ship, wing, any ship on a team, or a point
53-
#define OPF_SHIP_WING_POINT 24
54-
#define OPF_SHIP_WING_POINT_OR_NONE 25 // WMC - Ship, wing, point or none
55-
#define OPF_SHIP_TYPE 26 // type of ship (fighter/bomber/etc)
56-
#define OPF_KEYPRESS 27 // a default key
57-
#define OPF_EVENT_NAME 28 // name of an event
58-
#define OPF_AI_ORDER 29 // a squadmsg order player can give to a ship
59-
#define OPF_SKILL_LEVEL 30 // current skill level of the game
60-
#define OPF_MEDAL_NAME 31 // name of medals
61-
#define OPF_WEAPON_NAME 32 // name of a weapon
62-
#define OPF_SHIP_CLASS_NAME 33 // name of a ship class
63-
#define OPF_CUSTOM_HUD_GAUGE 34 // name of custom HUD gauge
64-
#define OPF_HUGE_WEAPON 35 // name of a secondary bomb type weapon
65-
#define OPF_SHIP_NOT_PLAYER 36 // a ship, but not a player ship
66-
#define OPF_JUMP_NODE_NAME 37 // name of a jump node
67-
#define OPF_VARIABLE_NAME 38 // variable name
68-
#define OPF_AMBIGUOUS 39 // type used with variable
69-
#define OPF_AWACS_SUBSYSTEM 40 // an awacs subsystem
70-
#define OPF_CARGO 41 // Goober5000 - a cargo string (currently used for set-cargo and is-cargo)
71-
#define OPF_AI_CLASS 42 // Goober5000 - an AI class
72-
#define OPF_SUPPORT_SHIP_CLASS 43 // Goober5000 - a support ship class
73-
#define OPF_ARRIVAL_LOCATION 44 // Goober5000 - a ship arrival location
74-
#define OPF_ARRIVAL_ANCHOR_ALL 45 // Goober5000 - all of a ship's possible arrival anchors
75-
#define OPF_DEPARTURE_LOCATION 46 // Goober5000 - a ship departure location
76-
#define OPF_SHIP_WITH_BAY 47 // Goober5000 - a ship with a fighter bay
77-
#define OPF_SOUNDTRACK_NAME 48 // Goober5000 - the name of a music soundtrack
78-
#define OPF_INTEL_NAME 49 // Goober5000 - the name of an intel entry in species.tbl
79-
#define OPF_STRING 50 // Goober5000 - any old string
80-
#define OPF_ROTATING_SUBSYSTEM 51 // Goober5000 - a rotating subsystem
81-
#define OPF_NAV_POINT 52 // Kazan - a Nav Point name
82-
#define OPF_SSM_CLASS 53 // Goober5000 - an SSM class
83-
#define OPF_FLEXIBLE_ARGUMENT 54 // Goober5000 - special to match for when-argument
84-
#define OPF_ANYTHING 55 // Goober5000 - anything goes, except containers
85-
#define OPF_SKYBOX_MODEL_NAME 56 // taylor - changing skybox model
86-
#define OPF_SHIP_OR_NONE 57 // Goober5000 - an "optional" ship argument
87-
#define OPF_BACKGROUND_BITMAP 58 // phreak - name of a background bitmap
88-
#define OPF_SUN_BITMAP 59 // phreak - name of a background bitmap
89-
#define OPF_NEBULA_STORM_TYPE 60 // phreak - name a nebula storm
90-
#define OPF_NEBULA_POOF 61 // phreak - name of a nebula poof
91-
#define OPF_TURRET_TARGET_ORDER 62 // WMC - name of a turret target type (see aiturret.cpp)
92-
#define OPF_SUBSYSTEM_OR_NONE 63 // Goober5000 - an "optional" subsystem argument
93-
#define OPF_PERSONA 64 // Karajorma - name of a persona
94-
#define OPF_SUBSYS_OR_GENERIC 65 // Karajorma - a subsystem or a generic name (like engine) which covers all subsystems of that type
95-
#define OPF_ORDER_RECIPIENT 66 // Karajorma - since orders can go to All Fighters as well as a ship or wing
96-
#define OPF_SUBSYSTEM_TYPE 67 // Goober5000 - a generic subsystem type (navigation, engines, etc.) rather than a specific subsystem
97-
#define OPF_POST_EFFECT 68 // Hery - type of post-processing effect
98-
#define OPF_TARGET_PRIORITIES 69 // FUBAR - Target priority groups
99-
#define OPF_ARMOR_TYPE 70 // FUBAR - Armor type or <none>
100-
#define OPF_FONT 71 // Goober5000 - a FreeSpace font
101-
#define OPF_HUD_ELEMENT 72 // A magic name of a specific HUD element
102-
#define OPF_SOUND_ENVIRONMENT 73 // Goober5000 - one of EFX_presets, per Taylor
103-
#define OPF_SOUND_ENVIRONMENT_OPTION 74 // Goober5000 - one of Taylor's options
104-
#define OPF_EXPLOSION_OPTION 75 // Goober5000
105-
#define OPF_AUDIO_VOLUME_OPTION 76 // The E
106-
#define OPF_WEAPON_BANK_NUMBER 77 // Karajorma - The number of a primary/secondary/tertiary weapon bank or all of them
107-
#define OPF_MESSAGE_OR_STRING 78 // Goober5000 - provides a list of messages like OPF_MESSAGE, but also allows entering arbitrary strings
108-
#define OPF_BUILTIN_HUD_GAUGE 79 // The E
109-
#define OPF_DAMAGE_TYPE 80 // FUBAR - Damage type or <none>
110-
#define OPF_SHIP_EFFECT 81 // The E - per-ship effects, as defined in post-processing.tbl
111-
#define OPF_ANIMATION_TYPE 82 // Goober5000 - as defined in modelanim.h
112-
#define OPF_MISSION_MOOD 83 // Karajorma - Moods determine which builtin messages will be sent
113-
#define OPF_SHIP_FLAG 84 // Karajorma - The name of a ship flag
114-
#define OPF_TEAM_COLOR 85 // The E - Color settings as defined in Colors.tbl
115-
#define OPF_NEBULA_PATTERN 86 // Axem - Full Nebula Background Patterns, as defined in nebula.tbl
116-
#define OPF_SKYBOX_FLAGS 87 // niffiwan - valid skybox flags
117-
#define OPF_GAME_SND 88 // m!m - A game sound
118-
#define OPF_FIREBALL 89 // Goober5000 - an entry in fireball.tbl
119-
#define OPF_SPECIES 90 // Goober5000
120-
#define OPF_LANGUAGE 91 // Goober5000
121-
#define OPF_FUNCTIONAL_WHEN_EVAL_TYPE 92 // Goober5000
122-
#define OPF_CONTAINER_NAME 93 // Karajorma/jg18 - The name of a SEXP container
123-
#define OPF_LIST_CONTAINER_NAME 94 // Karajorma/jg18 - The name of a SEXP list container
124-
#define OPF_MAP_CONTAINER_NAME 95 // Karajorma/jg18 - The name of a SEXP map container
125-
#define OPF_ANIMATION_NAME 96 // Lafiel
126-
#define OPF_CONTAINER_VALUE 97 // jg18 - Container data and map container keys
127-
#define OPF_DATA_OR_STR_CONTAINER 98 // jg18 - any data, or a container that is accessed via strings
128-
#define OPF_TRANSLATING_SUBSYSTEM 99 // Goober5000 - a translating subsystem
129-
#define OPF_ANY_HUD_GAUGE 100 // Goober5000 - both custom and builtin
130-
#define OPF_WING_FLAG 101 // Goober5000 - The name of a wing flag
131-
#define OPF_ASTEROID_DEBRIS 102 // MjnMixael - Debris types as defined in asteroids.tbl
132-
#define OPF_WING_FORMATION 103 // Goober5000 - as defined in ships.tbl
30+
enum : int {
31+
OPF_UNUSED, // argument types need to start at 1 instead of 0
32+
OPF_NONE, // argument cannot exist at this position if it's this
33+
OPF_NULL, // no value. Can still be used for type matching, however
34+
OPF_BOOL,
35+
OPF_NUMBER,
36+
OPF_SHIP,
37+
OPF_WING,
38+
OPF_SUBSYSTEM,
39+
OPF_POINT, // either a 3d point in space, or a waypoint name
40+
OPF_IFF,
41+
OPF_AI_GOAL, // special to match ai goals
42+
OPF_DOCKER_POINT, // docking point on docker ship
43+
OPF_DOCKEE_POINT, // docking point on dockee ship
44+
OPF_MESSAGE, // the name (id) of a message in Messages[] array
45+
OPF_WHO_FROM, // who sent the message -- doesn't necessarily have to be a ship!!!
46+
OPF_PRIORITY, // priority for messages
47+
OPF_WAYPOINT_PATH, // name of a waypoint
48+
OPF_POSITIVE, // positive number or zero
49+
OPF_MISSION_NAME, // name of a mission for various mission related things
50+
OPF_SHIP_POINT, // a waypoint or a ship
51+
OPF_GOAL_NAME, // name of goal (or maybe event?) from a mission
52+
OPF_SHIP_WING, // either a ship or wing name (they don't conflict)
53+
OPF_SHIP_WING_WHOLETEAM, // Karajorma - Ship, wing or an entire team's worth of ships
54+
OPF_SHIP_WING_SHIPONTEAM_POINT, // name of a ship, wing, any ship on a team, or a point
55+
OPF_SHIP_WING_POINT,
56+
OPF_SHIP_WING_POINT_OR_NONE, // WMC - Ship, wing, point or none
57+
OPF_SHIP_TYPE, // type of ship (fighter/bomber/etc)
58+
OPF_KEYPRESS, // a default key
59+
OPF_EVENT_NAME, // name of an event
60+
OPF_AI_ORDER, // a squadmsg order player can give to a ship
61+
OPF_SKILL_LEVEL, // current skill level of the game
62+
OPF_MEDAL_NAME, // name of medals
63+
OPF_WEAPON_NAME, // name of a weapon
64+
OPF_SHIP_CLASS_NAME, // name of a ship class
65+
OPF_CUSTOM_HUD_GAUGE, // name of custom HUD gauge
66+
OPF_HUGE_WEAPON, // name of a secondary bomb type weapon
67+
OPF_SHIP_NOT_PLAYER, // a ship, but not a player ship
68+
OPF_JUMP_NODE_NAME, // name of a jump node
69+
OPF_VARIABLE_NAME, // variable name
70+
OPF_AMBIGUOUS, // type used with variable
71+
OPF_AWACS_SUBSYSTEM, // an awacs subsystem
72+
OPF_CARGO, // Goober5000 - a cargo string (currently used for set-cargo and is-cargo)
73+
OPF_AI_CLASS, // Goober5000 - an AI class
74+
OPF_SUPPORT_SHIP_CLASS, // Goober5000 - a support ship class
75+
OPF_ARRIVAL_LOCATION, // Goober5000 - a ship arrival location
76+
OPF_ARRIVAL_ANCHOR_ALL, // Goober5000 - all of a ship's possible arrival anchors
77+
OPF_DEPARTURE_LOCATION, // Goober5000 - a ship departure location
78+
OPF_SHIP_WITH_BAY, // Goober5000 - a ship with a fighter bay
79+
OPF_SOUNDTRACK_NAME, // Goober5000 - the name of a music soundtrack
80+
OPF_INTEL_NAME, // Goober5000 - the name of an intel entry in species.tbl
81+
OPF_STRING, // Goober5000 - any old string
82+
OPF_ROTATING_SUBSYSTEM, // Goober5000 - a rotating subsystem
83+
OPF_NAV_POINT, // Kazan - a Nav Point name
84+
OPF_SSM_CLASS, // Goober5000 - an SSM class
85+
OPF_FLEXIBLE_ARGUMENT, // Goober5000 - special to match for when-argument
86+
OPF_ANYTHING, // Goober5000 - anything goes, except containers
87+
OPF_SKYBOX_MODEL_NAME, // taylor - changing skybox model
88+
OPF_SHIP_OR_NONE, // Goober5000 - an "optional" ship argument
89+
OPF_BACKGROUND_BITMAP, // phreak - name of a background bitmap
90+
OPF_SUN_BITMAP, // phreak - name of a background bitmap
91+
OPF_NEBULA_STORM_TYPE, // phreak - name a nebula storm
92+
OPF_NEBULA_POOF, // phreak - name of a nebula poof
93+
OPF_TURRET_TARGET_ORDER, // WMC - name of a turret target type (see aiturret.cpp)
94+
OPF_SUBSYSTEM_OR_NONE, // Goober5000 - an "optional" subsystem argument
95+
OPF_PERSONA, // Karajorma - name of a persona
96+
OPF_SUBSYS_OR_GENERIC, // Karajorma - a subsystem or a generic name (like engine) which covers all subsystems of that type
97+
OPF_ORDER_RECIPIENT, // Karajorma - since orders can go to All Fighters as well as a ship or wing
98+
OPF_SUBSYSTEM_TYPE, // Goober5000 - a generic subsystem type (navigation, engines, etc.) rather than a specific subsystem
99+
OPF_POST_EFFECT, // Hery - type of post-processing effect
100+
OPF_TARGET_PRIORITIES, // FUBAR - Target priority groups
101+
OPF_ARMOR_TYPE, // FUBAR - Armor type or <none>
102+
OPF_FONT, // Goober5000 - a FreeSpace font
103+
OPF_HUD_ELEMENT, // A magic name of a specific HUD element
104+
OPF_SOUND_ENVIRONMENT, // Goober5000 - one of EFX_presets, per Taylor
105+
OPF_SOUND_ENVIRONMENT_OPTION, // Goober5000 - one of Taylor's options
106+
OPF_EXPLOSION_OPTION, // Goober5000
107+
OPF_AUDIO_VOLUME_OPTION, // The E
108+
OPF_WEAPON_BANK_NUMBER, // Karajorma - The number of a primary/secondary/tertiary weapon bank or all of them
109+
OPF_MESSAGE_OR_STRING, // Goober5000 - provides a list of messages like OPF_MESSAGE, but also allows entering arbitrary strings
110+
OPF_BUILTIN_HUD_GAUGE, // The E
111+
OPF_DAMAGE_TYPE, // FUBAR - Damage type or <none>
112+
OPF_SHIP_EFFECT, // The E - per-ship effects, as defined in post-processing.tbl
113+
OPF_ANIMATION_TYPE, // Goober5000 - as defined in modelanim.h
114+
OPF_MISSION_MOOD, // Karajorma - Moods determine which builtin messages will be sent
115+
OPF_SHIP_FLAG, // Karajorma - The name of a ship flag
116+
OPF_TEAM_COLOR, // The E - Color settings as defined in Colors.tbl
117+
OPF_NEBULA_PATTERN, // Axem - Full Nebula Background Patterns, as defined in nebula.tbl
118+
OPF_SKYBOX_FLAGS, // niffiwan - valid skybox flags
119+
OPF_GAME_SND, // m!m - A game sound
120+
OPF_FIREBALL, // Goober5000 - an entry in fireball.tbl
121+
OPF_SPECIES, // Goober5000
122+
OPF_LANGUAGE, // Goober5000
123+
OPF_FUNCTIONAL_WHEN_EVAL_TYPE, // Goober5000
124+
OPF_CONTAINER_NAME, // Karajorma/jg18 - The name of a SEXP container
125+
OPF_LIST_CONTAINER_NAME, // Karajorma/jg18 - The name of a SEXP list container
126+
OPF_MAP_CONTAINER_NAME, // Karajorma/jg18 - The name of a SEXP map container
127+
OPF_ANIMATION_NAME, // Lafiel
128+
OPF_CONTAINER_VALUE, // jg18 - Container data and map container keys
129+
OPF_DATA_OR_STR_CONTAINER, // jg18 - any data, or a container that is accessed via strings
130+
OPF_TRANSLATING_SUBSYSTEM, // Goober5000 - a translating subsystem
131+
OPF_ANY_HUD_GAUGE, // Goober5000 - both custom and builtin
132+
OPF_WING_FLAG, // Goober5000 - The name of a wing flag
133+
OPF_ASTEROID_DEBRIS, // MjnMixael - Debris types as defined in asteroids.tbl
134+
OPF_WING_FORMATION, // Goober5000 - as defined in ships.tbl
135+
136+
//Must always be at the end of the list
137+
First_available_opf_id
138+
};
139+
140+
struct dynamic_sexp_enum_list {
141+
SCP_string name;
142+
SCP_vector<SCP_string> list;
143+
};
144+
145+
extern SCP_vector<dynamic_sexp_enum_list> Dynamic_enums;
133146

134147
// Operand return types
135148
#define OPR_NUMBER 1 // returns number

code/parse/sexp/LuaSEXP.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ static SCP_unordered_map<SCP_string, int> parameter_type_mapping{{ "boolean",
4545
{ "ship+wing+team", OPF_SHIP_WING_WHOLETEAM },
4646
{ "ship+wing+ship_on_team+waypoint", OPF_SHIP_WING_SHIPONTEAM_POINT },
4747
{ "ship+wing+waypoint", OPF_SHIP_WING_POINT },
48-
{ "ship+wing+waypoint+none", OPF_SHIP_WING_POINT_OR_NONE }, };
48+
{ "ship+wing+waypoint+none", OPF_SHIP_WING_POINT_OR_NONE },
49+
{ "enum", First_available_opf_id } };
4950

5051
std::pair<SCP_string, int> LuaSEXP::get_parameter_type(const SCP_string& name)
5152
{
@@ -245,8 +246,14 @@ luacpp::LuaValue LuaSEXP::sexpToLua(int node, int argnum) const {
245246
return LuaValue::createValue(_action.getLuaState(), l_OSWPT.Set(oswpt));
246247
}
247248
default:
248-
UNREACHABLE("Unhandled argument type! Someone added an argument type but didn't add handling code to execute().");
249-
return LuaValue::createNil(_action.getLuaState());
249+
if ((strcmp(argtype.first.c_str(), "enum")) == 0) {
250+
auto text = CTEXT(node);
251+
return LuaValue::createValue(_action.getLuaState(), text);
252+
} else {
253+
UNREACHABLE(
254+
"Unhandled argument type! Someone added an argument type but didn't add handling code to execute().");
255+
return LuaValue::createNil(_action.getLuaState());
256+
}
250257
}
251258
}
252259
int LuaSEXP::getSexpReturnValue(const LuaValueList& retVals) const {
@@ -518,6 +525,33 @@ void LuaSEXP::parseTable() {
518525
type = get_parameter_type("string");
519526
}
520527

528+
if ((strcmp(type.first.c_str(), "enum")) == 0) {
529+
type.second = increment_enum_list_id();
530+
required_string("+Enum Name:");
531+
532+
SCP_string enum_name;
533+
stuff_string(enum_name, F_NAME);
534+
535+
dynamic_sexp_enum_list thisList;
536+
thisList.name = enum_name;
537+
538+
SCP_vector<SCP_string> list_items;
539+
while (optional_string("+Enum:")) {
540+
SCP_string item;
541+
stuff_string(item, F_NAME);
542+
list_items.push_back(item);
543+
}
544+
545+
if ((int)list_items.size() > 0) {
546+
thisList.list = std::move(list_items);
547+
} else {
548+
thisList.list.push_back("<none>");
549+
}
550+
551+
Dynamic_enums.push_back(thisList);
552+
553+
}
554+
521555
if (variable_arg_part) {
522556
_varargs_type_pattern.push_back(type);
523557
} else {

code/parse/sexp/sexp_lookup.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct global_state {
2828
int next_free_operator_id = First_available_operator_id;
2929
int next_free_category_id = First_available_category_id;
3030
int next_free_subcategory_id = First_available_subcategory_id;
31+
int next_free_enum_list_id = First_available_opf_id;
3132
};
3233

3334
// Static initialization to avoid initialization order issues
@@ -198,8 +199,13 @@ DynamicSEXP* get_dynamic_sexp(int operator_const)
198199

199200
return iter->second.get();
200201
}
201-
int get_category_of_subcategory(int subcategory_id)
202+
int increment_enum_list_id()
202203
{
204+
auto& global = globals();
205+
return global.next_free_enum_list_id++;
206+
}
207+
int get_category_of_subcategory(int subcategory_id)
208+
{
203209
const auto& global = globals();
204210

205211
auto iter = global.subcategory_to_category.find(subcategory_id);

code/parse/sexp/sexp_lookup.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ int get_category_of_subcategory(int subcategory_id);
4444
*/
4545
int add_category(const SCP_string& name);
4646

47+
int increment_enum_list_id();
48+
4749
/**
4850
* @brief Dynamically add a new subcategory to the SEXP system
4951
*

0 commit comments

Comments
 (0)