/* ** thingdef_exp.cpp ** ** Expression parsing / runtime evaluating support ** **--------------------------------------------------------------------------- ** Copyright 2005 Jan Cholasta ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions ** are met: ** ** 1. Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** 2. Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** 3. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be ** covered by the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or (at ** your option) any later version. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** */ #include "actor.h" #include "sc_man.h" #include "tarray.h" #include "templates.h" #include "vectors.h" #include "cmdlib.h" #include "i_system.h" #include "m_random.h" #include "a_pickups.h" #include "thingdef.h" #include "p_lnspec.h" void InitExpressions (); void ClearExpressions (); static FRandom pr_exrandom ("EX_Random"); enum ExpOp { EX_NOP, EX_Const, EX_Var, EX_Compl, // ~exp EX_Not, // !exp // EX_Plus, // +exp EX_Minus, // -exp EX_Mul, // exp * exp EX_Div, // exp / exp EX_Mod, // exp % exp EX_Add, // exp + exp EX_Sub, // exp - exp EX_LShift, // exp << exp EX_RShift, // exp >> exp EX_LT, // exp < exp EX_GT, // exp > exp EX_LE, // exp <= exp EX_GE, // exp >= exp EX_Eq, // exp == exp EX_NE, // exp != exp EX_And, // exp & exp EX_Xor, // exp ^ exp EX_Or, // exp | exp EX_LogAnd, // exp && exp EX_LogOr, // exp || exp EX_Cond, // exp ? exp : exp EX_Random, // random (min, max) EX_Sin, // sin (angle) EX_Cos, // cos (angle) EX_InvCount, // invcount (type) EX_ActionSpecial, EX_Right, }; enum ExpValType { VAL_Int, VAL_Float, }; struct ExpVal { ExpValType Type; union { int Int; float Float; }; }; typedef ExpVal (*ExpVarGet) (AActor *, int); ExpVal GetAlpha (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; val.Float = FIXED2FLOAT (actor->alpha); return val; } ExpVal GetAngle (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; val.Float = (float)actor->angle / ANGLE_1; return val; } ExpVal GetArgs (AActor *actor, int id) { ExpVal val; val.Type = VAL_Int; val.Int = actor->args[id]; return val; } ExpVal GetCeilingZ (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; val.Float = FIXED2FLOAT (actor->ceilingz); return val; } ExpVal GetFloorZ (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; val.Float = FIXED2FLOAT (actor->floorz); return val; } ExpVal GetHealth (AActor *actor, int id) { ExpVal val; val.Type = VAL_Int; val.Int = actor->health; return val; } ExpVal GetPitch (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; val.Float = (float)actor->pitch / ANGLE_1; return val; } ExpVal GetSpecial (AActor *actor, int id) { ExpVal val; val.Type = VAL_Int; val.Int = actor->special; return val; } ExpVal GetTID (AActor *actor, int id) { ExpVal val; val.Type = VAL_Int; val.Int = actor->tid; return val; } ExpVal GetTIDToHate (AActor *actor, int id) { ExpVal val; val.Type = VAL_Int; val.Int = actor->TIDtoHate; return val; } ExpVal GetWaterLevel (AActor *actor, int id) { ExpVal val; val.Type = VAL_Int; val.Int = actor->waterlevel; return val; } ExpVal GetX (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; val.Float = FIXED2FLOAT (actor->x); return val; } ExpVal GetY (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; val.Float = FIXED2FLOAT (actor->y); return val; } ExpVal GetZ (AActor *actor, int id) { ExpVal val; val.Type = VAL_Float; val.Float = FIXED2FLOAT (actor->z); return val; } static struct FExpVar { const char *name; // identifier int array; // array size (0 if not an array) ExpVarGet get; } ExpVars[] = { { "alpha", 0, GetAlpha }, { "angle", 0, GetAngle }, { "args", 5, GetArgs }, { "ceilingz", 0, GetCeilingZ }, { "floorz", 0, GetFloorZ }, { "health", 0, GetHealth }, { "pitch", 0, GetPitch }, { "special", 0, GetSpecial }, { "tid", 0, GetTID }, { "tidtohate", 0, GetTIDToHate }, { "waterlevel", 0, GetWaterLevel }, { "x", 0, GetX }, { "y", 0, GetY }, { "z", 0, GetZ }, }; struct ExpData; static ExpVal EvalExpression (ExpData *data, AActor *self); struct ExpData { ExpData () { Type = EX_NOP; Value.Type = VAL_Int; Value.Int = 0; for (int i = 0; i < 2; i++) Children[i] = NULL; } ~ExpData () { for (int i = 0; i < 2; i++) { if (Children[i]) { if (Type == EX_InvCount) free (Children[i]); else delete Children[i]; } } } // Try to evaluate constant expression void EvalConst () { if (Type == EX_NOP || Type == EX_Const || Type == EX_Var) { return; } else if (Type == EX_Compl || Type == EX_Not || /*Type == EX_Plus || */Type == EX_Minus) { if (Children[0]->Type == EX_Const) { Value = EvalExpression (this, NULL); Type = EX_Const; } } else if (Type == EX_Cond) { 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[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 < 2; i++) { Children[i] = data->Children[i]; data->Children[i] = NULL; } delete data; } } 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) { Value = EvalExpression (this, NULL); Type = EX_Const; delete Children[0]; delete Children[1]; } } } bool Compare (ExpData *other) { if (!other) return false; if (Type != other->Type || Value.Type != other->Value.Type || Value.Float != other->Value.Float) { return false; } for (int i = 0; i < 2; i++) { if (Children[i] && !Children[i]->Compare (other->Children[i])) return false; } return true; } ExpOp Type; ExpVal Value; ExpData *Children[2]; }; TArray StateExpressions; // // ParseExpression // [GRB] Parses an expression and stores it into Expression array // static ExpData *ParseExpressionM (); static ExpData *ParseExpressionL (); static ExpData *ParseExpressionK (); static ExpData *ParseExpressionJ (); static ExpData *ParseExpressionI (); static ExpData *ParseExpressionH (); static ExpData *ParseExpressionG (); static ExpData *ParseExpressionF (); static ExpData *ParseExpressionE (); static ExpData *ParseExpressionD (); static ExpData *ParseExpressionC (); static ExpData *ParseExpressionB (); static ExpData *ParseExpressionA (); int ParseExpression (bool _not) { static bool inited=false; if (!inited) { InitExpressions (); atterm (ClearExpressions); inited=true; } ExpData *data = ParseExpressionM (); if (_not) { ExpData *tmp = data; data = new ExpData; data->Type = EX_Not; data->Children[0] = tmp; data->EvalConst (); } for (unsigned int i = 0; i < StateExpressions.Size (); i++) { if (StateExpressions[i]->Compare (data)) { delete data; return i; } } return StateExpressions.Push (data); } static ExpData *ParseExpressionM () { ExpData *tmp = ParseExpressionL (); if (SC_CheckString ("?")) { ExpData *data = new ExpData; data->Type = EX_Cond; data->Children[0] = tmp; ExpData *choices = new ExpData; data->Children[1] = choices; choices->Type = EX_Right; choices->Children[0] = ParseExpressionM (); if (!SC_CheckString (":")) SC_ScriptError ("':' expected"); choices->Children[1] = ParseExpressionM (); data->EvalConst (); return data; } else { return tmp; } } static ExpData *ParseExpressionL () { ExpData *tmp = ParseExpressionK (); if (SC_CheckString ("||")) { ExpData *data = new ExpData; data->Type = EX_LogOr; data->Children[0] = tmp; data->Children[1] = ParseExpressionL (); data->EvalConst (); return data; } else { return tmp; } } static ExpData *ParseExpressionK () { ExpData *tmp = ParseExpressionJ (); if (SC_CheckString ("&&")) { ExpData *data = new ExpData; data->Type = EX_LogAnd; data->Children[0] = tmp; data->Children[1] = ParseExpressionK (); data->EvalConst (); return data; } else { return tmp; } } static ExpData *ParseExpressionJ () { ExpData *tmp = ParseExpressionI (); if (SC_CheckString ("|")) { ExpData *data = new ExpData; data->Type = EX_Or; data->Children[0] = tmp; data->Children[1] = ParseExpressionJ (); data->EvalConst (); return data; } else { return tmp; } } static ExpData *ParseExpressionI () { ExpData *tmp = ParseExpressionH (); if (SC_CheckString ("^")) { ExpData *data = new ExpData; data->Type = EX_Xor; data->Children[0] = tmp; data->Children[1] = ParseExpressionI (); data->EvalConst (); return data; } else { return tmp; } } static ExpData *ParseExpressionH () { ExpData *tmp = ParseExpressionG (); if (SC_CheckString ("&")) { ExpData *data = new ExpData; data->Type = EX_And; data->Children[0] = tmp; data->Children[1] = ParseExpressionH (); data->EvalConst (); return data; } else { return tmp; } } static ExpData *ParseExpressionG () { ExpData *tmp = ParseExpressionF (); ExpData *data = new ExpData; if (SC_CheckString ("==")) { data->Type = EX_Eq; } else if (SC_CheckString ("==")) { data->Type = EX_NE; } else { delete data; return tmp; } data->Children[0] = tmp; data->Children[1] = ParseExpressionG (); data->EvalConst (); return data; } static ExpData *ParseExpressionF () { ExpData *tmp = ParseExpressionE (); ExpData *data = new ExpData; if (SC_CheckString ("<")) { data->Type = EX_LT; } else if (SC_CheckString (">")) { data->Type = EX_GT; } else if (SC_CheckString ("<=")) { data->Type = EX_LE; } else if (SC_CheckString (">=")) { data->Type = EX_GE; } else { delete data; return tmp; } data->Children[0] = tmp; data->Children[1] = ParseExpressionF (); data->EvalConst (); return data; } static ExpData *ParseExpressionE () { ExpData *tmp = ParseExpressionD (); ExpData *data = new ExpData; if (SC_CheckString ("<<")) { data->Type = EX_LShift; } else if (SC_CheckString (">>")) { data->Type = EX_RShift; } else { delete data; return tmp; } data->Children[0] = tmp; data->Children[1] = ParseExpressionE (); data->EvalConst (); return data; } static ExpData *ParseExpressionD () { ExpData *tmp = ParseExpressionC (); ExpData *data = new ExpData; if (SC_CheckString ("+")) { data->Type = EX_Add; } else if (SC_CheckString ("-")) { data->Type = EX_Sub; } else { delete data; return tmp; } data->Children[0] = tmp; data->Children[1] = ParseExpressionD (); data->EvalConst (); return data; } static ExpData *ParseExpressionC () { ExpData *tmp = ParseExpressionB (); ExpData *data = new ExpData; if (SC_CheckString ("*")) { data->Type = EX_Mul; } else if (SC_CheckString ("/")) { data->Type = EX_Div; } else if (SC_CheckString ("%")) { data->Type = EX_Mod; } else { delete data; return tmp; } data->Children[0] = tmp; data->Children[1] = ParseExpressionC (); data->EvalConst (); return data; } static ExpData *ParseExpressionB () { ExpData *data = new ExpData; if (SC_CheckString ("~")) { data->Type = EX_Compl; } else if (SC_CheckString ("!")) { data->Type = EX_Not; } else if (SC_CheckString ("-")) { data->Type = EX_Minus; } else { SC_CheckString ("+"); delete data; return ParseExpressionA (); } data->Children[0] = ParseExpressionA (); data->EvalConst (); return data; } static ExpData *ParseExpressionA () { if (SC_CheckString ("(")) { ExpData *data = ParseExpressionM (); if (!SC_CheckString (")")) SC_ScriptError ("')' expected"); return data; } else if (SC_CheckString ("random")) { if (!SC_CheckString ("(")) SC_ScriptError ("'(' expected"); ExpData *data = new ExpData; data->Type = EX_Random; data->Children[0] = ParseExpressionM (); if (!SC_CheckString (",")) SC_ScriptError ("',' expected"); data->Children[1] = ParseExpressionM (); if (!SC_CheckString (")")) SC_ScriptError ("')' expected"); return data; } else if (SC_CheckString ("sin")) { if (!SC_CheckString ("(")) SC_ScriptError ("'(' expected"); ExpData *data = new ExpData; data->Type = EX_Sin; data->Children[0] = ParseExpressionM (); if (!SC_CheckString (")")) SC_ScriptError ("')' expected"); return data; } else if (SC_CheckString ("cos")) { if (!SC_CheckString ("(")) SC_ScriptError ("'(' expected"); ExpData *data = new ExpData; data->Type = EX_Cos; data->Children[0] = ParseExpressionM (); if (!SC_CheckString (")")) SC_ScriptError ("')' expected"); return data; } else if (SC_CheckString ("invcount")) { if (!SC_CheckString ("(")) SC_ScriptError ("'(' expected"); ExpData *data = new ExpData; data->Type = EX_InvCount; SC_MustGetString (); data->Children[0] = (ExpData *)strdup (sc_String); if (!SC_CheckString (")")) SC_ScriptError ("')' expected"); return data; } else if (SC_CheckNumber ()) { ExpData *data = new ExpData; data->Type = EX_Const; data->Value.Type = VAL_Int; data->Value.Int = sc_Number; return data; } else if (SC_CheckFloat ()) { ExpData *data = new ExpData; data->Type = EX_Const; data->Value.Type = VAL_Float; data->Value.Float = sc_Float; return data; } 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++) { if (!stricmp (sc_String, ExpVars[i].name)) { varid = (int)i; break; } } if (varid == -1) SC_ScriptError ("Value expected"); ExpData *data = new ExpData; data->Type = EX_Var; data->Value.Type = VAL_Int; data->Value.Int = varid; if (ExpVars[varid].array) { if (!SC_CheckString ("[")) SC_ScriptError ("'[' expected"); data->Children[0] = ParseExpressionM (); if (!SC_CheckString ("]")) SC_ScriptError ("']' expected"); } return data; } } // // EvalExpression // [GRB] Evaluates previously stored expression // int EvalExpressionI (int id, AActor *self) { if (StateExpressions.Size() <= (unsigned int)id) return 0; ExpVal val = EvalExpression (StateExpressions[id], self); switch (val.Type) { default: case VAL_Int: return val.Int; case VAL_Float: return (int)val.Float; } } bool EvalExpressionN(int id, AActor * self) { return !EvalExpressionI(id, self); } float EvalExpressionF (int id, AActor *self) { if (StateExpressions.Size() <= (unsigned int)id) return 0.f; ExpVal val = EvalExpression (StateExpressions[id], self); switch (val.Type) { default: case VAL_Int: return (float)val.Int; case VAL_Float: return val.Float; } } static ExpVal EvalExpression (ExpData *data, AActor *self) { ExpVal val; switch (data->Type) { case EX_NOP: break; case EX_Const: val = data->Value; break; case EX_Var: if (!self) { // Should not happen I_FatalError ("Missing actor data"); } else { int id = 0; if (ExpVars[data->Value.Int].array) { ExpVal idval = EvalExpression (data->Children[0], self); id = ((idval.Type == VAL_Int) ? idval.Int : (int)idval.Float) % ExpVars[data->Value.Int].array; } val = ExpVars[data->Value.Int].get (self, id); } break; case EX_Compl: { ExpVal a = EvalExpression (data->Children[0], self); val.Type = VAL_Int; val.Int = ~((a.Type == VAL_Int) ? a.Int : (int)a.Float); } break; case EX_Not: { ExpVal a = EvalExpression (data->Children[0], self); val.Type = VAL_Int; val.Int = !((a.Type == VAL_Int) ? a.Int : (int)a.Float); } break; case EX_Minus: { val = EvalExpression (data->Children[0], self); if (val.Type == VAL_Int) val.Int = -val.Int; else val.Float = -val.Float; } break; case EX_Mul: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); if (a.Type == VAL_Int) { if (b.Type == VAL_Int) { val.Type = VAL_Int; val.Int = a.Int * b.Int; } else { val.Type = VAL_Float; val.Float = a.Int * b.Float; } } else { val.Type = VAL_Float; if (b.Type == VAL_Int) val.Float = a.Float * b.Int; else val.Float = a.Float * b.Float; } } break; case EX_Div: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); if (b.Int == 0) { I_FatalError ("Division by zero"); } if (a.Type == VAL_Int) { if (b.Type == VAL_Int) { val.Type = VAL_Int; val.Int = a.Int / b.Int; } else { val.Type = VAL_Float; val.Float = a.Int / b.Float; } } else { val.Type = VAL_Float; if (b.Type == VAL_Int) val.Float = a.Float / b.Int; else val.Float = a.Float / b.Float; } } break; case EX_Mod: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); if (b.Int == 0) { I_FatalError ("Division by zero"); } if (a.Type == VAL_Int) { if (b.Type == VAL_Int) { val.Type = VAL_Int; val.Int = a.Int % b.Int; } else { val.Type = VAL_Float; val.Float = fmodf (a.Int, b.Float); } } else { val.Type = VAL_Float; if (b.Type == VAL_Int) val.Float = fmodf (a.Float, b.Int); else val.Float = fmodf (a.Float, b.Float); } } break; case EX_Add: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); if (a.Type == VAL_Int) { if (b.Type == VAL_Int) { val.Type = VAL_Int; val.Int = a.Int + b.Int; } else { val.Type = VAL_Float; val.Float = a.Int + b.Float; } } else { val.Type = VAL_Float; if (b.Type == VAL_Int) val.Float = a.Float + b.Int; else val.Float = a.Float + b.Float; } } break; case EX_Sub: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); if (a.Type == VAL_Int) { if (b.Type == VAL_Int) { val.Type = VAL_Int; val.Int = a.Int - b.Int; } else { val.Type = VAL_Float; val.Float = a.Int - b.Float; } } else { val.Type = VAL_Float; if (b.Type == VAL_Int) val.Float = a.Float - b.Int; else val.Float = a.Float - b.Float; } } break; case EX_LShift: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int << b.Int; else val.Int = a.Int << (int)b.Float; } else { if (b.Type == VAL_Int) val.Int = (int)a.Float << b.Int; else val.Int = (int)a.Float << (int)b.Float; } } break; case EX_RShift: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int >> b.Int; else val.Int = a.Int >> (int)b.Float; } else { if (b.Type == VAL_Int) val.Int = (int)a.Float >> b.Int; else val.Int = (int)a.Float >> (int)b.Float; } } break; case EX_LT: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int < b.Int; else val.Int = a.Int < b.Float; } else { if (b.Type == VAL_Int) val.Int = a.Float < b.Int; else val.Int = a.Float < b.Float; } } break; case EX_GT: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int > b.Int; else val.Int = a.Int > b.Float; } else { if (b.Type == VAL_Int) val.Int = a.Float > b.Int; else val.Int = a.Float > b.Float; } } break; case EX_LE: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int <= b.Int; else val.Int = a.Int <= b.Float; } else { if (b.Type == VAL_Int) val.Int = a.Float <= b.Int; else val.Int = a.Float <= b.Float; } } break; case EX_GE: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int >= b.Int; else val.Int = a.Int >= b.Float; } else { if (b.Type == VAL_Int) val.Int = a.Float >= b.Int; else val.Int = a.Float >= b.Float; } } break; case EX_Eq: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int == b.Int; else val.Int = a.Int == b.Float; } else { if (b.Type == VAL_Int) val.Int = a.Float == b.Int; else val.Int = a.Float == b.Float; } } break; case EX_NE: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int != b.Int; else val.Int = a.Int != b.Float; } else { if (b.Type == VAL_Int) val.Int = a.Float != b.Int; else val.Int = a.Float != b.Float; } } break; case EX_And: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int & b.Int; else val.Int = a.Int & (int)b.Float; } else { if (b.Type == VAL_Int) val.Int = (int)a.Float & b.Int; else val.Int = (int)a.Float & (int)b.Float; } } break; case EX_Xor: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int ^ b.Int; else val.Int = a.Int ^ (int)b.Float; } else { if (b.Type == VAL_Int) val.Int = (int)a.Float ^ b.Int; else val.Int = (int)a.Float ^ (int)b.Float; } } break; case EX_Or: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int | b.Int; else val.Int = a.Int | (int)b.Float; } else { if (b.Type == VAL_Int) val.Int = (int)a.Float | b.Int; else val.Int = (int)a.Float | (int)b.Float; } } break; case EX_LogAnd: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int && b.Int; else val.Int = a.Int && b.Float; } else { if (b.Type == VAL_Int) val.Int = a.Float && b.Int; else val.Int = a.Float && b.Float; } } break; case EX_LogOr: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); val.Type = VAL_Int; if (a.Type == VAL_Int) { if (b.Type == VAL_Int) val.Int = a.Int || b.Int; else val.Int = a.Int || b.Float; } else { if (b.Type == VAL_Int) val.Int = a.Float || b.Int; else val.Int = a.Float || b.Float; } } break; case EX_Cond: { ExpVal a = EvalExpression (data->Children[0], self); if (a.Type == VAL_Float) a.Int = (int)a.Float; val = EvalExpression (data->Children[1]->Children[!!a.Int], self); } break; case EX_Random: { ExpVal a = EvalExpression (data->Children[0], self); ExpVal b = EvalExpression (data->Children[1], self); int min = (a.Type == VAL_Int) ? a.Int : (int)a.Float; int max = (b.Type == VAL_Int) ? b.Int : (int)b.Float; val.Type = VAL_Int; if (max < min) { swap (max, min); } if (max - min > 255) { int num1,num2,num3,num4; num1 = pr_exrandom(); num2 = pr_exrandom(); num3 = pr_exrandom(); num4 = pr_exrandom(); val.Int = ((num1 << 24) | (num2 << 16) | (num3 << 8) | num4); } else { val.Int = pr_exrandom(); } val.Int %= (max - min + 1); val.Int += min; } break; case EX_Sin: { ExpVal a = EvalExpression (data->Children[0], self); angle_t angle = (a.Type == VAL_Int) ? (a.Int * ANGLE_1) : angle_t(a.Float * ANGLE_1); val.Type = VAL_Float; val.Float = FIXED2FLOAT (finesine[angle>>ANGLETOFINESHIFT]); } break; case EX_Cos: { ExpVal a = EvalExpression (data->Children[0], self); angle_t angle = (a.Type == VAL_Int) ? (a.Int * ANGLE_1) : angle_t(a.Float * ANGLE_1); val.Type = VAL_Float; val.Float = FIXED2FLOAT (finecosine[angle>>ANGLETOFINESHIFT]); } break; case EX_InvCount: { const char *name = (const char *)data->Children[0]; const PClass *type = PClass::FindClass (name); val.Type = VAL_Int; val.Int = 0; if (!type) break; AInventory *item = self->FindInventory (type); if (item) 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; } // // InitExpressions // [GRB] Set up expression data // void InitExpressions () { // StateExpressions[0] always is const 0; ExpData *data = new ExpData; data->Type = EX_Const; data->Value.Type = VAL_Int; data->Value.Int = 0; StateExpressions.Push (data); } // // ClearExpressions // [GRB] Free all expression data // void ClearExpressions () { ExpData *data; while (StateExpressions.Pop (data)) delete data; }