diff --git a/src/namedef.h b/src/namedef.h index db492c1b27..a22a5de5f0 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -334,6 +334,8 @@ xx(FRandom) xx(Random2) xx(RandomPick) xx(FRandomPick) +xx(SetRandomSeed) +xx(BuiltinRandomSeed) xx(GetClass) xx(GetParentClass) xx(GetClassName) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index f088bc2430..0613b91bde 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -5906,6 +5906,82 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build) return out; } +//========================================================================== +// +// +// +//========================================================================== +FxRandomSeed::FxRandomSeed(FRandom * r, FxExpression *s, const FScriptPosition &pos, bool nowarn) + : FxExpression(EFX_Random, pos) +{ + EmitTail = false; + seed = new FxIntCast(s, nowarn); + rng = r; + ValueType = TypeVoid; +} + +//========================================================================== +// +// +// +//========================================================================== + +FxRandomSeed::~FxRandomSeed() +{ + SAFE_DELETE(seed); +} + +//========================================================================== +// +// +// +//========================================================================== + +FxExpression *FxRandomSeed::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + RESOLVE(seed, ctx); + return this; +}; + + +//========================================================================== +// +// +// +//========================================================================== + +int BuiltinRandomSeed(VMValue *param, TArray &defaultparam, int numparam, VMReturn *ret, int numret) +{ + PARAM_PROLOGUE; + PARAM_POINTER(rng, FRandom) + PARAM_INT(seed); + rng->Init(seed); + return 0; +} + +ExpEmit FxRandomSeed::Emit(VMFunctionBuilder *build) +{ + // Call DecoRandom to generate a random number. + VMFunction *callfunc; + PSymbol *sym = FindBuiltinFunction(NAME_BuiltinRandomSeed, BuiltinRandomSeed); + + assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction))); + assert(((PSymbolVMFunction *)sym)->Function != nullptr); + callfunc = ((PSymbolVMFunction *)sym)->Function; + + if (build->FramePointer.Fixed) EmitTail = false; // do not tail call if the stack is in use + int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K); + + build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng)); + EmitParameter(build, seed, ScriptPosition); + build->Emit(opcode, build->GetConstantAddress(callfunc), 2, 1); + + ExpEmit call; + if (EmitTail) call.Final = true; + return call; +} + //========================================================================== // // @@ -7537,6 +7613,7 @@ FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &a case NAME_RandomPick: case NAME_FRandomPick: case NAME_Random2: + case NAME_SetRandomSeed: RNG = FRandom::StaticFindRNG(rngname.GetChars()); break; @@ -7790,6 +7867,14 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } break; + case NAME_SetRandomSeed: + if (CheckArgSize(NAME_Random, ArgList, 1, 1, ScriptPosition)) + { + func = new FxRandomSeed(RNG, ArgList[0], ScriptPosition, ctx.FromDecorate); + ArgList[0] = nullptr; + } + break; + case NAME_Random: // allow calling Random without arguments to default to (0, 255) if (ArgList.Size() == 0) diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 004b1f2289..2121eff7a4 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -1321,6 +1321,27 @@ public: }; +//========================================================================== +// +// +// +//========================================================================== + +class FxRandomSeed : public FxExpression +{ +protected: + bool EmitTail; + FRandom *rng; + FxExpression *seed; + +public: + + FxRandomSeed(FRandom *, FxExpression *mi, const FScriptPosition &pos, bool nowarn); + ~FxRandomSeed(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxMemberBase