From 135cfcf0163a582b89a00f22ae7c65b19146be21 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 21 Nov 2016 21:34:34 +0100 Subject: [PATCH] - implemented State as an actual native struct, so that its fields can be accessed from scripts. - refactored state bitfield members into a flag word because the address of a bitfield cannot be taken, making such variables inaccessible to scripts. - actually use PNativeStruct for representing native structs defined in a script. --- src/d_dehacked.cpp | 15 ++--- src/dobjtype.cpp | 3 +- src/info.h | 71 ++++++++++++---------- src/p_mobj.cpp | 4 +- src/p_states.cpp | 37 +++++++++-- src/scripting/codegeneration/codegen.cpp | 4 +- src/scripting/decorate/olddecorations.cpp | 2 +- src/scripting/decorate/thingdef_states.cpp | 10 +-- src/scripting/thingdef_data.cpp | 2 + src/scripting/zscript/zcc_compile.cpp | 16 +++-- wadsrc/static/zscript/actor.txt | 1 - wadsrc/static/zscript/doom/fatso.txt | 2 +- 12 files changed, 102 insertions(+), 65 deletions(-) diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 3ad1b2cd9..508821fd8 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -1466,28 +1466,21 @@ static int PatchFrame (int frameNum) if (info != &dummy) { - info->DefineFlags |= SDF_DEHACKED; // Signals the state has been modified by dehacked + info->StateFlags |= STF_DEHACKED; // Signals the state has been modified by dehacked if ((unsigned)(frame & 0x7fff) > 63) { - Printf ("Frame %d: Subnumber must be in range [0,63]\n", frameNum); + Printf("Frame %d: Subnumber must be in range [0,63]\n", frameNum); } info->Tics = tics; info->Misc1 = misc1; info->Frame = frame & 0x3f; - info->Fullbright = frame & 0x8000 ? true : false; + if (frame & 0x8000) info->StateFlags |= STF_FULLBRIGHT; + else info->StateFlags &= STF_FULLBRIGHT; } return result; } -// there is exactly one place where this is needed and we do not want to expose the state internals to ZSCRIPT. -DEFINE_ACTION_FUNCTION(AActor, isDEHState) -{ - PARAM_PROLOGUE; - PARAM_POINTER(state, FState); - ACTION_RETURN_BOOL(state != nullptr && (state->DefineFlags & SDF_DEHACKED)); -} - static int PatchSprite (int sprNum) { int result; diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 2f536c300..420dbc515 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -558,6 +558,7 @@ void PType::StaticInit() RUNTIME_CLASS(PDynArray)->TypeTableType = RUNTIME_CLASS(PDynArray); RUNTIME_CLASS(PMap)->TypeTableType = RUNTIME_CLASS(PMap); RUNTIME_CLASS(PStruct)->TypeTableType = RUNTIME_CLASS(PStruct); + RUNTIME_CLASS(PNativeStruct)->TypeTableType = RUNTIME_CLASS(PNativeStruct); RUNTIME_CLASS(PPrototype)->TypeTableType = RUNTIME_CLASS(PPrototype); RUNTIME_CLASS(PClass)->TypeTableType = RUNTIME_CLASS(PClass); RUNTIME_CLASS(PStatePointer)->TypeTableType = RUNTIME_CLASS(PStatePointer); @@ -2469,7 +2470,7 @@ PNativeStruct *NewNativeStruct(FName name, PTypeBase *outer) PType *stype = TypeTable.FindType(RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, &bucket); if (stype == NULL) { - stype = new PStruct(name, outer); + stype = new PNativeStruct(name); TypeTable.AddType(stype, RUNTIME_CLASS(PNativeStruct), (intptr_t)outer, (intptr_t)name, bucket); } return static_cast(stype); diff --git a/src/info.h b/src/info.h index 4f2b4b293..a41a6def8 100644 --- a/src/info.h +++ b/src/info.h @@ -63,7 +63,17 @@ enum EStateDefineFlags SDF_LABEL = 4, SDF_INDEX = 5, SDF_MASK = 7, - SDF_DEHACKED = 8, // Identify a state as having been modified by a dehacked lump +}; + +enum EStateFlags +{ + STF_SLOW = 1, // State duration is extended when slow monsters is on. + STF_FAST = 2, // State duration is shortened when fast monsters is on. + STF_FULLBRIGHT = 4, // State is fullbright + STF_NODELAY = 8, // Spawn states executes its action normally + STF_SAMEFRAME = 16, // Ignore Frame (except when spawning actor) + STF_CANRAISE = 32, // Allows a monster to be resurrected without waiting for an infinate frame + STF_DEHACKED = 64, // Modified by Dehacked }; enum EStateUseFlags @@ -101,33 +111,44 @@ struct FState { FState *NextState; VMFunction *ActionFunc; - WORD sprite; - SWORD Tics; - WORD TicRange; - short Light; - BYTE Frame; - BYTE UseFlags; - BYTE DefineFlags; // Unused byte so let's use it during state creation. - int Misc1; // Was changed to SBYTE, reverted to long for MBF compat - int Misc2; // Was changed to BYTE, reverted to long for MBF compat - BYTE Fullbright:1; // State is fullbright - BYTE SameFrame:1; // Ignore Frame (except when spawning actor) - BYTE Fast:1; - BYTE NoDelay:1; // Spawn states executes its action normally - BYTE CanRaise:1; // Allows a monster to be resurrected without waiting for an infinate frame - BYTE Slow:1; // Inverse of fast - + int32_t sprite; + int16_t Tics; + uint16_t TicRange; + int16_t Light; + uint16_t StateFlags; + uint8_t Frame; + uint8_t UseFlags; + uint8_t DefineFlags; // Unused byte so let's use it during state creation. + int32_t Misc1; // Was changed to SBYTE, reverted to long for MBF compat + int32_t Misc2; // Was changed to BYTE, reverted to long for MBF compat +public: inline int GetFrame() const { return Frame; } inline bool GetSameFrame() const { - return SameFrame; + return !!(StateFlags & STF_SAMEFRAME); } inline int GetFullbright() const { - return Fullbright ? 0x10 /*RF_FULLBRIGHT*/ : 0; + return (StateFlags & STF_FULLBRIGHT)? 0x10 /*RF_FULLBRIGHT*/ : 0; + } + inline bool GetFast() const + { + return !!(StateFlags & STF_FAST); + } + inline bool GetSlow() const + { + return !!(StateFlags & STF_SLOW); + } + inline bool GetNoDelay() const + { + return !!(StateFlags & STF_NODELAY); + } + inline bool GetCanRaise() const + { + return !!(StateFlags & STF_CANRAISE); } inline int GetTics() const { @@ -149,22 +170,10 @@ struct FState { return NextState; } - inline bool GetNoDelay() const - { - return NoDelay; - } - inline bool GetCanRaise() const - { - return CanRaise; - } inline void SetFrame(BYTE frame) { Frame = frame - 'A'; } - inline bool CheckUse(int usetype) - { - return !!(UseFlags & usetype); - } void SetAction(VMFunction *func) { ActionFunc = func; } void ClearAction() { ActionFunc = NULL; } void SetAction(const char *name); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index a97ed61c5..b7da3e2c5 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -584,11 +584,11 @@ bool AActor::InStateSequence(FState * newstate, FState * basestate) int AActor::GetTics(FState * newstate) { int tics = newstate->GetTics(); - if (isFast() && newstate->Fast) + if (isFast() && newstate->GetFast()) { return tics - (tics>>1); } - else if (isSlow() && newstate->Slow) + else if (isSlow() && newstate->GetSlow()) { return tics<<1; } diff --git a/src/p_states.cpp b/src/p_states.cpp index fde7a0276..5444bcc3a 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -924,9 +924,9 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars, const FS if (*framechars == '#') noframe = true; - else if (*framechars == '^') + else if (*framechars == '^') frame = '\\' - 'A'; - else + else frame = (*framechars & 223) - 'A'; framechars++; @@ -937,13 +937,14 @@ int FStateDefinitions::AddStates(FState *state, const char *framechars, const FS } state->Frame = frame; - state->SameFrame = noframe; + if (noframe) state->StateFlags |= STF_SAMEFRAME; + else state->StateFlags &= STF_SAMEFRAME; StateArray.Push(*state); SourceLines.Push(sc); ++count; // NODELAY flag is not carried past the first state - state->NoDelay = false; + state->StateFlags &= STF_NODELAY; } laststate = &StateArray[StateArray.Size() - 1]; laststatebeforelabel = laststate; @@ -1055,3 +1056,31 @@ CCMD(dumpstates) Printf(PRINT_LOG, "----------------------------\n"); } } + +//========================================================================== +// +// sets up the script-side version of states +// +//========================================================================== + +void P_InitStateForScript() +{ + PNativeStruct *pstruct = dyn_cast(TypeState->PointedType); + assert(pstruct != nullptr); + + pstruct->AddNativeField("NextState", TypeState, myoffsetof(FState, NextState), VARF_ReadOnly); + pstruct->AddNativeField("sprite", TypeSInt32, myoffsetof(FState, sprite), VARF_ReadOnly); + pstruct->AddNativeField("Tics", TypeSInt16, myoffsetof(FState, Tics), VARF_ReadOnly); + pstruct->AddNativeField("TicRange", TypeUInt16, myoffsetof(FState, TicRange), VARF_ReadOnly); + pstruct->AddNativeField("Frame", TypeUInt8, myoffsetof(FState, Frame), VARF_ReadOnly); + pstruct->AddNativeField("UseFlags", TypeUInt8, myoffsetof(FState, UseFlags), VARF_ReadOnly); + pstruct->AddNativeField("Misc1", TypeSInt32, myoffsetof(FState, Misc1), VARF_ReadOnly); + pstruct->AddNativeField("Misc2", TypeSInt32, myoffsetof(FState, Misc2), VARF_ReadOnly); + pstruct->AddNativeField("bSlow", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_SLOW); + pstruct->AddNativeField("bFast", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_FAST); + pstruct->AddNativeField("bFullbright", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_FULLBRIGHT); + pstruct->AddNativeField("bNoDelay", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_NODELAY); + pstruct->AddNativeField("bSameFrame", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_SAMEFRAME); + pstruct->AddNativeField("bCanRaise", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_CANRAISE); + pstruct->AddNativeField("bDehacked", TypeUInt16, myoffsetof(FState, StateFlags), VARF_ReadOnly, STF_DEHACKED); +} \ No newline at end of file diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 8d44e5c18..75d49801f 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5679,7 +5679,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) return ret; } } - else if (Object->ValueType->IsA(RUNTIME_CLASS(PStruct))) + else if (Object->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) { auto ret = ResolveMember(ctx, ctx.Class, Object, static_cast(Object->ValueType)); delete this; @@ -6278,7 +6278,7 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx) return nullptr; } } - else if (classx->ValueType->IsA(RUNTIME_CLASS(PStruct))) // Classes can never be used as value types so we do not have to consider that case. + else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct))) { // if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset. if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember) diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index a4cf20de4..a2cbc636b 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -699,7 +699,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray &states, TArray { sc.ScriptError ("* must come after a frame"); } - state.Fullbright = true; + state.StateFlags |= STF_FULLBRIGHT; } else if (*token < 'A' || *token > ']') { diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index cad542d1b..4f60b8585 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -274,24 +274,24 @@ do_stop: { if (sc.Compare("BRIGHT")) { - state.Fullbright = true; + state.StateFlags |= STF_FULLBRIGHT; continue; } if (sc.Compare("FAST")) { - state.Fast = true; + state.StateFlags |= STF_FAST; continue; } if (sc.Compare("SLOW")) { - state.Slow = true; + state.StateFlags |= STF_SLOW; continue; } if (sc.Compare("NODELAY")) { if (bag.statedef.GetStateLabelIndex(NAME_Spawn) == bag.statedef.GetStateCount()) { - state.NoDelay = true; + state.StateFlags |= STF_NODELAY; } else { @@ -327,7 +327,7 @@ do_stop: } if (sc.Compare("CANRAISE")) { - state.CanRaise = true; + state.StateFlags |= STF_CANRAISE; continue; } diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 5e8338a27..23aba902f 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -658,6 +658,7 @@ static int funccmp(const void * a, const void * b) //========================================================================== void G_InitLevelLocalsForScript(); void P_InitPlayerForScript(); +void P_InitStateForScript(); void InitThingdef() { @@ -669,6 +670,7 @@ void InitThingdef() G_InitLevelLocalsForScript(); P_InitPlayerForScript(); + P_InitStateForScript(); FAutoSegIterator probe(CRegHead, CRegTail); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 81b1c5ef6..c76df32e3 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -416,7 +416,10 @@ void ZCCCompiler::CreateStructTypes() for(auto s : Structs) { s->Outer = s->OuterDef == nullptr? nullptr : s->OuterDef->CType(); - s->strct->Type = NewStruct(s->NodeName(), s->Outer); + if (s->strct->Flags & ZCC_Native) + s->strct->Type = NewNativeStruct(s->NodeName(), nullptr); + else + s->strct->Type = NewStruct(s->NodeName(), s->Outer); s->strct->Symbol = new PSymbolType(s->NodeName(), s->Type()); GlobalSymbols.AddSymbol(s->strct->Symbol); @@ -2568,11 +2571,12 @@ void ZCCCompiler::CompileStates() Error(sl, "Duration is not a constant"); } } - state.Fullbright = sl->bBright; - state.Fast = sl->bFast; - state.Slow = sl->bSlow; - state.CanRaise = sl->bCanRaise; - if ((state.NoDelay = sl->bNoDelay)) + if (sl->bBright) state.StateFlags |= STF_FULLBRIGHT; + if (sl->bFast) state.StateFlags |= STF_FAST; + if (sl->bSlow) state.StateFlags |= STF_SLOW; + if (sl->bCanRaise) state.StateFlags |= STF_CANRAISE; + if (sl->bNoDelay) state.StateFlags |= STF_NODELAY; + if (sl->bNoDelay) { if (statedef.GetStateLabelIndex(NAME_Spawn) != statedef.GetStateCount()) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 87d2f8759..61bdf49c8 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -78,7 +78,6 @@ class Actor : Thinker native native bool GiveBody (int num, int max=0); native void SetDamage(int dmg); - native static bool isDehState(state st); native double Distance2D(Actor other); native void SetOrigin(vector3 newpos, bool moving); native void SetXYZ(vector3 newpos); diff --git a/wadsrc/static/zscript/doom/fatso.txt b/wadsrc/static/zscript/doom/fatso.txt index 98bcc3fc9..3831110c0 100644 --- a/wadsrc/static/zscript/doom/fatso.txt +++ b/wadsrc/static/zscript/doom/fatso.txt @@ -192,7 +192,7 @@ extend class Actor aimtarget.Height = Height; bool shootmode = ((flags & MSF_Classic) || // Flag explicitely set, or no flags and compat options - (flags == 0 && isDehState(CurState) && compat_mushroom)); + (flags == 0 && CurState.bDehacked && compat_mushroom)); for (i = -numspawns; i <= numspawns; i += 8) {