diff --git a/src/namedef.h b/src/namedef.h index 146997309..7eef612c1 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -300,6 +300,7 @@ xx(CallACS) xx(Sqrt) xx(CheckClass) xx(IsPointerEqual) +xx(RClamp) // Various actor names which are used internally xx(MapSpot) diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index dd90ce1d1..2e25fb2f7 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -158,6 +158,7 @@ std2: 'random' { RET(TK_Random); } 'random2' { RET(TK_Random2); } 'frandom' { RET(TK_FRandom); } + 'rclamp' { RET(TK_RClamp); } L (L|D)* { RET(TK_Identifier); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index 9dde74972..62622cf00 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -122,4 +122,5 @@ xx(TK_Array, "'array'") xx(TK_In, "'in'") xx(TK_SizeOf, "'sizeof'") xx(TK_AlignOf, "'alignof'") +xx(TK_RClamp, "'rclamp'") #undef xx diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 773f7ffac..4cef24187 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -371,6 +371,29 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls) return new FxRandom(rng, min, max, sc); } + else if (sc.CheckToken(TK_RClamp)) + { + FRandom *rng; + + if (sc.CheckToken('[')) + { + sc.MustGetToken(TK_Identifier); + rng = FRandom::StaticFindRNG(sc.String); + sc.MustGetToken(']'); + } + else + { + rng = &pr_exrandom; + } + sc.MustGetToken('('); + + FxExpression *min = ParseExpressionM(sc, cls); + sc.MustGetToken(','); + FxExpression *max = ParseExpressionM(sc, cls); + sc.MustGetToken(')'); + + return new FxRClamp(rng, min, max, sc); + } else if (sc.CheckToken(TK_FRandom)) { FRandom *rng; diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index 77af37f53..42e35489d 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -559,6 +559,27 @@ public: // //========================================================================== +class FxRClamp : public FxExpression +{ +protected: + FRandom * rng; + FxExpression *min, *max; + +public: + + FxRClamp(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos); + ~FxRClamp(); + FxExpression *Resolve(FCompileContext&); + + ExpVal EvalExpression(AActor *self); +}; + +//========================================================================== +// +// +// +//========================================================================== + class FxFRandom : public FxRandom { public: diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 7dbf5ec36..5a5510a0b 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -1691,6 +1691,89 @@ ExpVal FxRandom::EvalExpression (AActor *self) return val; } +//========================================================================== +// +// +// +//========================================================================== +FxRClamp::FxRClamp(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos) +: FxExpression(pos) +{ + if (mi != NULL && ma != NULL) + { + min = new FxIntCast(mi); + max = new FxIntCast(ma); + } + else min = max = NULL; + rng = r; + ValueType = VAL_Int; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRClamp::~FxRClamp() +{ + SAFE_DELETE(min); + SAFE_DELETE(max); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxRClamp::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + if (min && max) + { + RESOLVE(min, ctx); + RESOLVE(max, ctx); + ABORT(min && max); + } + return this; +}; + + +//========================================================================== +// +// +// +//========================================================================== + +ExpVal FxRClamp::EvalExpression(AActor *self) +{ + ExpVal val; + val.Type = VAL_Int; + + if (min != NULL && max != NULL) + { + int minval = min->EvalExpression(self).GetInt(); + int maxval = max->EvalExpression(self).GetInt(); + + if (maxval < minval) + { + swapvalues(maxval, minval); + } + + val.Int = (*rng)(2); //rng->operator()(2); //(maxval - minval + 1) + minval; + if (val.Int > 0) + val.Int = maxval; + else + val.Int = minval; + } + else + { + val.Int = (*rng)(); + } + return val; +} + //========================================================================== // //