From 7dc4be302f57bb729d9b2121ff1a9c3f0eba4394 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 16 Aug 2006 20:56:06 +0000 Subject: [PATCH] - Added action special support to the thingdef expression evaluator. Now you can use them like normal functions, which is probably most useful for ACS_ExecuteWithResult. SVN r294 (trunk) --- docs/rh-log.txt | 3 ++ src/thingdef.cpp | 23 +++++++++ src/thingdef.h | 3 ++ src/thingdef_exp.cpp | 108 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 123 insertions(+), 14 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index c9912dad77..88a3fc004b 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,7 @@ August 16, 2006 +- Added action special support to the thingdef expression evaluator. Now you + can use them like normal functions, which is probably most useful for + ACS_ExecuteWithResult. - Switched to IJG code for reading JPEG images. I have included a stripped- down version of the library with the ZDoom source. (It actually uses less space than zlib now.) Unix users probably ought to use the system-supplied diff --git a/src/thingdef.cpp b/src/thingdef.cpp index 92f29af8af..39e0a043ae 100644 --- a/src/thingdef.cpp +++ b/src/thingdef.cpp @@ -1306,6 +1306,29 @@ int FindLineSpecial(const char * string) return 0; } +//========================================================================== +// +// FindLineSpecialEx +// +// Like FindLineSpecial, but also returns the min and max argument count. +// +//========================================================================== + +int FindLineSpecialEx (const char *string, int *min_args, int *max_args) +{ + const ACSspecials *spec; + + spec = is_special(string, (unsigned int)strlen(string)); + if (spec != NULL) + { + *min_args = spec->MinArgs; + *max_args = MAX(spec->MinArgs, spec->MaxArgs); + return spec->Special; + } + *min_args = *max_args = 0; + return 0; +} + //========================================================================== // // DoSpecialFunctions diff --git a/src/thingdef.h b/src/thingdef.h index 4daad9d84f..7eb191da7e 100644 --- a/src/thingdef.h +++ b/src/thingdef.h @@ -57,6 +57,9 @@ enum }; +// The contents of string must be lowercase (for now, anyway) +int FindLineSpecialEx (const char *string, int *minargs, int *maxargs); + #endif diff --git a/src/thingdef_exp.cpp b/src/thingdef_exp.cpp index 54deb3fa07..23c8c2c957 100644 --- a/src/thingdef_exp.cpp +++ b/src/thingdef_exp.cpp @@ -46,6 +46,8 @@ #include "i_system.h" #include "m_random.h" #include "a_pickups.h" +#include "thingdef.h" +#include "p_lnspec.h" void InitExpressions (); void ClearExpressions (); @@ -87,6 +89,8 @@ enum ExpOp EX_Sin, // sin (angle) EX_Cos, // cos (angle) EX_InvCount, // invcount (type) + EX_ActionSpecial, + EX_Right, }; enum ExpValType @@ -251,12 +255,12 @@ struct ExpData Type = EX_NOP; Value.Type = VAL_Int; Value.Int = 0; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 2; i++) Children[i] = NULL; } ~ExpData () { - for (int i = 0; i < 3; i++) + for (int i = 0; i < 2; i++) { if (Children[i]) { @@ -287,12 +291,14 @@ struct ExpData if (Children[0]->Type == EX_Const) { bool cond = (Children[0]->Value.Type == VAL_Int) ? (Children[0]->Value.Int != 0) : (Children[0]->Value.Float != 0); - ExpData *data = Children[cond ? 1 : 2]; - delete Children[cond ? 2 : 1]; + ExpData *data = Children[1]->Children[cond]; + delete Children[1]->Children[!cond]; + delete Children[1]; + delete Children[0]; Type = data->Type; Value = data->Value; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 2; i++) { Children[i] = data->Children[i]; data->Children[i] = NULL; @@ -301,7 +307,7 @@ struct ExpData delete data; } } - else if (Type != EX_Random && Type != EX_Sin && Type != EX_Cos && Type != EX_InvCount) + else if (Type != EX_Random && Type != EX_Sin && Type != EX_Cos && Type != EX_InvCount && Type != EX_ActionSpecial) { if (Children[0]->Type == EX_Const && Children[1]->Type == EX_Const) { @@ -324,7 +330,7 @@ struct ExpData return false; } - for (int i = 0; i < 3; i++) + for (int i = 0; i < 2; i++) { if (Children[i] && !Children[i]->Compare (other->Children[i])) return false; @@ -335,7 +341,7 @@ struct ExpData ExpOp Type; ExpVal Value; - ExpData *Children[3]; + ExpData *Children[2]; }; TArray StateExpressions; @@ -402,10 +408,13 @@ static ExpData *ParseExpressionM () ExpData *data = new ExpData; data->Type = EX_Cond; data->Children[0] = tmp; - data->Children[1] = ParseExpressionM (); + ExpData *choices = new ExpData; + data->Children[1] = choices; + choices->Type = EX_Right; + choices->Children[0] = ParseExpressionM (); if (!SC_CheckString (":")) SC_ScriptError ("':' expected"); - data->Children[2] = ParseExpressionM (); + choices->Children[1] = ParseExpressionM (); data->EvalConst (); return data; } @@ -778,8 +787,47 @@ static ExpData *ParseExpressionA () } else { + int specnum, min_args, max_args; + SC_MustGetString (); + // Check if this is an action special + strlwr (sc_String); + specnum = FindLineSpecialEx (sc_String, &min_args, &max_args); + if (specnum != 0) + { + int i; + + if (!SC_CheckString ("(")) + SC_ScriptError ("'(' expected"); + + ExpData *data = new ExpData, **left; + data->Type = EX_ActionSpecial; + data->Value.Int = specnum; + + data->Children[0] = ParseExpressionM (); + left = &data->Children[1]; + + for (i = 1; i < 5 && SC_CheckString (","); ++i) + { + ExpData *right = new ExpData; + right->Type = EX_Right; + right->Children[0] = ParseExpressionM (); + *left = right; + left = &right->Children[1]; + } + *left = NULL; + if (!SC_CheckString (")")) + SC_ScriptError ("')' expected"); + if (i < min_args) + SC_ScriptError ("Not enough arguments to action special"); + if (i > max_args) + SC_ScriptError ("Too many arguments to action special"); + + return data; + } + + // Check if it's a variable we understand int varid = -1; for (size_t i = 0; i < countof(ExpVars); i++) { @@ -1363,10 +1411,10 @@ static ExpVal EvalExpression (ExpData *data, AActor *self) { ExpVal a = EvalExpression (data->Children[0], self); - if (a.Type == VAL_Int) - val = a.Int ? EvalExpression (data->Children[1], self) : EvalExpression (data->Children[2], self); - else - val = a.Float ? EvalExpression (data->Children[1], self) : EvalExpression (data->Children[2], self); + if (a.Type == VAL_Float) + a.Int = (int)a.Float; + + val = EvalExpression (data->Children[1]->Children[!!a.Int], self); } break; @@ -1442,6 +1490,38 @@ static ExpVal EvalExpression (ExpData *data, AActor *self) val.Int = item->Amount; } break; + + case EX_ActionSpecial: + { + int parms[5] = { 0, 0, 0, 0 }; + int i = 0; + ExpData *parm = data; + + while (parm != NULL && i < 5) + { + ExpVal val = EvalExpression (parm->Children[0], self); + if (val.Type == VAL_Int) + { + parms[i] = val.Int; + } + else + { + parms[i] = (int)val.Float; + } + i++; + parm = parm->Children[1]; + } + + val.Type = VAL_Int; + val.Int = LineSpecials[data->Value.Int] (NULL, self, false, + parms[0], parms[1], parms[2], parms[3], parms[4]); + } + break; + + case EX_Right: + // This should never be a top-level expression. + assert (data->Type != EX_Right); + break; } return val;