Skip to content

Commit fd2ebaf

Browse files
Goober5000claude
andauthored
allow -1 sound index in OPF_GAME_SND syntax check (#7540)
The numeric branch of the OPF_GAME_SND check in check_sexp_syntax never actually ran until the type2 variable-overload bug was fixed, so missions using a sound index of -1 ("no sound" / "default") loaded fine. Now that the check is live, explicitly allow -1, which the runtime already treats as an invalid (unset) sound. Also return the more descriptive SEXP_CHECK_INVALID_GAME_SND / SEXP_CHECK_INVALID_FIREBALL error codes, and let nested-operator (SEXP_ATOM_LIST) arguments fall through since their type is already validated upstream. Also route the Lua SEXP soundentry argument through sexp_get_sound_index so it accepts a table index, an operator, or a name like the core SEXPs do, instead of only a name. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent d5093cf commit fd2ebaf

3 files changed

Lines changed: 19 additions & 14 deletions

File tree

code/parse/sexp.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3970,36 +3970,38 @@ int check_sexp_syntax(int node, int desired_return_type, int recursive, int *bad
39703970
case OPF_GAME_SND:
39713971
if (node_subtype == SEXP_ATOM_NUMBER)
39723972
{
3973-
if (!gamesnd_get_by_tbl_index(atoi(CTEXT(node))).isValid())
3974-
{
3975-
return SEXP_CHECK_NUM_RANGE_INVALID;
3976-
}
3973+
int node_num = atoi(CTEXT(node));
3974+
if (node_num == -1)
3975+
break; // explicitly allow a sound of -1, indicating either "no sound" or "default"
3976+
if (!gamesnd_get_by_tbl_index(node_num).isValid())
3977+
return SEXP_CHECK_INVALID_GAME_SND;
39773978
}
39783979
else if (node_subtype == SEXP_ATOM_STRING)
39793980
{
3980-
if (stricmp(CTEXT(node), SEXP_NONE_STRING) != 0 && !gamesnd_get_by_name(CTEXT(node)).isValid())
3981-
{
3981+
auto node_text = CTEXT(node);
3982+
if (stricmp(node_text, SEXP_NONE_STRING) == 0)
3983+
break; // explicitly allow "no sound", although some sexps might interpret it as "default"
3984+
if (!gamesnd_get_by_name(node_text).isValid())
39823985
return SEXP_CHECK_INVALID_GAME_SND;
3983-
}
39843986
}
3987+
else if (node_subtype != SEXP_ATOM_LIST)
3988+
return SEXP_CHECK_INVALID_GAME_SND;
39853989
break;
39863990

39873991
case OPF_FIREBALL:
39883992
if (node_subtype == SEXP_ATOM_NUMBER || can_construe_as_integer(CTEXT(node)))
39893993
{
39903994
int num = atoi(CTEXT(node));
39913995
if (!SCP_vector_inbounds(Fireball_info, num))
3992-
{
3993-
return SEXP_CHECK_NUM_RANGE_INVALID;
3994-
}
3996+
return SEXP_CHECK_INVALID_FIREBALL;
39953997
}
39963998
else if (node_subtype == SEXP_ATOM_STRING)
39973999
{
39984000
if (fireball_info_lookup(CTEXT(node)) < 0)
3999-
{
40004001
return SEXP_CHECK_INVALID_FIREBALL;
4001-
}
40024002
}
4003+
else if (node_subtype != SEXP_ATOM_LIST)
4004+
return SEXP_CHECK_INVALID_FIREBALL;
40034005
break;
40044006

40054007
case OPF_SPECIES:

code/parse/sexp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class object;
2525
class waypoint;
2626
class p_object;
2727
struct ship_obj;
28+
class gamesnd_id;
2829

2930
// bumped to 30 by Goober5000
3031
#define OPERATOR_LENGTH 30 // if this ever exceeds TOKEN_LENGTH, let JasonH know!
@@ -1481,6 +1482,7 @@ extern int run_sexp(const char* sexpression, bool run_eval_num = false, bool *is
14811482
extern int stuff_sexp_variable_list();
14821483
extern int eval_sexp(int cur_node, int referenced_node = -1);
14831484
extern int eval_num(int n, bool &is_nan, bool &is_nan_forever);
1485+
extern gamesnd_id sexp_get_sound_index(int node);
14841486
extern bool is_sexp_true(int cur_node, int referenced_node = -1);
14851487
extern bool map_opf_to_opr(sexp_opf_t opf_type, sexp_opr_t &opr_type);
14861488
const char *opr_type_name(sexp_opr_t opr_type);

code/parse/sexp/LuaSEXP.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,9 @@ luacpp::LuaValue LuaSEXP::sexpToLua(int node, int argnum, int parent_node) const
262262
return LuaValue::createValue(_action.getLuaState(), l_Weaponclass.Set(weapon_info_lookup(name)));
263263
}
264264
case OPF_GAME_SND: {
265-
auto name = CTEXT(node);
266-
return LuaValue::createValue(_action.getLuaState(), l_SoundEntry.Set(sound_entry_h(gamesnd_get_by_name(name))));
265+
// handle a table index, an operator, or a name (matching what the core SEXPs accept);
266+
// -1 or <none> yields an invalid handle that the script can check with :isValid()
267+
return LuaValue::createValue(_action.getLuaState(), l_SoundEntry.Set(sound_entry_h(sexp_get_sound_index(node))));
267268
}
268269
case OPF_STRING: {
269270
auto text = CTEXT(node);

0 commit comments

Comments
 (0)