- 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.
This commit is contained in:
Christoph Oelckers 2016-11-21 21:34:34 +01:00
parent ff3baac8a7
commit 135cfcf016
12 changed files with 102 additions and 65 deletions

View File

@ -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;

View File

@ -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<PNativeStruct *>(stype);

View File

@ -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);

View File

@ -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;
}

View File

@ -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<PNativeStruct>(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);
}

View File

@ -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<PStruct *>(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)

View File

@ -699,7 +699,7 @@ static void ParseSpriteFrames (PClassActor *info, TArray<FState> &states, TArray
{
sc.ScriptError ("* must come after a frame");
}
state.Fullbright = true;
state.StateFlags |= STF_FULLBRIGHT;
}
else if (*token < 'A' || *token > ']')
{

View File

@ -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;
}

View File

@ -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);

View File

@ -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())
{

View File

@ -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);

View File

@ -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)
{