exported XSECTOR and XWALL.

this required an extension to the ZScript front end to allow defining the bitfield flag variables which cannot have their address taken.
This commit is contained in:
Christoph Oelckers 2023-10-01 20:39:40 +02:00
parent 5a26989d06
commit 3aafcb94f1
17 changed files with 432 additions and 88 deletions

View file

@ -699,6 +699,7 @@ set( NOT_COMPILED_SOURCE_FILES
games/blood/src/view.cpp
games/blood/src/warp.cpp
games/blood/src/weapon.cpp
games/blood/src/vmexports.cpp
# Duke
games/duke/src/actors.cpp

View file

@ -374,6 +374,15 @@ flag_def(X) ::= FLAGDEF(T) IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) S
X = def;
}
flag_def(X) ::= FLAGDEF(T) INTERNAL IDENTIFIER(A) COLON IDENTIFIER(B) COMMA INTCONST(C) SEMICOLON.
{
NEW_AST_NODE(FlagDef,def,T);
def->NodeName = A.Name();
def->RefName = B.Name();
def->BitValue = C.Int | 0x10000;
X = def;
}
identifier_list(X) ::= IDENTIFIER(A).
{
@ -433,6 +442,7 @@ struct_member(X) ::= declarator(A). { X = A; /*X-overwrites-A*/ }
struct_member(X) ::= enum_def(A). { X = A; /*X-overwrites-A*/ }
struct_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ }
struct_member(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ }
struct_member(X) ::= flag_def(A). { X = A; /*X-overwrites-A*/ }
/*----- Constant Definition ------*/
/* Like UnrealScript, a constant's type is implied by its value's type. */

View file

@ -452,6 +452,11 @@ void ZCCCompiler::ProcessStruct(ZCC_Struct *cnode, PSymbolTreeNode *treenode, ZC
}
break;
case AST_FlagDef:
cls->FlagDefs.Push(static_cast<ZCC_FlagDef*>(node));
break;
default:
assert(0 && "Unhandled AST node type");
break;

View file

@ -23,6 +23,7 @@ struct ZCC_StructWork
TArray<ZCC_VarDeclarator *> Fields;
TArray<ZCC_FuncDeclarator *> Functions;
TArray<ZCC_StaticArrayStatement *> Arrays;
TArray<ZCC_FlagDef*> FlagDefs;
ZCC_StructWork()
{

View file

@ -89,6 +89,11 @@ void ZCCRazeCompiler::CompileAllProperties()
if (c->FlagDefs.Size() > 0)
CompileFlagDefs(c->ClassType(), c->FlagDefs, c->Type()->TypeName);
}
for (auto s : Structs)
{
if (s->FlagDefs.Size() > 0)
CompileFlagDefs(s->Type(), s->FlagDefs, s->Type()->TypeName);
}
}
@ -158,17 +163,22 @@ bool ZCCRazeCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Pr
bool ZCCRazeCompiler::CompileFlagDefs(PClass *type, TArray<ZCC_FlagDef *> &Properties, FName prefix)
{
if (!type->IsDescendantOf(RUNTIME_CLASS(DCoreActor)))
{
Error(Properties[0], "Flags can only be defined for actors");
return false;
}
for (auto p : Properties)
{
PField *field;
FName referenced = FName(p->RefName);
bool internal = (p->BitValue & 0x10000); // defines just a variable for the flag but no property.
if (!internal)
{
if (!type->IsDescendantOf(RUNTIME_CLASS(DCoreActor)))
{
Error(Properties[0], "Flag properties can only be defined for actors");
return false;
}
}
FName referenced(p->RefName);
if (FName(p->NodeName) == FName("prefix") && fileSystem.GetFileContainer(Lump) == 0)
PField *field;
if (!internal && FName(p->NodeName) == FName("prefix") && fileSystem.GetFileContainer(Lump) == 0)
{
// only for internal definitions: Allow setting a prefix. This is only for compatiblity with the old DECORATE property parser, but not for general use.
prefix = referenced;
@ -190,32 +200,72 @@ bool ZCCRazeCompiler::CompileFlagDefs(PClass *type, TArray<ZCC_FlagDef *> &Prope
else field = nullptr;
FString qualifiedname;
// Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen.
// All these will be removed from the symbol table after the compiler finishes to free up the allocated space.
FName name = FName(p->NodeName);
for (int i = 0; i < 2; i++)
FName name(p->NodeName);
if (!internal)
{
if (i == 0) qualifiedname.Format("@flagdef@%s", name.GetChars());
else
FString qualifiedname;
// Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen.
// All these will be removed from the symbol table after the compiler finishes to free up the allocated space.
for (int i = 0; i < 2; i++)
{
if (prefix == NAME_None) continue;
qualifiedname.Format("@flagdef@%s.%s", prefix.GetChars(), name.GetChars());
}
if (i == 0) qualifiedname.Format("@flagdef@%s", name.GetChars());
else
{
if (prefix == NAME_None) continue;
qualifiedname.Format("@flagdef@%s.%s", prefix.GetChars(), name.GetChars());
}
if (!type->VMType->Symbols.AddSymbol(Create<PPropFlag>(qualifiedname, field, p->BitValue, i == 0 && prefix != NAME_None)))
{
Error(p, "Unable to add flag definition %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars());
if (!type->VMType->Symbols.AddSymbol(Create<PPropFlag>(qualifiedname, field, p->BitValue, i == 0 && prefix != NAME_None)))
{
Error(p, "Unable to add flag definition %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars());
}
}
if (field != nullptr)
type->VMType->AddNativeField(FStringf("b%s", name.GetChars()), TypeSInt32, field->Offset, 0, 1 << p->BitValue);
}
if (field != nullptr)
type->VMType->AddNativeField(FStringf("b%s", name.GetChars()), TypeSInt32, field->Offset, 0, 1 << p->BitValue);
// internal ones get no 'b'.
else if (field != nullptr)
type->VMType->AddNativeField(name.GetChars(), TypeSInt32, field->Offset, 0, 1 << p->BitValue);
}
}
return true;
}
bool ZCCRazeCompiler::CompileFlagDefs(PContainerType* type, TArray<ZCC_FlagDef*>& Properties, FName prefix)
{
for (auto p : Properties)
{
bool internal = (p->BitValue & 0x10000); // defines just a variable for the flag but no property.
if (!internal)
{
Error(Properties[0], "Flag properties can only be defined for actors");
return false;
}
FName referenced(p->RefName);
PField* field;
if (referenced != NAME_None)
{
field = dyn_cast<PField>(type->Symbols.FindSymbol(referenced, true));
if (field == nullptr)
{
Error(p, "Variable %s not found in %s", referenced.GetChars(), type->TypeName.GetChars());
}
else if (!field->Type->isInt() || field->Type->Size != 4)
{
Error(p, "Variable %s in %s must have a size of 4 bytes for use as flag storage", referenced.GetChars(), type->TypeName.GetChars());
}
FName name(p->NodeName);
type->AddNativeField(name.GetChars(), TypeSInt32, field->Offset, 0, 1 << (p->BitValue & 0xffff));
return true;
}
}
return false;
}
//==========================================================================
//
// Parses an actor property's parameters and calls the handler
@ -449,9 +499,105 @@ void ZCCRazeCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *
}
else if (!ex->isConstant())
{
if (ex->ExprType == EFX_VectorValue && ex->ValueType == f->Type)
{
auto v = static_cast<FxVectorValue *>(ex);
if (f->Type == TypeVector2)
{
if(!v->isConstVector(2))
{
Error(exp, "%s: non-constant Vector2 parameter", prop->SymbolName.GetChars());
return;
}
(*(DVector2*)addr) = DVector2(
static_cast<FxConstant *>(v->xyzw[0])->GetValue().GetFloat(),
static_cast<FxConstant *>(v->xyzw[1])->GetValue().GetFloat()
);
goto vector_ok;
}
else if (f->Type == TypeFVector2)
{
if(!v->isConstVector(2))
{
Error(exp, "%s: non-constant FVector2 parameter", prop->SymbolName.GetChars());
return;
}
(*(FVector2*)addr) = FVector2(
float(static_cast<FxConstant *>(v->xyzw[0])->GetValue().GetFloat()),
float(static_cast<FxConstant *>(v->xyzw[1])->GetValue().GetFloat())
);
goto vector_ok;
}
else if (f->Type == TypeVector3)
{
if(!v->isConstVector(3))
{
Error(exp, "%s: non-constant Vector3 parameter", prop->SymbolName.GetChars());
return;
}
(*(DVector3*)addr) = DVector3(
static_cast<FxConstant *>(v->xyzw[0])->GetValue().GetFloat(),
static_cast<FxConstant *>(v->xyzw[1])->GetValue().GetFloat(),
static_cast<FxConstant *>(v->xyzw[2])->GetValue().GetFloat()
);
goto vector_ok;
}
else if (f->Type == TypeFVector3)
{
if(!v->isConstVector(3))
{
Error(exp, "%s: non-constant FVector3 parameter", prop->SymbolName.GetChars());
return;
}
(*(FVector3*)addr) = FVector3(
float(static_cast<FxConstant*>(v->xyzw[0])->GetValue().GetFloat()),
float(static_cast<FxConstant*>(v->xyzw[1])->GetValue().GetFloat()),
float(static_cast<FxConstant*>(v->xyzw[2])->GetValue().GetFloat())
);
goto vector_ok;
}
else if (f->Type == TypeVector4)
{
if(!v->isConstVector(4))
{
Error(exp, "%s: non-constant Vector4 parameter", prop->SymbolName.GetChars());
return;
}
(*(DVector4*)addr) = DVector4(
static_cast<FxConstant *>(v->xyzw[0])->GetValue().GetFloat(),
static_cast<FxConstant *>(v->xyzw[1])->GetValue().GetFloat(),
static_cast<FxConstant *>(v->xyzw[2])->GetValue().GetFloat(),
static_cast<FxConstant *>(v->xyzw[3])->GetValue().GetFloat()
);
goto vector_ok;
}
else if (f->Type == TypeFVector4)
{
if(!v->isConstVector(4))
{
Error(exp, "%s: non-constant FVector4 parameter", prop->SymbolName.GetChars());
return;
}
(*(FVector4*)addr) = FVector4(
float(static_cast<FxConstant*>(v->xyzw[0])->GetValue().GetFloat()),
float(static_cast<FxConstant*>(v->xyzw[1])->GetValue().GetFloat()),
float(static_cast<FxConstant*>(v->xyzw[2])->GetValue().GetFloat()),
float(static_cast<FxConstant *>(v->xyzw[3])->GetValue().GetFloat())
);
goto vector_ok;
}
else
{
Error(exp, "%s: invalid vector parameter", prop->SymbolName.GetChars());
return;
}
}
else
{
if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars());
return;
}
// If we get TypeError, there has already been a message from deeper down so do not print another one.
if (exp->Type != TypeError) Error(exp, "%s: non-constant parameter", prop->SymbolName.GetChars());
return;
}
if (f->Type == TypeBool)
@ -508,6 +654,7 @@ void ZCCRazeCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *
{
Error(property, "unhandled property type %s", f->Type->DescriptiveName());
}
vector_ok:
exp->ToErrorNode(); // invalidate after processing.
exp = static_cast<ZCC_Expression *>(exp->SiblingNext);
}

View file

@ -18,6 +18,7 @@ private:
void CompileAllProperties();
bool CompileProperties(PClass *type, TArray<ZCC_Property *> &Properties, FName prefix);
bool CompileFlagDefs(PClass *type, TArray<ZCC_FlagDef *> &Properties, FName prefix);
bool CompileFlagDefs(PContainerType* type, TArray<ZCC_FlagDef*>& Properties, FName prefix);
void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *property, DCoreActor *defaults, Baggage &bag);
void DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *property, DCoreActor *defaults, Baggage &bag);
void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *prop, Baggage &bag);

View file

@ -6225,7 +6225,7 @@ DBloodActor* actSpawnDude(DBloodActor* source, int nType, double dist)
spawned->xspr.dudeGuard = source->xspr.dudeGuard;
spawned->xspr.dudeAmbush = source->xspr.dudeAmbush;
spawned->xspr.dudeFlag4 = source->xspr.dudeFlag4;
spawned->xspr.unused1 = source->xspr.unused1;
spawned->xspr.modernFlags = source->xspr.modernFlags;
break;
}
}

View file

@ -1924,12 +1924,12 @@ void aiInitSprite(DBloodActor* actor)
if (stateTimer > 0)
{
if (uwater) aiPatrolState(actor, kAiStatePatrolWaitW);
else if (actor->xspr.unused1 & kDudeFlagCrouch) aiPatrolState(actor, kAiStatePatrolWaitC);
else if (actor->xspr.modernFlags & kDudeFlagCrouch) aiPatrolState(actor, kAiStatePatrolWaitC);
else aiPatrolState(actor, kAiStatePatrolWaitL);
actor->xspr.stateTimer = stateTimer; // restore state timer
}
else if (uwater) aiPatrolState(actor, kAiStatePatrolMoveW);
else if (actor->xspr.unused1 & kDudeFlagCrouch) aiPatrolState(actor, kAiStatePatrolMoveC);
else if (actor->xspr.modernFlags & kDudeFlagCrouch) aiPatrolState(actor, kAiStatePatrolMoveC);
else aiPatrolState(actor, kAiStatePatrolMoveL);
}
}

View file

@ -1907,7 +1907,7 @@ DBloodActor* genDudeSpawn(DBloodActor* source, DBloodActor* actor, double nDist)
spawned->xspr.dudeGuard = source->xspr.dudeGuard;
spawned->xspr.dudeAmbush = source->xspr.dudeAmbush;
spawned->xspr.dudeFlag4 = source->xspr.dudeFlag4;
spawned->xspr.unused1 = source->xspr.unused1;
spawned->xspr.modernFlags = source->xspr.modernFlags;
break;
}
}
@ -1986,7 +1986,7 @@ void genDudeTransform(DBloodActor* actor)
actor->xspr.dudeDeaf = actIncarnation->xspr.dudeDeaf;
actor->xspr.dudeAmbush = actIncarnation->xspr.dudeAmbush;
actor->xspr.dudeFlag4 = actIncarnation->xspr.dudeFlag4;
actor->xspr.unused1 = actIncarnation->xspr.unused1;
actor->xspr.modernFlags = actIncarnation->xspr.modernFlags;
actor->xspr.dropMsg = actIncarnation->xspr.dropMsg;
actor->xspr.key = actIncarnation->xspr.key;

View file

@ -341,7 +341,7 @@ void dbLoadMap(const char* pPath, DVector3& pos, short* pAngle, sectortype** cur
pXSector->Depth = bitReader.readUnsigned(3);
pXSector->panVel = bitReader.readUnsigned(8);
pXSector->panAngle = mapangle(bitReader.readUnsigned(11));
pXSector->unused1 = bitReader.readUnsigned(1);
pXSector->pauseMotion = bitReader.readUnsigned(1);
pXSector->decoupled = bitReader.readUnsigned(1);
pXSector->triggerOnce = bitReader.readUnsigned(1);
pXSector->isTriggered = bitReader.readUnsigned(1);
@ -535,9 +535,9 @@ void dbLoadMap(const char* pPath, DVector3& pos, short* pAngle, sectortype** cur
pXSprite->waitTime = bitReader.readUnsigned(12);
pXSprite->restState = bitReader.readUnsigned(1);
pXSprite->Interrutable = bitReader.readUnsigned(1);
pXSprite->unused1 = bitReader.readUnsigned(2);
pXSprite->modernFlags = bitReader.readUnsigned(2);
pXSprite->respawnPending = bitReader.readUnsigned(2);
pXSprite->unused2 = bitReader.readUnsigned(1);
pXSprite->patrolstate = bitReader.readUnsigned(1);
pXSprite->lT = bitReader.readUnsigned(1);
pXSprite->dropMsg = bitReader.readUnsigned(8);
pXSprite->Decoupled = bitReader.readUnsigned(1);
@ -551,7 +551,7 @@ void dbLoadMap(const char* pPath, DVector3& pos, short* pAngle, sectortype** cur
pXSprite->Touch = bitReader.readUnsigned(1);
pXSprite->Sight = bitReader.readUnsigned(1);
pXSprite->Proximity = bitReader.readUnsigned(1);
pXSprite->unused3 = bitReader.readUnsigned(2);
pXSprite->sightstuff = bitReader.readUnsigned(2);
pXSprite->lSkill = bitReader.readUnsigned(5);
pXSprite->lS = bitReader.readUnsigned(1);
pXSprite->lB = bitReader.readUnsigned(1);
@ -566,7 +566,7 @@ void dbLoadMap(const char* pPath, DVector3& pos, short* pAngle, sectortype** cur
pXSprite->medium = bitReader.readUnsigned(2);
pXSprite->respawn = bitReader.readUnsigned(2);
pXSprite->data4 = bitReader.readUnsigned(16);
pXSprite->unused4 = bitReader.readUnsigned(6);
pXSprite->patrolturndelay = bitReader.readUnsigned(6);
pXSprite->lockMsg = bitReader.readUnsigned(8);
pXSprite->health = bitReader.readUnsigned(12);
pXSprite->dudeDeaf = bitReader.readUnsigned(1);

View file

@ -642,9 +642,12 @@ FSerializer& Serialize(FSerializer& arc, const char* keyname, XSPRITE& w, XSPRIT
("lskill", w.lSkill, def->lSkill)
("lockmsg", w.lockMsg, def->lockMsg)
("dodgedir", w.dodgeDir, def->dodgeDir)
("modernflags", w.unused1, def->unused1)
("sightstuff", w.unused3, def->unused3)
("patrolturndelay", w.unused4, def->unused4)
("wave", w.wave, def->wave)
("medium", w.medium, def->medium)
("respawn", w.respawn, def->respawn)
("modernflags", w.modernFlags, def->modernFlags)
("sightstuff", w.sightstuff, def->sightstuff)
("patrolturndelay", w.patrolturndelay, def->patrolturndelay)
.EndObject();
}
return arc;

View file

@ -91,10 +91,7 @@ struct XSPRITE {
unsigned int dudeAmbush : 1; // dudeAmbush
unsigned int dudeGuard : 1; // dudeGuard
unsigned int dudeFlag4 : 1; // unused
unsigned int wave : 2; // Wave
unsigned int medium : 2; // medium
unsigned int respawn : 2; // Respawn option
unsigned int unused2 : 1; // (new) patrol state
unsigned int patrolstate : 1; // (new) patrol state
};
};
@ -130,9 +127,13 @@ struct XSPRITE {
uint8_t lSkill; // Launch 12345
uint8_t lockMsg; // Lock msg
int8_t dodgeDir; // Dude dodge direction
uint8_t unused1; // modern flags
uint8_t unused3; // something about sight checks
uint8_t unused4; // patrol turn delay
uint8_t wave; // Wave
uint8_t medium; // medium
uint8_t respawn; // Respawn option
uint8_t modernFlags; // modern flags
uint8_t sightstuff; // something about sight checks
uint8_t patrolturndelay; // patrol turn delay
};
@ -185,7 +186,7 @@ struct XSECTOR {
unsigned int bobFloor : 1; // Motion bob floor
unsigned int bobCeiling : 1; // Motion bob ceiling
unsigned int bobRotate : 1; // Motion rotate
unsigned int unused1 : 1; // (new) pause motion
unsigned int pauseMotion : 1; // (new) pause motion
};
};
DBloodActor* marker0;
@ -193,23 +194,23 @@ struct XSECTOR {
DBloodActor* basePath;
DBloodActor* actordata;
uint32_t busy;
double offCeilZ;
double onCeilZ;
double offFloorZ;
double onFloorZ;
DAngle panAngle; // Motion angle
DAngle windAng; // Wind ang
uint32_t windVel; // Wind vel (changed from 10 bit to use higher velocity values)
uint32_t busy;
uint16_t data; // Data
uint16_t txID; // TX ID
uint16_t rxID; // RX ID
uint16_t busyTimeA; // OFF->ON busyTime
uint16_t waitTimeA; // OFF->ON waitTime
DAngle panAngle; // Motion angle
uint16_t busyTimeB; // ON->OFF busyTime
uint16_t waitTimeB; // ON->OFF waitTime
DAngle windAng; // Wind ang
uint16_t bobTheta; // Motion Theta
int16_t bobSpeed; // Motion speed

View file

@ -306,7 +306,7 @@ static DBloodActor* nnExtSpawnDude(DBloodActor* sourceactor, DBloodActor* origin
pDudeActor->xspr.dudeGuard = sourceactor->xspr.dudeGuard;
pDudeActor->xspr.dudeAmbush = sourceactor->xspr.dudeAmbush;
pDudeActor->xspr.dudeFlag4 = sourceactor->xspr.dudeFlag4;
pDudeActor->xspr.unused1 = sourceactor->xspr.unused1;
pDudeActor->xspr.modernFlags = sourceactor->xspr.modernFlags;
}
@ -762,7 +762,7 @@ void nnExtInitModernStuff(TArray<DBloodActor*>& actors)
}
// make Sight, Screen, Aim flags work not just for dudes and things...
if ((actor->xspr.Sight || actor->xspr.unused3) && gSightSpritesCount < kMaxSuperXSprites)
if ((actor->xspr.Sight || actor->xspr.sightstuff) && gSightSpritesCount < kMaxSuperXSprites)
{
switch (actor->spr.statnum)
{
@ -1204,7 +1204,7 @@ void nnExtProcessSuperSprites()
pSight->xspr.isTriggered) continue; // don't process locked or triggered sprites
// sprite is drawn for one of players
if ((pSight->xspr.unused3 & kTriggerSpriteScreen) && (pSight->spr.cstat2 & CSTAT2_SPRITE_MAPPED))
if ((pSight->xspr.sightstuff & kTriggerSpriteScreen) && (pSight->spr.cstat2 & CSTAT2_SPRITE_MAPPED))
{
trTriggerSprite(pSight, kCmdSpriteSight);
pSight->spr.cstat2 &= ~CSTAT2_SPRITE_MAPPED;
@ -1230,7 +1230,7 @@ void nnExtProcessSuperSprites()
trTriggerSprite(pSight, kCmdSpriteSight, plActor);
}
if (pSight->xspr.unused3 & kTriggerSpriteAim)
if (pSight->xspr.sightstuff & kTriggerSpriteAim)
{
bool vector = (pSight->spr.cstat & CSTAT_SPRITE_BLOCK_HITSCAN);
if (!vector)
@ -4232,7 +4232,7 @@ bool condCheckSector(DBloodActor* aCond, int cmpOp, bool PUSH)
}
}
case 57: // this sector in movement?
return !pXSect->unused1;
return !pXSect->pauseMotion;
}
}
else
@ -4462,7 +4462,7 @@ bool condCheckDude(DBloodActor* aCond, int cmpOp, bool PUSH)
case 6: return objActor->xspr.dudeDeaf;
case 7: return objActor->xspr.dudeGuard;
case 8: return objActor->xspr.dudeAmbush;
case 9: return (objActor->xspr.unused1 & kDudeFlagStealth);
case 9: return (objActor->xspr.modernFlags & kDudeFlagStealth);
case 10: // check if the marker is busy with another dude
case 11: // check if the marker is reached
if (!objActor->xspr.dudeFlag4 || !targ || targ->GetType() != kMarkerPath) return false;
@ -4482,7 +4482,7 @@ bool condCheckDude(DBloodActor* aCond, int cmpOp, bool PUSH)
return true;
case 12: // compare spot progress value in %
if (!objActor->xspr.dudeFlag4 || !targ || targ->GetType() != kMarkerPath) var = 0;
else if (!(objActor->xspr.unused1 & kDudeFlagStealth) || objActor->xspr.data3 < 0 || objActor->xspr.data3 > kMaxPatrolSpotValue) var = 0;
else if (!(objActor->xspr.modernFlags & kDudeFlagStealth) || objActor->xspr.data3 < 0 || objActor->xspr.data3 > kMaxPatrolSpotValue) var = 0;
else var = (kPercFull * objActor->xspr.data3) / kMaxPatrolSpotValue;
return condCmp(var, arg1, arg2, cmpOp);
case 15: return getDudeInfo(objActor)->lockOut; // dude allowed to interact with objects?
@ -5392,7 +5392,7 @@ void sectorPauseMotion(sectortype* pSector, DBloodActor* initiator)
{
if (!pSector->hasX()) return;
XSECTOR* pXSector = &pSector->xs();
pXSector->unused1 = 1;
pXSector->pauseMotion = 1;
evKillSector(pSector, initiator);
@ -5412,7 +5412,7 @@ void sectorContinueMotion(sectortype* pSector, EVENT event)
if (!pSector->hasX()) return;
XSECTOR* pXSector = &pSector->xs();
pXSector->unused1 = 0;
pXSector->pauseMotion = 0;
int busyTimeA = pXSector->busyTimeA;
int waitTimeA = pXSector->waitTimeA;
@ -5534,7 +5534,7 @@ bool modernTypeOperateSector(sectortype* pSector, const EVENT& event)
// continue motion of the paused sector
}
else if (pXSector->unused1)
else if (pXSector->pauseMotion)
{
switch (event.cmd)
{
@ -7811,8 +7811,8 @@ void aiPatrolState(DBloodActor* actor, int state)
if (actor->GetType() == kDudeModernCustom) aiGenDudeNewState(actor, newState);
else aiNewState(actor, newState);
if (crouch) actor->xspr.unused1 |= kDudeFlagCrouch;
else actor->xspr.unused1 &= ~kDudeFlagCrouch;
if (crouch) actor->xspr.modernFlags |= kDudeFlagCrouch;
else actor->xspr.modernFlags &= ~kDudeFlagCrouch;
if (nSeqOverride)
seqSpawn(seq, actor);
@ -7986,11 +7986,11 @@ void aiPatrolSetMarker(DBloodActor* actor)
}
bool node = markerIsNode(targetactor, false);
actor->xspr.unused2 = aiPatrolGetPathDir(actor, targetactor); // decide if it should go back or forward
if (actor->xspr.unused2 == kPatrolMoveBackward && Chance(0x8000) && node)
actor->xspr.unused2 = kPatrolMoveForward;
actor->xspr.patrolstate = aiPatrolGetPathDir(actor, targetactor); // decide if it should go back or forward
if (actor->xspr.patrolstate == kPatrolMoveBackward && Chance(0x8000) && node)
actor->xspr.patrolstate = kPatrolMoveForward;
bool back = (actor->xspr.unused2 == kPatrolMoveBackward); next = (back) ? targetactor->xspr.data1 : targetactor->xspr.data2;
bool back = (actor->xspr.patrolstate == kPatrolMoveBackward); next = (back) ? targetactor->xspr.data1 : targetactor->xspr.data2;
BloodStatIterator it(kStatPathMarker);
while (auto nextactor = it.Next())
{
@ -8043,8 +8043,8 @@ void aiPatrolStop(DBloodActor* actor, DBloodActor* targetactor, bool alarm)
if (actor->hasX())
{
actor->xspr.data3 = 0; // reset spot progress
actor->xspr.unused1 &= ~kDudeFlagCrouch; // reset the crouch status
actor->xspr.unused2 = kPatrolMoveForward; // reset path direction
actor->xspr.modernFlags &= ~kDudeFlagCrouch; // reset the crouch status
actor->xspr.patrolstate = kPatrolMoveForward; // reset path direction
actor->prevmarker = nullptr;
actor->xspr.TargetPos.X = -1; // reset the previous marker index
if (actor->xspr.health <= 0)
@ -8202,7 +8202,7 @@ void aiPatrolMove(DBloodActor* actor)
actor->vel += actor->spr.Angles.Yaw.ToVector() * FixedToFloat(frontSpeed);
}
double vel = (actor->xspr.unused1 & kDudeFlagCrouch) ? kMaxPatrolCrouchVelocity : kMaxPatrolVelocity;
double vel = (actor->xspr.modernFlags & kDudeFlagCrouch) ? kMaxPatrolCrouchVelocity : kMaxPatrolVelocity;
vel *= dv.XY().Length() / 1024; // was: MulScale16 with length << 6, effectively resulting in >> 10.
actor->vel.X = clamp(actor->vel.X, -vel, vel);
@ -8395,7 +8395,7 @@ DBloodActor* aiPatrolSearchTargets(DBloodActor* actor)
}
int i, mod, sndCnt = 0, seeChance, hearChance;
bool stealth = (actor->xspr.unused1 & kDudeFlagStealth);
bool stealth = (actor->xspr.modernFlags & kDudeFlagStealth);
bool blind = (actor->xspr.dudeGuard);
bool deaf = (actor->xspr.dudeDeaf);
int nRandomSkill = Random(gGameOptions.nDifficulty);
@ -8715,10 +8715,10 @@ void aiPatrolFlagsMgr(DBloodActor* sourceactor, DBloodActor* destactor, bool cop
destactor->xspr.dudeAmbush = sourceactor->xspr.dudeAmbush;
destactor->xspr.dudeGuard = sourceactor->xspr.dudeGuard;
destactor->xspr.dudeDeaf = sourceactor->xspr.dudeDeaf;
destactor->xspr.unused1 = sourceactor->xspr.unused1;
destactor->xspr.modernFlags = sourceactor->xspr.modernFlags;
if (sourceactor->xspr.unused1 & kDudeFlagStealth) destactor->xspr.unused1 |= kDudeFlagStealth;
else destactor->xspr.unused1 &= ~kDudeFlagStealth;
if (sourceactor->xspr.modernFlags & kDudeFlagStealth) destactor->xspr.modernFlags |= kDudeFlagStealth;
else destactor->xspr.modernFlags &= ~kDudeFlagStealth;
}
// do init
@ -8753,7 +8753,7 @@ void aiPatrolFlagsMgr(DBloodActor* sourceactor, DBloodActor* destactor, bool cop
bool aiPatrolGetPathDir(DBloodActor* actor, DBloodActor* marker)
{
if (actor->xspr.unused2 == kPatrolMoveForward) return (marker->xspr.data2 == -2) ? (bool)kPatrolMoveBackward : (bool)kPatrolMoveForward;
if (actor->xspr.patrolstate == kPatrolMoveForward) return (marker->xspr.data2 == -2) ? (bool)kPatrolMoveBackward : (bool)kPatrolMoveForward;
else return (findNextMarker(marker, kPatrolMoveBackward) != nullptr) ? (bool)kPatrolMoveBackward : (bool)kPatrolMoveForward;
}
@ -8777,7 +8777,7 @@ void aiPatrolThink(DBloodActor* actor)
}
bool crouch = (actor->xspr.unused1 & kDudeFlagCrouch), uwater = spriteIsUnderwater(actor);
bool crouch = (actor->xspr.modernFlags & kDudeFlagCrouch), uwater = spriteIsUnderwater(actor);
if (markeractor == nullptr || (actor->GetType() == kDudeModernCustom && ((uwater && !canSwim(actor)) || !canWalk(actor))))
{
aiPatrolStop(actor, nullptr);
@ -8785,7 +8785,7 @@ void aiPatrolThink(DBloodActor* actor)
}
const DUDEINFO_EXTRA* pExtra = &gDudeInfoExtra[actor->GetType() - kDudeBase];
bool isFinal = ((!actor->xspr.unused2 && markeractor->xspr.data2 == -1) || (actor->xspr.unused2 && markeractor->xspr.data1 == -1));
bool isFinal = ((!actor->xspr.patrolstate && markeractor->xspr.data2 == -1) || (actor->xspr.patrolstate && markeractor->xspr.data1 == -1));
bool reached = false;
if (aiPatrolWaiting(actor->xspr.aiState))
@ -8802,12 +8802,12 @@ void aiPatrolThink(DBloodActor* actor)
{
stateTimer = actor->xspr.stateTimer;
if (--actor->xspr.unused4 <= 0)
if (--actor->xspr.patrolturndelay <= 0)
{
if (uwater) aiPatrolState(actor, kAiStatePatrolTurnW);
else if (crouch) aiPatrolState(actor, kAiStatePatrolTurnC);
else aiPatrolState(actor, kAiStatePatrolTurnL);
actor->xspr.unused4 = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange);
actor->xspr.patrolturndelay = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange);
}
// must restore stateTimer for waiting
@ -8879,7 +8879,7 @@ void aiPatrolThink(DBloodActor* actor)
// take marker's angle
if (!(markeractor->spr.flags & kModernTypeFlag4))
{
actor->xspr.goalAng = ((!(markeractor->spr.flags & kModernTypeFlag8) && actor->xspr.unused2) ? markeractor->spr.Angles.Yaw+ DAngle180 : markeractor->spr.Angles.Yaw).Normalized360();
actor->xspr.goalAng = ((!(markeractor->spr.flags & kModernTypeFlag8) && actor->xspr.patrolstate) ? markeractor->spr.Angles.Yaw+ DAngle180 : markeractor->spr.Angles.Yaw).Normalized360();
if (absangle(actor->spr.Angles.Yaw, actor->xspr.goalAng) > minAngle) // let the enemy play move animation while turning
return;
}
@ -8912,7 +8912,7 @@ void aiPatrolThink(DBloodActor* actor)
actor->xspr.stateTimer = (markeractor->xspr.waitTime * 120) / 10;
if (markeractor->spr.flags & kModernTypeFlag16)
actor->xspr.unused4 = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange);
actor->xspr.patrolturndelay = kMinPatrolTurnDelay + Random(kPatrolTurnDelayRange);
return;
}

View file

@ -172,7 +172,7 @@ bool isMovableSector(sectortype* pSect)
{
if (isMovableSector(pSect->type) && pSect->hasX())
{
return (pSect->xs().busy && !pSect->xs().unused1);
return (pSect->xs().busy && !pSect->xs().pauseMotion);
}
return false;
}

View file

@ -1717,7 +1717,7 @@ void OperateSector(sectortype* pSector, EVENT event)
break;
default:
#ifdef NOONE_EXTENSIONS
if (gModernMap && pXSector->unused1) break;
if (gModernMap && pXSector->pauseMotion) break;
#endif
switch (pSector->type) {
case kSectorZMotionSprite:
@ -2205,7 +2205,7 @@ void trProcessBusy(void)
int oldBusy = gBusy[i].busy;
gBusy[i].busy = ClipRange(oldBusy + gBusy[i].delta * 4, 0, 65536);
#ifdef NOONE_EXTENSIONS
if (!gModernMap || !gBusy[i].sect->xs().unused1) nStatus = gBusyProc[gBusy[i].type](gBusy[i].sect, gBusy[i].busy, nullptr);
if (!gModernMap || !gBusy[i].sect->xs().pauseMotion) nStatus = gBusyProc[gBusy[i].type](gBusy[i].sect, gBusy[i].busy, nullptr);
else nStatus = 3; // allow to pause/continue motion for sectors any time by sending special command
#else
nStatus = gBusyProc[gBusy[i].type](gBusy[i].at0, gBusy[i].at8);

View file

@ -4,13 +4,13 @@ Copyright (C) 2020-2023 - Christoph Oelckers
This file is part of Raze
This is free software; you can redistribute it and/or
This is free software;you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
as published by the Free Software Foundation;either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY;without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
@ -25,6 +25,57 @@ See the GNU General Public License for more details.
BEGIN_BLD_NS
DEFINE_FIELD_X(XSECTOR, XSECTOR, flags)
DEFINE_FIELD_X(XSECTOR, XSECTOR, flags2)
DEFINE_FIELD_X(XSECTOR, XSECTOR, marker0)
DEFINE_FIELD_X(XSECTOR, XSECTOR, marker1)
DEFINE_FIELD_X(XSECTOR, XSECTOR, basePath)
DEFINE_FIELD_X(XSECTOR, XSECTOR, actordata)
DEFINE_FIELD_X(XSECTOR, XSECTOR, busy)
DEFINE_FIELD_X(XSECTOR, XSECTOR, offCeilZ)
DEFINE_FIELD_X(XSECTOR, XSECTOR, onCeilZ)
DEFINE_FIELD_X(XSECTOR, XSECTOR, offFloorZ)
DEFINE_FIELD_X(XSECTOR, XSECTOR, onFloorZ)
DEFINE_FIELD_X(XSECTOR, XSECTOR, windVel)
DEFINE_FIELD_X(XSECTOR, XSECTOR, data)
DEFINE_FIELD_X(XSECTOR, XSECTOR, txID)
DEFINE_FIELD_X(XSECTOR, XSECTOR, rxID)
DEFINE_FIELD_X(XSECTOR, XSECTOR, busyTimeA)
DEFINE_FIELD_X(XSECTOR, XSECTOR, waitTimeA)
DEFINE_FIELD_X(XSECTOR, XSECTOR, panAngle)
DEFINE_FIELD_X(XSECTOR, XSECTOR, busyTimeB)
DEFINE_FIELD_X(XSECTOR, XSECTOR, waitTimeB)
DEFINE_FIELD_X(XSECTOR, XSECTOR, windAng)
DEFINE_FIELD_X(XSECTOR, XSECTOR, bobTheta)
DEFINE_FIELD_X(XSECTOR, XSECTOR, bobSpeed)
DEFINE_FIELD_X(XSECTOR, XSECTOR, busyWaveA)
DEFINE_FIELD_X(XSECTOR, XSECTOR, busyWaveB)
DEFINE_FIELD_X(XSECTOR, XSECTOR, command)
DEFINE_FIELD_X(XSECTOR, XSECTOR, amplitude)
DEFINE_FIELD_X(XSECTOR, XSECTOR, freq)
DEFINE_FIELD_X(XSECTOR, XSECTOR, phase)
DEFINE_FIELD_X(XSECTOR, XSECTOR, wave)
DEFINE_FIELD_X(XSECTOR, XSECTOR, shade)
DEFINE_FIELD_X(XSECTOR, XSECTOR, panVel)
DEFINE_FIELD_X(XSECTOR, XSECTOR, Depth)
DEFINE_FIELD_X(XSECTOR, XSECTOR, Key)
DEFINE_FIELD_X(XSECTOR, XSECTOR, ceilpal)
DEFINE_FIELD_X(XSECTOR, XSECTOR, damageType)
DEFINE_FIELD_X(XSECTOR, XSECTOR, floorpal)
DEFINE_FIELD_X(XSECTOR, XSECTOR, bobZRange)
DEFINE_FIELD_X(XWALL, XWALL, flags)
DEFINE_FIELD_X(XWALL, XWALL, busy)
DEFINE_FIELD_X(XWALL, XWALL, data)
DEFINE_FIELD_X(XWALL, XWALL, txID)
DEFINE_FIELD_X(XWALL, XWALL, rxID)
DEFINE_FIELD_X(XWALL, XWALL, busyTime)
DEFINE_FIELD_X(XWALL, XWALL, waitTime)
DEFINE_FIELD_X(XWALL, XWALL, command)
DEFINE_FIELD_NAMED_X(XWALL, XWALL, panVel.X, panVelX) // VM does not support int vectors.
DEFINE_FIELD_NAMED_X(XWALL, XWALL, panVel.Y, panVelY)
DEFINE_FIELD_X(XWALL, XWALL, key)
void Blood_ChangeType(DBloodActor* self, PClassActor* type)
{

View file

@ -110,6 +110,93 @@ enum ESectorExBits
//=============================================================================
//
// Blood's sector extension.
//
//=============================================================================
struct XSECTOR native
{
native uint flags;
native int flags2;
native BloodActor marker0;
native BloodActor marker1;
native BloodActor basePath;
native BloodActor actordata;
native uint busy;
native double offCeilZ;
native double onCeilZ;
native double offFloorZ;
native double onFloorZ;
native uint windVel;
native uint16 data;
native uint16 txID;
native uint16 rxID;
native uint16 busyTimeA;
native uint16 waitTimeA;
native double panAngle;
native uint16 busyTimeB;
native uint16 waitTimeB;
native double windAng;
native uint16 bobTheta;
native int16 bobSpeed;
native uint8 busyWaveA;
native uint8 busyWaveB;
native uint8 command;
native int8 amplitude;
native uint8 freq;
native uint8 phase;
native uint8 wave;
native int8 shade;
native uint8 panVel;
native uint8 Depth;
native uint8 Key;
native uint8 ceilpal;
native uint8 damageType;
native uint8 floorpal;
native uint8 bobZRange;
flagdef internal state: flags, 0;
flagdef internal triggerOn: flags, 1;
flagdef internal triggerOff: flags, 2;
flagdef internal restState: flags, 3;
flagdef internal interruptable: flags, 4;
flagdef internal reTriggerA: flags, 5;
flagdef internal reTriggerB: flags, 6;
flagdef internal shadeAlways: flags, 7;
flagdef internal shadeFloor: flags, 8;
flagdef internal shadeCeiling: flags, 9;
flagdef internal shadeWalls: flags, 10;
flagdef internal panAlways: flags, 11;
flagdef internal panFloor: flags, 12;
flagdef internal panCeiling: flags, 13;
flagdef internal Drag: flags, 14;
flagdef internal Underwater: flags, 15;
flagdef internal decoupled: flags, 16;
flagdef internal triggerOnce: flags, 17;
flagdef internal isTriggered: flags, 18;
flagdef internal Push: flags, 19;
flagdef internal Vector: flags, 20;
flagdef internal Reserved: flags, 21;
flagdef internal Enter: flags, 22;
flagdef internal Exit: flags, 23;
flagdef internal Wallpush: flags, 24;
flagdef internal color: flags, 25;
flagdef internal stopOn: flags, 26;
flagdef internal stopOff: flags, 27;
flagdef internal Crush: flags, 28;
flagdef internal locked: flags, 29;
flagdef internal windAlways: flags, 30;
flagdef internal dudeLockout: flags2, 0;
flagdef internal bobAlways: flags2, 1;
flagdef internal bobFloor: flags2, 2;
flagdef internal bobCeiling: flags2, 3;
flagdef internal bobRotate: flags2, 4;
flagdef internal pauseMotion: flags2, 5;
}
//=============================================================================
//
// internal sector struct - no longer identical with on-disk format
@ -177,7 +264,7 @@ struct sectortype native
native uint8 shadedsector;
DukeActor hitagactor; // we need this because Duke stores an actor in the hitag field. Is really a DDukeActor, but cannot be declared here safely.
//native XSECTOR x;
native XSECTOR x;
native BloodActor upperLink;
native BloodActor lowerLink;
native double baseFloor;
@ -244,6 +331,43 @@ struct sectortype native
}
//=============================================================================
//
// Blood's wall extension.
//
//=============================================================================
struct XWALL native {
native uint flags;
native uint busy;
native int16 data;
native uint16 txID;
native uint16 rxID;
native uint16 busyTime;
native uint16 waitTime;
native uint8 command;
native int panVelX;
native int panVelY;
native uint8 key;
flagdef internal state: flags, 0;
flagdef internal triggerOn: flags, 1;
flagdef internal triggerOff: flags, 2;
flagdef internal restState: flags, 3;
flagdef internal interruptable: flags, 4;
flagdef internal panAlways: flags, 5;
flagdef internal decoupled: flags, 6;
flagdef internal triggerOnce: flags, 7;
flagdef internal isTriggered: flags, 8;
flagdef internal triggerPush: flags, 9;
flagdef internal triggerVector: flags, 10;
flagdef internal triggerTouch: flags, 11;
flagdef internal locked: flags, 12;
flagdef internal dudeLockout: flags, 13;
}
//=============================================================================
//
// internal wall struct - no longer identical with on-disk format
@ -281,7 +405,7 @@ struct walltype native
//native uint8 xrepeat; // these are still bytes, do not export unless floatified
//native uint8 yrepeat;
//native XWALL x;
native XWALL x;
native void setxpan(double add);