Merge commit '6b5be653dc'
This commit is contained in:
commit
58ddcd4806
65 changed files with 1310 additions and 332 deletions
|
|
@ -19,6 +19,8 @@ LineEdit::LineEdit(Widget* parent) : Widget(parent)
|
|||
|
||||
LineEdit::~LineEdit()
|
||||
{
|
||||
delete timer;
|
||||
delete scroll_timer;
|
||||
}
|
||||
|
||||
bool LineEdit::IsReadOnly() const
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
// texture to behave like an impassable line (projectiles
|
||||
// pass through it).
|
||||
checkswitchrange = <bool>; // Switches can only be activated when vertically reachable.
|
||||
walking = <bool>; // Crossing activation checks if creature is on the ground, and fails if they are not.
|
||||
blockprojectiles = <bool>; // Line blocks all projectiles
|
||||
blockuse = <bool>; // Line blocks all use actions
|
||||
blocksight = <bool>; // Line blocks monster line of sight
|
||||
|
|
@ -306,6 +307,8 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
|||
leakiness = <int>; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0.
|
||||
damageterraineffect = <bool>; // Will spawn a terrain splash when damage is inflicted. Default = false.
|
||||
damagehazard = <bool>; // Changes damage model to Strife's delayed damage for the given sector. Default = false.
|
||||
hurtmonsters = <bool>; // Non-players like monsters and decorations are hurt by this sector in the same manner as player. Doesn't work with damagehazard.
|
||||
harminair = <bool>; // Actors in this sector are harmed by the damage effects of the floor even if they aren't touching it.
|
||||
floorterrain = <string>; // Sets the terrain for the sector's floor. Default = 'use the flat texture's terrain definition.'
|
||||
ceilingterrain = <string>; // Sets the terrain for the sector's ceiling. Default = 'use the flat texture's terrain definition.'
|
||||
floor_reflect = <float>; // reflectiveness of floor (OpenGL only, not functional on sloped sectors)
|
||||
|
|
|
|||
|
|
@ -592,6 +592,10 @@ void DShape2D::OnDestroy() {
|
|||
|
||||
void F2DDrawer::AddShape(FGameTexture* img, DShape2D* shape, DrawParms& parms)
|
||||
{
|
||||
// bail if shape is null (shouldn't happen but it might)
|
||||
if (!shape)
|
||||
ThrowAbortException(X_OTHER, "shape is null");
|
||||
|
||||
// [MK] bail out if vertex/coord array sizes are mismatched
|
||||
if ( shape->mVertices.Size() != shape->mCoords.Size() )
|
||||
ThrowAbortException(X_OTHER, "Mismatch in vertex/coord count: %u != %u", shape->mVertices.Size(), shape->mCoords.Size());
|
||||
|
|
|
|||
|
|
@ -130,6 +130,24 @@ static FileReader OpenMusic(const char* musicname)
|
|||
return reader;
|
||||
}
|
||||
|
||||
bool MusicExists(const char* music_name)
|
||||
{
|
||||
if (music_name == nullptr)
|
||||
return false;
|
||||
|
||||
if (FileExists(music_name))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
int lumpnum;
|
||||
lumpnum = mus_cb.FindMusic(music_name);
|
||||
if (lumpnum == -1) lumpnum = fileSystem.CheckNumForName(music_name, FileSys::ns_music);
|
||||
if (lumpnum != -1 && fileSystem.FileLength(lumpnum) != 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void S_SetMusicCallbacks(MusicCallbacks* cb)
|
||||
{
|
||||
mus_cb = *cb;
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ bool S_StartMusic (const char *music_name);
|
|||
// Start music using <music_name>, and set whether looping
|
||||
bool S_ChangeMusic (const char *music_name, int order=0, bool looping=true, bool force=false);
|
||||
|
||||
// Check if <music_name> exists
|
||||
bool MusicExists(const char* music_name);
|
||||
|
||||
void S_RestartMusic ();
|
||||
void S_MIDIDeviceChanged(int newdev);
|
||||
|
||||
|
|
|
|||
|
|
@ -278,6 +278,8 @@ xx(BuiltinNameToClass)
|
|||
xx(BuiltinClassCast)
|
||||
xx(BuiltinFunctionPtrCast)
|
||||
xx(BuiltinFindTranslation)
|
||||
xx(HandleDeprecatedFlags)
|
||||
xx(CheckDeprecatedFlags)
|
||||
|
||||
xx(ScreenJobRunner)
|
||||
xx(Action)
|
||||
|
|
|
|||
|
|
@ -197,7 +197,10 @@ void FSerializer::Close()
|
|||
}
|
||||
if (mErrors > 0)
|
||||
{
|
||||
I_Error("%d errors parsing JSON", mErrors);
|
||||
if (mLumpName.IsNotEmpty())
|
||||
I_Error("%d errors parsing JSON lump %s", mErrors, mLumpName.GetChars());
|
||||
else
|
||||
I_Error("%d errors parsing JSON", mErrors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -331,6 +334,28 @@ bool FSerializer::HasObject(const char* name)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FSerializer::IsKeyNull(const char* name)
|
||||
{
|
||||
if (isReading())
|
||||
{
|
||||
auto val = r->FindKey(name);
|
||||
if (val != nullptr)
|
||||
{
|
||||
if (val->IsNull())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FSerializer::EndObject()
|
||||
{
|
||||
if (isWriting())
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public:
|
|||
void EndObject();
|
||||
bool HasKey(const char* name);
|
||||
bool HasObject(const char* name);
|
||||
bool IsKeyNull(const char* name);
|
||||
bool BeginArray(const char *name);
|
||||
void EndArray();
|
||||
unsigned GetSize(const char *group);
|
||||
|
|
@ -225,6 +226,7 @@ public:
|
|||
|
||||
int mErrors = 0;
|
||||
int mObjectErrors = 0;
|
||||
FString mLumpName;
|
||||
};
|
||||
|
||||
FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval);
|
||||
|
|
|
|||
|
|
@ -2828,83 +2828,104 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
|
|||
|
||||
// Special case: Assignment to a bitfield.
|
||||
IsBitWrite = Base->GetBitValue();
|
||||
if (IsBitWrite >= 0x10000)
|
||||
{
|
||||
// internal flags - need more here
|
||||
IsBitWrite &= 0xffff;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP };
|
||||
assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType());
|
||||
|
||||
ExpEmit pointer = Base->Emit(build);
|
||||
Address = pointer;
|
||||
|
||||
ExpEmit result;
|
||||
bool intconst = false;
|
||||
int intconstval = 0;
|
||||
|
||||
if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT)
|
||||
if (IsBitWrite < 64)
|
||||
{
|
||||
intconst = true;
|
||||
intconstval = static_cast<FxConstant*>(Right)->GetValue().GetInt();
|
||||
result.Konst = true;
|
||||
result.RegType = REGT_INT;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Right->Emit(build);
|
||||
}
|
||||
assert(result.RegType <= REGT_TYPE);
|
||||
static const uint8_t loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP };
|
||||
assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType());
|
||||
|
||||
if (pointer.Target)
|
||||
{
|
||||
if (result.Konst)
|
||||
ExpEmit pointer = Base->Emit(build);
|
||||
Address = pointer;
|
||||
|
||||
ExpEmit result;
|
||||
bool intconst = false;
|
||||
int intconstval = 0;
|
||||
|
||||
if (Right->isConstant() && Right->ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval);
|
||||
else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum);
|
||||
intconst = true;
|
||||
intconstval = static_cast<FxConstant*>(Right)->GetValue().GetInt();
|
||||
result.Konst = true;
|
||||
result.RegType = REGT_INT;
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum);
|
||||
result = Right->Emit(build);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.Konst)
|
||||
assert(result.RegType <= REGT_TYPE);
|
||||
|
||||
if (pointer.Target)
|
||||
{
|
||||
if (result.Konst)
|
||||
{
|
||||
if (intconst) build->EmitLoadInt(pointer.RegNum, intconstval);
|
||||
else build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result.Konst)
|
||||
{
|
||||
ExpEmit temp(build, result.RegType);
|
||||
if (intconst) build->EmitLoadInt(temp.RegNum, intconstval);
|
||||
else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum);
|
||||
result.Free(build);
|
||||
result = temp;
|
||||
}
|
||||
|
||||
if (IsBitWrite == -1)
|
||||
{
|
||||
build->Emit(Base->ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite);
|
||||
}
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
ExpEmit temp(build, result.RegType);
|
||||
if (intconst) build->EmitLoadInt(temp.RegNum, intconstval);
|
||||
else build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum);
|
||||
result.Free(build);
|
||||
result = temp;
|
||||
return pointer;
|
||||
}
|
||||
|
||||
if (IsBitWrite == -1)
|
||||
{
|
||||
build->Emit(Base->ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0));
|
||||
pointer.Free(build);
|
||||
|
||||
if (intconst)
|
||||
{ //fix int constant return for assignment
|
||||
return Right->Emit(build);
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_SBIT, pointer.RegNum, result.RegNum, 1 << IsBitWrite);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
result.Free(build);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
pointer.Free(build);
|
||||
|
||||
if(intconst)
|
||||
{ //fix int constant return for assignment
|
||||
return Right->Emit(build);
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;
|
||||
VMFunction* callfunc;
|
||||
auto sym = FindBuiltinFunction(NAME_HandleDeprecatedFlags);
|
||||
|
||||
assert(sym);
|
||||
callfunc = sym->Variants[0].Implementation;
|
||||
|
||||
FunctionCallEmitter emitters(callfunc);
|
||||
emitters.AddParameter(build, Base);
|
||||
emitters.AddParameter(build, Right);
|
||||
emitters.AddParameterIntConst(IsBitWrite - 64);
|
||||
return emitters.EmitCall(build);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2934,23 +2955,40 @@ FxExpression *FxAssignSelf::Resolve(FCompileContext &ctx)
|
|||
|
||||
ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it
|
||||
if (!pointer.Target)
|
||||
if (Assignment->IsBitWrite < 64)
|
||||
{
|
||||
ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
if (Assignment->IsBitWrite != -1)
|
||||
ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it
|
||||
if (!pointer.Target)
|
||||
{
|
||||
build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite);
|
||||
ExpEmit out(build, ValueType->GetRegType(), ValueType->GetRegCount());
|
||||
if (Assignment->IsBitWrite == -1)
|
||||
{
|
||||
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_LBIT, out.RegNum, pointer.RegNum, 1 << Assignment->IsBitWrite);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0));
|
||||
return pointer;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pointer;
|
||||
VMFunction* callfunc;
|
||||
auto sym = FindBuiltinFunction(NAME_CheckDeprecatedFlags);
|
||||
|
||||
assert(sym);
|
||||
callfunc = sym->Variants[0].Implementation;
|
||||
|
||||
FunctionCallEmitter emitters(callfunc);
|
||||
emitters.AddParameter(build, Assignment->Base);
|
||||
emitters.AddParameterIntConst(Assignment->IsBitWrite - 64);
|
||||
emitters.AddReturn(REGT_INT);
|
||||
return emitters.EmitCall(build);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7728,56 +7766,73 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
|||
|
||||
ExpEmit FxStructMember::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit obj = classx->Emit(build);
|
||||
assert(obj.RegType == REGT_POINTER);
|
||||
|
||||
if (obj.Konst)
|
||||
if (membervar->BitValue < 64 || AddressRequested)
|
||||
{
|
||||
// If the situation where we are dereferencing a constant
|
||||
// pointer is common, then it would probably be worthwhile
|
||||
// to add new opcodes for those. But as of right now, I
|
||||
// don't expect it to be a particularly common case.
|
||||
ExpEmit newobj(build, REGT_POINTER);
|
||||
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
|
||||
obj = newobj;
|
||||
}
|
||||
ExpEmit obj = classx->Emit(build);
|
||||
assert(obj.RegType == REGT_POINTER);
|
||||
|
||||
if (membervar->Flags & VARF_Meta)
|
||||
{
|
||||
obj.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, obj.RegNum);
|
||||
obj = meta;
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
if (membervar->Offset == 0)
|
||||
if (obj.Konst)
|
||||
{
|
||||
return obj;
|
||||
// If the situation where we are dereferencing a constant
|
||||
// pointer is common, then it would probably be worthwhile
|
||||
// to add new opcodes for those. But as of right now, I
|
||||
// don't expect it to be a particularly common case.
|
||||
ExpEmit newobj(build, REGT_POINTER);
|
||||
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
|
||||
obj = newobj;
|
||||
}
|
||||
|
||||
if (membervar->Flags & VARF_Meta)
|
||||
{
|
||||
obj.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, obj.RegNum);
|
||||
obj = meta;
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
if (membervar->Offset == 0)
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
obj.Free(build);
|
||||
ExpEmit out(build, REGT_POINTER);
|
||||
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset));
|
||||
return out;
|
||||
}
|
||||
|
||||
int offsetreg = build->GetConstantInt((int)membervar->Offset);
|
||||
ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount());
|
||||
|
||||
if (membervar->BitValue == -1)
|
||||
{
|
||||
build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpEmit out(build, REGT_POINTER);
|
||||
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg);
|
||||
build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue);
|
||||
out.Free(build);
|
||||
}
|
||||
obj.Free(build);
|
||||
ExpEmit out(build, REGT_POINTER);
|
||||
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset));
|
||||
return out;
|
||||
}
|
||||
|
||||
int offsetreg = build->GetConstantInt((int)membervar->Offset);
|
||||
ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount());
|
||||
|
||||
if (membervar->BitValue == -1)
|
||||
{
|
||||
build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg);
|
||||
return loc;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpEmit out(build, REGT_POINTER);
|
||||
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, offsetreg);
|
||||
build->Emit(OP_LBIT, loc.RegNum, out.RegNum, 1 << membervar->BitValue);
|
||||
out.Free(build);
|
||||
VMFunction* callfunc;
|
||||
auto sym = FindBuiltinFunction(NAME_CheckDeprecatedFlags);
|
||||
|
||||
assert(sym);
|
||||
callfunc = sym->Variants[0].Implementation;
|
||||
|
||||
FunctionCallEmitter emitters(callfunc);
|
||||
emitters.AddParameter(build, classx);
|
||||
emitters.AddParameterIntConst(membervar->BitValue - 64);
|
||||
emitters.AddReturn(REGT_INT);
|
||||
return emitters.EmitCall(build);
|
||||
}
|
||||
obj.Free(build);
|
||||
return loc;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -330,7 +330,8 @@ void PType::StaticInit()
|
|||
|
||||
TypeVoidPtr = NewPointer(TypeVoid, false);
|
||||
TypeRawFunction = new PPointer;
|
||||
TypeRawFunction->mDescriptiveName = "Raw Function Pointer";
|
||||
TypeRawFunction->mDescriptiveName = "Raw Function Pointer";
|
||||
TypeTable.AddType(TypeRawFunction, NAME_None);
|
||||
TypeVMFunction = NewPointer(NewStruct("VMFunction", nullptr, true));
|
||||
TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value.
|
||||
TypeStringStruct = NewStruct("Stringstruct", nullptr, true);
|
||||
|
|
|
|||
|
|
@ -1162,6 +1162,17 @@ DEFINE_ACTION_FUNCTION(_Console, PrintfEx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Console, DebugPrintf)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(debugLevel);
|
||||
PARAM_VA_POINTER(va_reginfo);
|
||||
|
||||
FString s = FStringFormat(VM_ARGS_NAMES, 1);
|
||||
DPrintf(debugLevel, "%s\n", s.GetChars());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void StopAllSounds()
|
||||
{
|
||||
soundEngine->StopAllChannels();
|
||||
|
|
|
|||
|
|
@ -372,6 +372,13 @@ FStartScreen* GetGameStartScreen(int max_progress)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
FStartScreen::~FStartScreen()
|
||||
{
|
||||
if (StartupTexture) delete StartupTexture;
|
||||
if (HeaderTexture) delete HeaderTexture;
|
||||
if (NetTexture) delete NetTexture;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ST_Util_ClearBlock
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ protected:
|
|||
FGameTexture* NetTexture = nullptr;
|
||||
public:
|
||||
FStartScreen(int maxp) { MaxPos = maxp; }
|
||||
virtual ~FStartScreen() = default;
|
||||
virtual ~FStartScreen();
|
||||
void Render(bool force = false);
|
||||
bool Progress(int);
|
||||
void NetProgress(int count);
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ bool M_SetSpecialMenu(FName& menu, int param); // game specific checks
|
|||
|
||||
const FIWADInfo *D_FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad);
|
||||
void InitWidgetResources(const char* basewad);
|
||||
void CloseWidgetResources();
|
||||
|
||||
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
||||
|
||||
|
|
@ -3938,6 +3939,7 @@ int GameMain()
|
|||
M_SaveDefaultsFinal();
|
||||
DeleteStartupScreen();
|
||||
C_UninitCVars(); // must come last so that nothing will access the CVARs anymore after deletion.
|
||||
CloseWidgetResources();
|
||||
delete Args;
|
||||
Args = nullptr;
|
||||
return ret;
|
||||
|
|
@ -4030,7 +4032,7 @@ void D_Cleanup()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
UNSAFE_CCMD(restart)
|
||||
UNSAFE_CCMD(debug_restart)
|
||||
{
|
||||
// remove command line args that would get in the way during restart
|
||||
Args->RemoveArgs("-iwad");
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ enum SPAC
|
|||
SPAC_UseBack = 1<<10, // Can be used from the backside
|
||||
SPAC_Damage = 1<<11, // [ZZ] when linedef receives damage
|
||||
SPAC_Death = 1<<12, // [ZZ] when linedef receives damage and has 0 health
|
||||
SPAC_Walking = 1<<13, // Can only be used when standing on a floor (not falling or floating) - only for line cross, not use
|
||||
|
||||
SPAC_PlayerActivate = (SPAC_Cross|SPAC_Use|SPAC_Impact|SPAC_Push|SPAC_AnyCross|SPAC_UseThrough|SPAC_UseBack),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ FGameConfigFile::FGameConfigFile ()
|
|||
SetValueForKey ("Path", "/usr/local/share/games/doom", true);
|
||||
SetValueForKey ("Path", "/usr/share/doom", true);
|
||||
SetValueForKey ("Path", "/usr/share/games/doom", true);
|
||||
SetValueForKey ("Path", SHARE_DIR "/doom", true);
|
||||
SetValueForKey ("Path", SHARE_DIR "/games/doom", true);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -143,6 +146,8 @@ FGameConfigFile::FGameConfigFile ()
|
|||
SetValueForKey ("Path", "$HOME/" GAME_DIR, true);
|
||||
SetValueForKey ("Path", "$HOME/.local/share/games/doom", true);
|
||||
SetValueForKey ("Path", SHARE_DIR, true);
|
||||
SetValueForKey ("Path", SHARE_DIR "/doom", true);
|
||||
SetValueForKey ("Path", SHARE_DIR "/games/doom", true);
|
||||
SetValueForKey ("Path", "/usr/local/share/doom", true);
|
||||
SetValueForKey ("Path", "/usr/local/share/games/doom", true);
|
||||
SetValueForKey ("Path", "/usr/share/doom", true);
|
||||
|
|
@ -180,6 +185,11 @@ FGameConfigFile::FGameConfigFile ()
|
|||
SetValueForKey("Path", "/usr/share/doom/fm_banks", true);
|
||||
SetValueForKey("Path", "/usr/share/games/doom/soundfonts", true);
|
||||
SetValueForKey("Path", "/usr/share/games/doom/fm_banks", true);
|
||||
SetValueForKey("Path", SHARE_DIR "/doom/soundfonts", true);
|
||||
SetValueForKey("Path", SHARE_DIR "/doom/fm_banks", true);
|
||||
SetValueForKey("Path", SHARE_DIR "/games/doom/soundfonts", true);
|
||||
SetValueForKey("Path", SHARE_DIR "/games/doom/fm_banks", true);
|
||||
SetValueForKey("Path", "/usr/share/soundfonts", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1153,7 +1153,7 @@ static const struct DehFlags2 deh_mobjflags_mbf21[] = {
|
|||
{"NORADIUSDMG", [](AActor* defaults) { defaults->flags3 |= MF3_NORADIUSDMG; }}, // doesn't take splash damage
|
||||
{"FORCERADIUSDMG", [](AActor* defaults) { defaults->flags4 |= MF4_FORCERADIUSDMG; }}, // causes splash damage even if target immune
|
||||
{"HIGHERMPROB", [](AActor* defaults) { defaults->MinMissileChance = 160; }}, // higher missile attack probability
|
||||
{"RANGEHALF", [](AActor* defaults) { defaults->flags4 |= MF4_MISSILEMORE; }}, // use half distance for missile attack probability
|
||||
{"RANGEHALF", [](AActor* defaults) { defaults->missilechancemult = 0.5; }}, // use half distance for missile attack probability
|
||||
{"NOTHRESHOLD", [](AActor* defaults) { defaults->flags4 |= MF4_QUICKTORETALIATE; }}, // no targeting threshold
|
||||
{"LONGMELEE", [](AActor* defaults) { defaults->meleethreshold = 196; }}, // long melee range
|
||||
{"BOSS", [](AActor* defaults) { defaults->flags2 |= MF2_BOSS; defaults->flags3 |= MF3_NORADIUSDMG; }}, // full volume see / death sound + splash immunity
|
||||
|
|
@ -1174,9 +1174,10 @@ static void ClearBits2Stuff(AActor* defaults)
|
|||
defaults->maxtargetrange = 0;
|
||||
defaults->MinMissileChance = 200;
|
||||
defaults->meleethreshold = 0;
|
||||
defaults->missilechancemult = 1;
|
||||
defaults->flags2 &= ~(MF2_BOSS | MF2_RIP);
|
||||
defaults->flags3 &= ~(MF3_NOTARGET | MF3_NORADIUSDMG | MF3_FULLVOLDEATH);
|
||||
defaults->flags4 &= ~(MF4_MISSILEMORE | MF4_QUICKTORETALIATE | MF4_FORCERADIUSDMG);
|
||||
defaults->flags4 &= ~(MF4_QUICKTORETALIATE | MF4_FORCERADIUSDMG);
|
||||
defaults->flags8 &= ~(MF8_E1M8BOSS | MF8_E2M8BOSS | MF8_E3M8BOSS | MF8_E4M8BOSS | MF8_E4M6BOSS | MF8_MAP07BOSS1 | MF8_MAP07BOSS2 | MF8_FULLVOLSEE);
|
||||
}
|
||||
|
||||
|
|
@ -1437,6 +1438,27 @@ static int PatchThing (int thingy, int flags)
|
|||
}
|
||||
DPrintf(DMSG_SPAMMY, "MBF21 Bits: %d (0x%08x)\n", info->flags.GetValue(), info->flags.GetValue());
|
||||
}
|
||||
// New fields from Crispy Doom
|
||||
else if (!stricmp(Line1, "Melee threshold"))
|
||||
{
|
||||
info->meleethreshold = DEHToDouble(val);
|
||||
}
|
||||
else if (!stricmp(Line1, "Max target range"))
|
||||
{
|
||||
// [crispy] Maximum distance range to start shooting (zero for unlimited)
|
||||
info->maxtargetrange = DEHToDouble(val);
|
||||
}
|
||||
else if (!stricmp(Line1, "Min missile chance"))
|
||||
{
|
||||
// [crispy] Minimum chance for firing a missile
|
||||
info->MinMissileChance = DEHToDouble(val);
|
||||
}
|
||||
else if (!stricmp(Line1, "Missile chance multiplier"))
|
||||
{
|
||||
// [crispy] Multiplies the chance of firing a missile (65536 = normal chance)
|
||||
info->missilechancemult = DEHToDouble(val);
|
||||
}
|
||||
|
||||
else if (linelen > 6)
|
||||
{
|
||||
if (stricmp (Line1 + linelen - 6, " frame") == 0)
|
||||
|
|
@ -3861,7 +3883,7 @@ struct FlagHandler
|
|||
#define F4(flag) { [](AActor* a) { a->flags4 |= flag; }, [](AActor* a) { a->flags4 &= ~flag; }, [](AActor* a)->bool { return a->flags4 & flag; } }
|
||||
#define F6(flag) { [](AActor* a) { a->flags6 |= flag; }, [](AActor* a) { a->flags6 &= ~flag; }, [](AActor* a)->bool { return a->flags6 & flag; } }
|
||||
#define F8(flag) { [](AActor* a) { a->flags8 |= flag; }, [](AActor* a) { a->flags8 &= ~flag; }, [](AActor* a)->bool { return a->flags8 & flag; } }
|
||||
#define DEPF(flag) { [](AActor* a) { HandleDeprecatedFlags(a, nullptr, true, flag); }, [](AActor* a) { HandleDeprecatedFlags(a, nullptr, false, flag); }, [](AActor* a)->bool { return CheckDeprecatedFlags(a, nullptr, flag); } }
|
||||
#define DEPF(flag) { [](AActor* a) { HandleDeprecatedFlags(a, true, flag); }, [](AActor* a) { HandleDeprecatedFlags(a, false, flag); }, [](AActor* a)->bool { return !!CheckDeprecatedFlags(a, flag); } }
|
||||
|
||||
void SetNoSector(AActor* a)
|
||||
{
|
||||
|
|
@ -3930,7 +3952,7 @@ void ClearCountitem(AActor* a)
|
|||
{
|
||||
if (a->flags & MF_COUNTITEM)
|
||||
{
|
||||
a->flags |= MF_COUNTITEM;
|
||||
a->flags &= ~MF_COUNTITEM;
|
||||
a->Level->total_items--;
|
||||
}
|
||||
}
|
||||
|
|
@ -3939,6 +3961,7 @@ void SetFriendly(AActor* a)
|
|||
{
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--;
|
||||
a->flags |= MF_FRIENDLY;
|
||||
a->flags3 |= MF3_NOBLOCKMONST;
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++;
|
||||
}
|
||||
|
||||
|
|
@ -3946,6 +3969,7 @@ void ClearFriendly(AActor* a)
|
|||
{
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters--;
|
||||
a->flags &= ~MF_FRIENDLY;
|
||||
a->flags3 &= ~MF3_NOBLOCKMONST;
|
||||
if (a->CountsAsKill() && a->health > 0) a->Level->total_monsters++;
|
||||
}
|
||||
|
||||
|
|
@ -4101,7 +4125,7 @@ static FlagHandler flag1handlers[32] = {
|
|||
{ SetTranslation2, ClearTranslation2, CheckTranslation2 },
|
||||
F6(MF6_TOUCHY),
|
||||
{ SetBounces, ClearBounces, [](AActor* a)->bool { return a->BounceFlags & BOUNCE_DEH; } },
|
||||
F(MF_FRIENDLY),
|
||||
{ SetFriendly, ClearFriendly, [](AActor* a)->bool { return a->flags & MF_FRIENDLY; } },
|
||||
{ SetTranslucent, ClearTranslucent, CheckTranslucent },
|
||||
};
|
||||
|
||||
|
|
@ -4112,7 +4136,7 @@ static FlagHandler flag2handlers[32] = {
|
|||
F3(MF3_NORADIUSDMG),
|
||||
F4(MF4_FORCERADIUSDMG),
|
||||
DEPF(DEPF_HIGHERMPROB),
|
||||
F4(MF4_MISSILEMORE),
|
||||
DEPF(DEPF_MISSILEMORE),
|
||||
F4(MF4_QUICKTORETALIATE),
|
||||
DEPF(DEPF_LONGMELEERANGE),
|
||||
{ SetBoss, ClearBoss, [](AActor* a)->bool { return a->flags2 & MF2_BOSS; } },
|
||||
|
|
|
|||
|
|
@ -164,6 +164,20 @@ bool CheckWarpTransMap (FString &mapname, bool substitute)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool SecretLevelVisited()
|
||||
{
|
||||
for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
|
||||
if ((wadlevelinfos[i].flags3 & LEVEL3_SECRET) && (wadlevelinfos[i].flags & LEVEL_VISITED))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static int FindWadClusterInfo (int cluster)
|
||||
{
|
||||
for (unsigned int i = 0; i < wadclusterinfos.Size(); i++)
|
||||
|
|
@ -255,6 +269,7 @@ void level_info_t::Reset()
|
|||
Music = "";
|
||||
LevelName = "";
|
||||
AuthorName = "";
|
||||
MapLabel = "";
|
||||
FadeTable = "COLORMAP";
|
||||
CustomColorMap = "COLORMAP";
|
||||
WallHorizLight = -8;
|
||||
|
|
@ -281,6 +296,8 @@ void level_info_t::Reset()
|
|||
RedirectCVARMapName = "";
|
||||
EnterPic = "";
|
||||
ExitPic = "";
|
||||
EnterAnim = "";
|
||||
ExitAnim = "";
|
||||
Intermission = NAME_None;
|
||||
deathsequence = NAME_None;
|
||||
slideshow = NAME_None;
|
||||
|
|
@ -1013,6 +1030,13 @@ DEFINE_MAP_OPTION(author, true)
|
|||
info->AuthorName = parse.sc.String;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(label, true)
|
||||
{
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetString();
|
||||
info->MapLabel = parse.sc.String;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(secretnext, true)
|
||||
{
|
||||
parse.ParseAssign();
|
||||
|
|
@ -1257,6 +1281,20 @@ DEFINE_MAP_OPTION(enterpic, true)
|
|||
info->EnterPic = parse.sc.String;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(exitanim, true)
|
||||
{
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetString();
|
||||
info->ExitAnim = parse.sc.String;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(enteranim, true)
|
||||
{
|
||||
parse.ParseAssign();
|
||||
parse.sc.MustGetString();
|
||||
info->EnterAnim = parse.sc.String;
|
||||
}
|
||||
|
||||
DEFINE_MAP_OPTION(specialaction, true)
|
||||
{
|
||||
parse.ParseAssign();
|
||||
|
|
@ -2401,9 +2439,13 @@ static void SetLevelNum (level_info_t *info, int num)
|
|||
for (unsigned int i = 0; i < wadlevelinfos.Size(); ++i)
|
||||
{
|
||||
if (wadlevelinfos[i].levelnum == num)
|
||||
{
|
||||
wadlevelinfos[i].levelnum = 0;
|
||||
wadlevelinfos[i].broken_id24_levelnum = 0;
|
||||
}
|
||||
}
|
||||
info->levelnum = num;
|
||||
info->broken_id24_levelnum = num; // at least make it work - somehow.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -2631,6 +2673,7 @@ void G_ParseMapInfo (FString basemapinfo)
|
|||
{
|
||||
int lump, lastlump = 0;
|
||||
level_info_t gamedefaults;
|
||||
TArray<FString> secretMaps;
|
||||
|
||||
int flags1 = 0, flags2 = 0;
|
||||
if (gameinfo.gametype == GAME_Doom)
|
||||
|
|
@ -2747,5 +2790,23 @@ void G_ParseMapInfo (FString basemapinfo)
|
|||
{
|
||||
I_FatalError ("You cannot use clearskills in a MAPINFO if you do not define any new skills after it.");
|
||||
}
|
||||
|
||||
// Find any and all secret maps.
|
||||
for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
|
||||
{
|
||||
if (wadlevelinfos[i].NextSecretMap.IsNotEmpty() && wadlevelinfos[i].NextSecretMap != wadlevelinfos[i].NextMap)
|
||||
{
|
||||
secretMaps.Push(wadlevelinfos[i].NextSecretMap);
|
||||
}
|
||||
}
|
||||
// ...and then mark them all as secret maps.
|
||||
for (unsigned int i = 0; i < secretMaps.Size(); i++)
|
||||
{
|
||||
auto* li = FindLevelInfo(secretMaps[i].GetChars(), false);
|
||||
if (li)
|
||||
{
|
||||
li->flags3 |= LEVEL3_SECRET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ enum ELevelFlags : unsigned int
|
|||
LEVEL3_NOJUMPDOWN = 0x00040000, // only for MBF21. Inverse of MBF's dog_jumping flag.
|
||||
LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame
|
||||
LEVEL3_NOFOGOFWAR = 0x00100000, // disables effect of r_radarclipper CVAR on this map
|
||||
LEVEL3_SECRET = 0x00200000, // level is a secret level
|
||||
|
||||
// VKDoom custom flags
|
||||
VKDLEVELFLAG_NOUSERSAVE = 0x00000001,
|
||||
|
|
@ -328,6 +329,7 @@ struct FExitText
|
|||
struct level_info_t
|
||||
{
|
||||
int levelnum;
|
||||
int broken_id24_levelnum;
|
||||
|
||||
FString MapName;
|
||||
FString NextMap;
|
||||
|
|
@ -355,6 +357,7 @@ struct level_info_t
|
|||
FString LightningSound = "world/thunder";
|
||||
FString Music;
|
||||
FString LevelName;
|
||||
FString MapLabel;
|
||||
FString AuthorName;
|
||||
int8_t WallVertLight, WallHorizLight;
|
||||
int musicorder;
|
||||
|
|
@ -396,6 +399,8 @@ struct level_info_t
|
|||
|
||||
FString EnterPic;
|
||||
FString ExitPic;
|
||||
FString EnterAnim;
|
||||
FString ExitAnim;
|
||||
FString InterMusic;
|
||||
int intermusicorder;
|
||||
TMap <FName, std::pair<FString, int> > MapInterMusic;
|
||||
|
|
@ -495,6 +500,8 @@ level_info_t *FindLevelInfo (const char *mapname, bool allowdefault=true);
|
|||
level_info_t *FindLevelByNum (int num);
|
||||
level_info_t *CheckLevelRedirect (level_info_t *info);
|
||||
|
||||
bool SecretLevelVisited();
|
||||
|
||||
FString CalcMapName (int episode, int level);
|
||||
|
||||
void G_ClearMapinfo();
|
||||
|
|
|
|||
|
|
@ -504,6 +504,8 @@ enum
|
|||
SECMF_OVERLAPPING = 512, // floor and ceiling overlap and require special renderer action.
|
||||
SECMF_NOSKYWALLS = 1024, // Do not draw "sky walls"
|
||||
SECMF_LIFT = 2048, // For MBF monster AI
|
||||
SECMF_HURTMONSTERS = 4096, // Monsters in this sector are hurt like players.
|
||||
SECMF_HARMINAIR = 8192, // Actors in this sector are also hurt mid-air.
|
||||
};
|
||||
|
||||
enum
|
||||
|
|
|
|||
|
|
@ -832,8 +832,10 @@ void FTextureAnimator::ParseFireTexture(FScanner& sc)
|
|||
sc.MustGetValue(false);
|
||||
a = sc.Number;
|
||||
palette.Push(PalEntry(a, r, g, b));
|
||||
if (a != 255 && a != 0);
|
||||
if (a != 255 && a != 0)
|
||||
{
|
||||
gametex->SetTranslucent(true);
|
||||
}
|
||||
|
||||
if (palette.Size() > 256)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ struct UMapEntry
|
|||
FString LevelName;
|
||||
FString InterText;
|
||||
FString InterTextSecret;
|
||||
FString author;
|
||||
FString label;
|
||||
TArray<FSpecialAction> BossActions;
|
||||
bool BossCleared = false;
|
||||
|
||||
|
|
@ -52,10 +54,13 @@ struct UMapEntry
|
|||
char endpic[9] = "";
|
||||
char exitpic[9] = "";
|
||||
char enterpic[9] = "";
|
||||
char exitanim[9] = "";
|
||||
char enteranim[9] = "";
|
||||
char interbackdrop[9] = "FLOOR4_8";
|
||||
char intermusic[9] = "";
|
||||
int partime = 0;
|
||||
int nointermission = 0;
|
||||
int id24_levelnum = 0; // note that this one's semantics are massively screwed up. Only to be used for ID24-style intermissions.
|
||||
};
|
||||
|
||||
static TArray<UMapEntry> Maps;
|
||||
|
|
@ -122,7 +127,7 @@ static int ParseLumpName(FScanner &scanner, char *buffer)
|
|||
//
|
||||
// -----------------------------------------------
|
||||
|
||||
static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape)
|
||||
static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape, int *id24_levelnum)
|
||||
{
|
||||
// find the next line with content.
|
||||
// this line is no property.
|
||||
|
|
@ -136,6 +141,16 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape)
|
|||
scanner.MustGetToken(TK_StringConst);
|
||||
mape->LevelName = scanner.String;
|
||||
}
|
||||
else if (!pname.CompareNoCase("author"))
|
||||
{
|
||||
scanner.MustGetToken(TK_StringConst);
|
||||
mape->author = scanner.String;
|
||||
}
|
||||
else if (!pname.CompareNoCase("label"))
|
||||
{
|
||||
scanner.MustGetToken(TK_StringConst);
|
||||
mape->label = scanner.String;
|
||||
}
|
||||
else if (!pname.CompareNoCase("next"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->nextmap);
|
||||
|
|
@ -186,6 +201,14 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape)
|
|||
{
|
||||
ParseLumpName(scanner, mape->enterpic);
|
||||
}
|
||||
else if (!pname.CompareNoCase("exitanim"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->exitanim);
|
||||
}
|
||||
else if (!pname.CompareNoCase("enteranim"))
|
||||
{
|
||||
ParseLumpName(scanner, mape->enteranim);
|
||||
}
|
||||
else if (!pname.CompareNoCase("nointermission"))
|
||||
{
|
||||
scanner.MustGetBoolToken();
|
||||
|
|
@ -244,6 +267,7 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape)
|
|||
epi.mEpisodeMap = mape->MapName;
|
||||
epi.mPicName = split[0];
|
||||
epi.mNoSkill = false;
|
||||
mape->id24_levelnum = *id24_levelnum = 1;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < AllEpisodes.Size(); i++)
|
||||
|
|
@ -314,15 +338,16 @@ static int ParseStandardProperty(FScanner &scanner, UMapEntry *mape)
|
|||
//
|
||||
// -----------------------------------------------
|
||||
|
||||
static int ParseMapEntry(FScanner &scanner, UMapEntry *val)
|
||||
static int ParseMapEntry(FScanner &scanner, UMapEntry *val, int *id24_levelnum)
|
||||
{
|
||||
scanner.MustGetToken(TK_Identifier);
|
||||
|
||||
val->MapName = scanner.String;
|
||||
val->id24_levelnum = ++(*id24_levelnum);
|
||||
scanner.MustGetToken('{');
|
||||
while(!scanner.CheckToken('}'))
|
||||
{
|
||||
ParseStandardProperty(scanner, val);
|
||||
ParseStandardProperty(scanner, val, id24_levelnum);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -338,12 +363,13 @@ int ParseUMapInfo(int lumpnum)
|
|||
FScanner scanner(lumpnum);
|
||||
unsigned int i;
|
||||
|
||||
int id24_levelnum = 1;
|
||||
while (scanner.GetToken())
|
||||
{
|
||||
scanner.TokenMustBe(TK_Map);
|
||||
|
||||
UMapEntry parsed;
|
||||
ParseMapEntry(scanner, &parsed);
|
||||
ParseMapEntry(scanner, &parsed, &id24_levelnum);
|
||||
|
||||
// Endpic overrides level exits.
|
||||
if (parsed.endpic[0])
|
||||
|
|
@ -403,6 +429,14 @@ void CommitUMapinfo(level_info_t *defaultinfo)
|
|||
levelinfo->LevelName = map.LevelName;
|
||||
levelinfo->PName = ""; // clear the map name patch to force the string version to be shown - unless explicitly overridden right next.
|
||||
}
|
||||
if (map.author.IsNotEmpty())
|
||||
{
|
||||
levelinfo->AuthorName = map.author;
|
||||
}
|
||||
if (map.label.IsNotEmpty())
|
||||
{
|
||||
levelinfo->MapLabel = map.label;
|
||||
}
|
||||
if (map.levelpic[0]) levelinfo->PName = map.levelpic;
|
||||
if (map.nextmap[0]) levelinfo->NextMap = map.nextmap;
|
||||
else if (map.endpic[0])
|
||||
|
|
@ -443,6 +477,9 @@ void CommitUMapinfo(level_info_t *defaultinfo)
|
|||
if (map.partime > 0) levelinfo->partime = map.partime;
|
||||
if (map.enterpic[0]) levelinfo->EnterPic = map.enterpic;
|
||||
if (map.exitpic[0]) levelinfo->ExitPic = map.exitpic;
|
||||
if (map.enteranim[0]) levelinfo->EnterAnim = map.enteranim;
|
||||
if (map.exitanim[0]) levelinfo->ExitAnim = map.exitanim;
|
||||
levelinfo->broken_id24_levelnum = map.id24_levelnum;
|
||||
/* UMAPINFO's intermusic is for the text screen, not the summary.
|
||||
if (map.intermusic[0])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1034,6 +1034,10 @@ public:
|
|||
// This switch contains all keys of the UDMF base spec which only apply to Hexen format specials
|
||||
if (!isTranslated) switch (key.GetIndex())
|
||||
{
|
||||
case NAME_Walking:
|
||||
Flag(ld->activation, SPAC_Walking, key);
|
||||
continue;
|
||||
|
||||
case NAME_Playercross:
|
||||
Flag(ld->activation, SPAC_Cross, key);
|
||||
continue;
|
||||
|
|
@ -2030,6 +2034,14 @@ public:
|
|||
Flag(sec->Flags, SECF_HAZARD, key);
|
||||
break;
|
||||
|
||||
case NAME_hurtmonsters:
|
||||
Flag(sec->MoreFlags, SECMF_HURTMONSTERS, key);
|
||||
break;
|
||||
|
||||
case NAME_harminair:
|
||||
Flag(sec->MoreFlags, SECMF_HARMINAIR, key);
|
||||
break;
|
||||
|
||||
case NAME_floorterrain:
|
||||
sec->terrainnum[sector_t::floor] = P_FindTerrain(CheckString(key));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -625,6 +625,7 @@ xx(ScaleY)
|
|||
xx(FriendlySeeBlocks)
|
||||
xx(Floatbobphase)
|
||||
xx(Floatbobstrength)
|
||||
xx(FloatBobFactor)
|
||||
xx(Target)
|
||||
xx(Master)
|
||||
xx(Tracer)
|
||||
|
|
@ -670,6 +671,7 @@ xx(Missilecross)
|
|||
xx(Anycross)
|
||||
xx(Monsteruse)
|
||||
xx(Monsterpush)
|
||||
xx(Walking)
|
||||
|
||||
xx(ZDoom)
|
||||
xx(ZDoomTranslated)
|
||||
|
|
@ -808,6 +810,8 @@ xx(damageinterval)
|
|||
xx(leakiness)
|
||||
xx(damageterraineffect)
|
||||
xx(damagehazard)
|
||||
xx(hurtmonsters)
|
||||
xx(harminair)
|
||||
xx(floorterrain)
|
||||
xx(ceilingterrain)
|
||||
xx(floor_reflect)
|
||||
|
|
|
|||
|
|
@ -262,8 +262,8 @@ enum ActorFlag4
|
|||
MF4_STRIFEDAMAGE = 0x00000100, // Strife projectiles only do up to 4x damage, not 8x
|
||||
|
||||
MF4_CANUSEWALLS = 0x00000200, // Can activate 'use' specials
|
||||
MF4_MISSILEMORE = 0x00000400, // increases the chance of a missile attack
|
||||
MF4_MISSILEEVENMORE = 0x00000800, // significantly increases the chance of a missile attack
|
||||
// = 0x00000400,
|
||||
// = 0x00000800,
|
||||
MF4_FORCERADIUSDMG = 0x00001000, // if put on an object it will override MF3_NORADIUSDMG
|
||||
MF4_DONTFALL = 0x00002000, // Doesn't have NOGRAVITY disabled when dying.
|
||||
MF4_SEESDAGGERS = 0x00004000, // This actor can see you striking with a dagger
|
||||
|
|
@ -442,7 +442,9 @@ enum ActorFlag9
|
|||
MF9_DOSHADOWBLOCK = 0x00000002, // [inkoalawetrust] Should the monster look for SHADOWBLOCK actors ?
|
||||
MF9_SHADOWBLOCK = 0x00000004, // [inkoalawetrust] Actors in the line of fire with this flag trigger the MF_SHADOW aiming penalty.
|
||||
MF9_SHADOWAIMVERT = 0x00000008, // [inkoalawetrust] Monster aim is also offset vertically when aiming at shadow actors.
|
||||
MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states
|
||||
MF9_DECOUPLEDANIMATIONS = 0x00000010, // [RL0] Decouple model animations from states
|
||||
MF9_NOSECTORDAMAGE = 0x00000020, // [inkoalawetrust] Actor ignores any sector-based damage (i.e damaging floors, NOT crushers)
|
||||
MF9_ISPUFF = 0x00000040, // [AA] Set on actors by P_SpawnPuff
|
||||
};
|
||||
|
||||
// --- mobj.renderflags ---
|
||||
|
|
@ -1231,6 +1233,7 @@ public:
|
|||
TObjPtr<AActor*> alternative; // (Un)Morphed actors stored here. Those with the MF_UNMORPHED flag are the originals.
|
||||
TObjPtr<AActor*> tracer; // Thing being chased/attacked for tracers
|
||||
TObjPtr<AActor*> master; // Thing which spawned this one (prevents mutual attacks)
|
||||
TObjPtr<AActor*> damagesource; // [AA] Thing that fired a hitscan using this actor as a puff
|
||||
|
||||
int tid; // thing identifier
|
||||
int special; // special
|
||||
|
|
@ -1252,6 +1255,7 @@ public:
|
|||
// but instead tries to come closer for a melee attack.
|
||||
// This is not the same as meleerange
|
||||
double maxtargetrange; // any target farther away cannot be attacked
|
||||
double missilechancemult; // distance multiplier for CheckMeleeRange, formerly done with MISSILE(EVEN)MORE flags.
|
||||
double bouncefactor; // Strife's grenades use 50%, Hexen's Flechettes 70.
|
||||
double wallbouncefactor; // The bounce factor for walls can be different.
|
||||
double Gravity; // [GRB] Gravity factor
|
||||
|
|
@ -1304,6 +1308,7 @@ public:
|
|||
uint8_t FloatBobPhase;
|
||||
uint8_t FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc)
|
||||
double FloatBobStrength;
|
||||
double FloatBobFactor;
|
||||
PalEntry BloodColor;
|
||||
FTranslationID BloodTranslation;
|
||||
|
||||
|
|
@ -1524,9 +1529,13 @@ public:
|
|||
{
|
||||
return Z() + Height;
|
||||
}
|
||||
double CenterOffset() const
|
||||
{
|
||||
return Height / 2;
|
||||
}
|
||||
double Center() const
|
||||
{
|
||||
return Z() + Height/2;
|
||||
return Z() + CenterOffset();
|
||||
}
|
||||
void SetZ(double newz, bool moving = true)
|
||||
{
|
||||
|
|
@ -1603,6 +1612,11 @@ public:
|
|||
Vel.Y += speed * angle.Sin();
|
||||
}
|
||||
|
||||
void Thrust(const DVector3& vel)
|
||||
{
|
||||
Vel += vel;
|
||||
}
|
||||
|
||||
void Vel3DFromAngle(DAngle angle, DAngle pitch, double speed)
|
||||
{
|
||||
double cospitch = pitch.Cos();
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ inline double AActor::GetBobOffset(double ticfrac) const
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
return BobSin(FloatBobPhase + Level->maptime + ticfrac) * FloatBobStrength;
|
||||
return BobSin(FloatBobPhase + Level->maptime * FloatBobFactor + ticfrac) * FloatBobStrength;
|
||||
}
|
||||
|
||||
inline double AActor::GetCameraHeight() const
|
||||
|
|
|
|||
|
|
@ -198,15 +198,15 @@ void P_Add3DFloor(sector_t* sec, sector_t* sec2, line_t* master, int flags, int
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// P_PlayerOnSpecial3DFloor
|
||||
// Checks to see if a player is standing on or is inside a 3D floor (water)
|
||||
// P_ActorOnSpecial3DFloor
|
||||
// Checks to see if an actor is standing on or is inside a 3D floor (water)
|
||||
// and applies any specials..
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_PlayerOnSpecial3DFloor(player_t* player)
|
||||
void P_ActorOnSpecial3DFloor(AActor* victim)
|
||||
{
|
||||
for(auto rover : player->mo->Sector->e->XFloor.ffloors)
|
||||
for(auto rover : victim->Sector->e->XFloor.ffloors)
|
||||
{
|
||||
if (!(rover->flags & FF_EXISTS)) continue;
|
||||
if (rover->flags & FF_FIX) continue;
|
||||
|
|
@ -215,22 +215,22 @@ void P_PlayerOnSpecial3DFloor(player_t* player)
|
|||
if(rover->flags & FF_SOLID)
|
||||
{
|
||||
// Player must be on top of the floor to be affected...
|
||||
if(player->mo->Z() != rover->top.plane->ZatPoint(player->mo)) continue;
|
||||
if(victim->Z() != rover->top.plane->ZatPoint(victim)) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Water and DEATH FOG!!! heh
|
||||
if ((rover->flags & FF_NODAMAGE) ||
|
||||
player->mo->Z() > rover->top.plane->ZatPoint(player->mo) ||
|
||||
player->mo->Top() < rover->bottom.plane->ZatPoint(player->mo))
|
||||
victim->Z() > rover->top.plane->ZatPoint(victim) ||
|
||||
victim->Top() < rover->bottom.plane->ZatPoint(victim))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Apply sector specials
|
||||
P_PlayerInSpecialSector(player, rover->model);
|
||||
P_ActorInSpecialSector(victim, rover->model);
|
||||
|
||||
// Apply flat specials (using the ceiling!)
|
||||
P_PlayerOnSpecialFlat(player, rover->model->GetTerrain(rover->top.isceiling));
|
||||
P_ActorOnSpecialFlat(victim, rover->model->GetTerrain(rover->top.isceiling));
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,8 +113,7 @@ struct lightlist_t
|
|||
|
||||
|
||||
|
||||
class player_t;
|
||||
void P_PlayerOnSpecial3DFloor(player_t* player);
|
||||
void P_ActorOnSpecial3DFloor(AActor* victim);
|
||||
|
||||
bool P_CheckFor3DFloorHit(AActor * mo, double z, bool trigger);
|
||||
bool P_CheckFor3DCeilingHit(AActor * mo, double z, bool trigger);
|
||||
|
|
|
|||
|
|
@ -373,8 +373,7 @@ static int P_CheckMissileRange (AActor *actor)
|
|||
if (actor->MeleeState != nullptr && dist < actor->meleethreshold)
|
||||
return false; // From the Revenant: close enough for fist attack
|
||||
|
||||
if (actor->flags4 & MF4_MISSILEMORE) dist *= 0.5;
|
||||
if (actor->flags4 & MF4_MISSILEEVENMORE) dist *= 0.125;
|
||||
dist *= actor->missilechancemult;
|
||||
|
||||
int mmc = int(actor->MinMissileChance * G_SkillProperty(SKILLP_Aggressiveness));
|
||||
return pr_checkmissilerange() >= min(int(dist), mmc);
|
||||
|
|
@ -465,6 +464,12 @@ static int P_IsUnderDamage(AActor* actor)
|
|||
dir |= cl->getDirection();
|
||||
}
|
||||
// Q: consider crushing 3D floors too?
|
||||
// [inkoalawetrust] Check for sectors that can harm the actor.
|
||||
if (!(actor->flags9 & MF9_NOSECTORDAMAGE) && seclist->m_sector->damageamount > 0)
|
||||
{
|
||||
if (seclist->m_sector->MoreFlags & SECMF_HARMINAIR || actor->isAtZ(seclist->m_sector->LowestFloorAt(actor)) || actor->waterlevel)
|
||||
return (actor->player || (actor->player == nullptr && seclist->m_sector->MoreFlags & SECMF_HURTMONSTERS)) ? -1 : 0;
|
||||
}
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
|
@ -1835,14 +1840,6 @@ int P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
|
|||
if (!P_IsVisible (actor, player->mo, allaround, params))
|
||||
continue; // out of sight
|
||||
|
||||
// [SP] Deathmatch fixes - if we have MF_FRIENDLY we're definitely in deathmatch
|
||||
// We're going to ignore our master, but go after his enemies.
|
||||
if ( actor->flags & MF_FRIENDLY )
|
||||
{
|
||||
if ( actor->IsFriend(player->mo) )
|
||||
continue;
|
||||
}
|
||||
|
||||
// [RC] Well, let's let special monsters with this flag active be able to see
|
||||
// the player then, eh?
|
||||
if(!(actor->flags6 & MF6_SEEINVISIBLE))
|
||||
|
|
|
|||
|
|
@ -408,7 +408,8 @@ enum
|
|||
RADF_OLDRADIUSDAMAGE = 32,
|
||||
RADF_THRUSTLESS = 64,
|
||||
RADF_NOALLIES = 128,
|
||||
RADF_CIRCULAR = 256
|
||||
RADF_CIRCULAR = 256,
|
||||
RADF_CIRCULARTHRUST = 512,
|
||||
};
|
||||
int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, double distance, double fulldmgdistance, bool oldradiusdmg, bool circular);
|
||||
int P_RadiusAttack (AActor *spot, AActor *source, int damage, double distance,
|
||||
|
|
|
|||
|
|
@ -6236,24 +6236,44 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, double
|
|||
if (!(thing->flags7 & MF7_DONTTHRUST))
|
||||
{
|
||||
thrust = points * 0.5 / (double)thing->Mass;
|
||||
|
||||
if (bombsource == thing)
|
||||
{
|
||||
thrust *= selfthrustscale;
|
||||
}
|
||||
vz = (thing->Center() - bombspot->Z()) * thrust;
|
||||
if (bombsource != thing)
|
||||
|
||||
if (flags & RADF_CIRCULARTHRUST)
|
||||
{
|
||||
vz *= 0.5;
|
||||
auto dir = bombspot->Vec3To(thing);
|
||||
dir.Z += thing->CenterOffset() - bombspot->CenterOffset();
|
||||
|
||||
if (!dir.isZero())
|
||||
{
|
||||
dir.MakeUnit();
|
||||
thing->Thrust(dir * thrust);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vz *= 0.8;
|
||||
}
|
||||
thing->Thrust(bombspot->AngleTo(thing), thrust);
|
||||
if (!(flags & RADF_NODAMAGE) || (flags & RADF_THRUSTZ))
|
||||
{
|
||||
if (!(thing->Level->i_compatflags2 & COMPATF2_EXPLODE1) || (flags & RADF_THRUSTZ))
|
||||
thing->Vel.Z += vz; // this really doesn't work well
|
||||
thing->Thrust(bombspot->AngleTo(thing), thrust);
|
||||
|
||||
if (!(flags & RADF_NODAMAGE) || (flags & RADF_THRUSTZ))
|
||||
{
|
||||
if (!(thing->Level->i_compatflags2 & COMPATF2_EXPLODE1) || (flags & RADF_THRUSTZ))
|
||||
{
|
||||
vz = (thing->Center() - bombspot->Z()) * thrust;
|
||||
if (bombsource != thing)
|
||||
{
|
||||
vz *= 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
vz *= 0.8;
|
||||
}
|
||||
|
||||
thing->Vel.Z += vz; // this really doesn't work well
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ IMPLEMENT_POINTERS_START(AActor)
|
|||
IMPLEMENT_POINTER(target)
|
||||
IMPLEMENT_POINTER(lastenemy)
|
||||
IMPLEMENT_POINTER(tracer)
|
||||
IMPLEMENT_POINTER(damagesource)
|
||||
IMPLEMENT_POINTER(goal)
|
||||
IMPLEMENT_POINTER(LastLookActor)
|
||||
IMPLEMENT_POINTER(Inventory)
|
||||
|
|
@ -217,6 +218,7 @@ void AActor::Serialize(FSerializer &arc)
|
|||
A("angles", Angles)
|
||||
A("frame", frame)
|
||||
A("scale", Scale)
|
||||
A("nolocalrender", NoLocalRender) // Note: This will probably be removed later since a better solution is needed
|
||||
A("renderstyle", RenderStyle)
|
||||
A("renderflags", renderflags)
|
||||
A("renderflags2", renderflags2)
|
||||
|
|
@ -289,6 +291,7 @@ void AActor::Serialize(FSerializer &arc)
|
|||
A("inventoryid", InventoryID)
|
||||
A("floatbobphase", FloatBobPhase)
|
||||
A("floatbobstrength", FloatBobStrength)
|
||||
A("floatbobfactor", FloatBobFactor)
|
||||
A("translation", Translation)
|
||||
A("bloodcolor", BloodColor)
|
||||
A("bloodtranslation", BloodTranslation)
|
||||
|
|
@ -317,6 +320,7 @@ void AActor::Serialize(FSerializer &arc)
|
|||
A("wallbouncefactor", wallbouncefactor)
|
||||
A("bouncecount", bouncecount)
|
||||
A("maxtargetrange", maxtargetrange)
|
||||
A("missilechancemult", missilechancemult)
|
||||
A("meleethreshold", meleethreshold)
|
||||
A("meleerange", meleerange)
|
||||
A("damagetype", DamageType)
|
||||
|
|
@ -398,7 +402,8 @@ void AActor::Serialize(FSerializer &arc)
|
|||
("unmorphtime", UnmorphTime)
|
||||
("morphflags", MorphFlags)
|
||||
("premorphproperties", PremorphProperties)
|
||||
("morphexitflash", MorphExitFlash);
|
||||
("morphexitflash", MorphExitFlash)
|
||||
("damagesource", damagesource);
|
||||
|
||||
|
||||
SerializeTerrain(arc, "floorterrain", floorterrain, &def->floorterrain);
|
||||
|
|
@ -798,7 +803,7 @@ DEFINE_ACTION_FUNCTION(AActor, GiveInventoryType)
|
|||
|
||||
void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealth)
|
||||
{
|
||||
Level->total_monsters -= CountsAsKill();
|
||||
if (health > 0) Level->total_monsters -= CountsAsKill();
|
||||
TIDtoHate = other->TIDtoHate;
|
||||
LastLookActor = other->LastLookActor;
|
||||
LastLookPlayerNumber = other->LastLookPlayerNumber;
|
||||
|
|
@ -813,7 +818,7 @@ void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealt
|
|||
LastHeard = target = other->target;
|
||||
}
|
||||
if (resetHealth) health = SpawnHealth();
|
||||
Level->total_monsters += CountsAsKill();
|
||||
if (health > 0) Level->total_monsters += CountsAsKill();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, CopyFriendliness)
|
||||
|
|
@ -4430,6 +4435,14 @@ void AActor::Tick ()
|
|||
// must have been removed
|
||||
if (ObjectFlags & OF_EuthanizeMe) return;
|
||||
}
|
||||
//[inkoalawetrust] Genericized level damage handling that makes sector, 3D floor, and TERRAIN flat damage affect monsters and other NPCs too.
|
||||
if (!(flags9 & MF9_NOSECTORDAMAGE) && (player || (player == nullptr && Sector->MoreFlags & SECMF_HURTMONSTERS)))
|
||||
{
|
||||
P_ActorOnSpecial3DFloor(this);
|
||||
P_ActorInSpecialSector(this,Sector);
|
||||
if (!isAbove(Sector->floorplane.ZatPoint(this)) || waterlevel) // Actor must be touching the floor for TERRAIN flats.
|
||||
P_ActorOnSpecialFlat(this, P_GetThingFloorType(this));
|
||||
}
|
||||
|
||||
if (tics != -1)
|
||||
{
|
||||
|
|
@ -6278,9 +6291,15 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1
|
|||
if ( puff && (puff->flags5 & MF5_PUFFGETSOWNER))
|
||||
puff->target = source;
|
||||
|
||||
// [AA] Track the source of the attack unconditionally in a separate field.
|
||||
puff->damagesource = source;
|
||||
|
||||
// Angle is the opposite of the hit direction (i.e. the puff faces the source.)
|
||||
puff->Angles.Yaw = hitdir + DAngle::fromDeg(180);
|
||||
|
||||
// [AA] Mark the spawned actor as a puff with a flag.
|
||||
puff->flags9 |= MF9_ISPUFF;
|
||||
|
||||
// If a puff has a crash state and an actor was not hit,
|
||||
// it will enter the crash state. This is used by the StrifeSpark
|
||||
// and BlasterPuff.
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@
|
|||
#include "c_console.h"
|
||||
#include "p_spec_thinkers.h"
|
||||
|
||||
static FRandom pr_playerinspecialsector ("PlayerInSpecialSector");
|
||||
static FRandom pr_actorinspecialsector ("ActorInSpecialSector");
|
||||
|
||||
EXTERN_CVAR(Bool, cl_predict_specials)
|
||||
EXTERN_CVAR(Bool, forcewater)
|
||||
|
|
@ -254,6 +254,13 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType,
|
|||
return false;
|
||||
}
|
||||
|
||||
if ((activationType & (SPAC_Cross|SPAC_MCross)) && (lineActivation & SPAC_Walking))
|
||||
{
|
||||
// not on floor
|
||||
if ((mo->Pos().Z > mo->floorz) && !(mo->flags2 & MF2_ONMOBJ))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lineActivation & SPAC_UseThrough)
|
||||
{
|
||||
lineActivation |= SPAC_Use;
|
||||
|
|
@ -412,22 +419,18 @@ bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType)
|
|||
}
|
||||
|
||||
//
|
||||
// P_PlayerInSpecialSector
|
||||
// P_ActorInSpecialSector
|
||||
// Called every tic frame
|
||||
// that the player origin is in a special sector
|
||||
// that the actor origin is in a special sector
|
||||
//
|
||||
void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
|
||||
void P_ActorInSpecialSector (AActor *victim, sector_t * sector)
|
||||
{
|
||||
if (sector == NULL)
|
||||
{
|
||||
// Falling, not all the way down yet?
|
||||
sector = player->mo->Sector;
|
||||
if (!player->mo->isAtZ(sector->LowestFloorAt(player->mo))
|
||||
&& !player->mo->waterlevel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
sector = victim->Sector;
|
||||
|
||||
// Falling, not all the way down yet?
|
||||
if (!(sector->MoreFlags & SECMF_HARMINAIR) && !victim->isAtZ(sector->LowestFloorAt(victim)) && !victim->waterlevel)
|
||||
return;
|
||||
|
||||
// Has hit ground.
|
||||
|
||||
|
|
@ -438,7 +441,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
|
|||
if (sector->damageinterval <= 0)
|
||||
sector->damageinterval = 32; // repair invalid damageinterval values
|
||||
|
||||
if (sector->Flags & (SECF_EXIT1 | SECF_EXIT2))
|
||||
if (victim->player && sector->Flags & (SECF_EXIT1 | SECF_EXIT2))
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
if (playeringame[i])
|
||||
|
|
@ -457,7 +460,7 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
|
|||
// different damage types yet, so that's not happening for now.
|
||||
// [MK] account for subclasses that may have "Full" protection (i.e.: prevent leaky damage)
|
||||
int ironfeet = 0;
|
||||
for (auto i = player->mo->Inventory; i != NULL; i = i->Inventory)
|
||||
for (auto i = victim->Inventory; i != NULL; i = i->Inventory)
|
||||
{
|
||||
if (i->IsKindOf(NAME_PowerIronFeet))
|
||||
{
|
||||
|
|
@ -469,28 +472,28 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
|
|||
}
|
||||
}
|
||||
|
||||
if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE;
|
||||
if ((ironfeet == 0 || (ironfeet < 2 && pr_playerinspecialsector() < sector->leakydamage)))
|
||||
if (victim->player && sector->Flags & SECF_ENDGODMODE) victim->player->cheats &= ~CF_GODMODE;
|
||||
if ((ironfeet == 0 || (ironfeet < 2 && pr_actorinspecialsector() < sector->leakydamage)))
|
||||
{
|
||||
if (sector->Flags & SECF_HAZARD)
|
||||
if (victim->player && sector->Flags & SECF_HAZARD)
|
||||
{
|
||||
player->hazardcount += sector->damageamount;
|
||||
player->hazardtype = sector->damagetype;
|
||||
player->hazardinterval = sector->damageinterval;
|
||||
victim->player->hazardcount += sector->damageamount;
|
||||
victim->player->hazardtype = sector->damagetype;
|
||||
victim->player->hazardinterval = sector->damageinterval;
|
||||
}
|
||||
else if (Level->time % sector->damageinterval == 0)
|
||||
{
|
||||
if (!(player->cheats & (CF_GODMODE | CF_GODMODE2)))
|
||||
if (!(victim->player && victim->player->cheats & (CF_GODMODE | CF_GODMODE2)))
|
||||
{
|
||||
P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype);
|
||||
P_DamageMobj(victim, NULL, NULL, sector->damageamount, sector->damagetype);
|
||||
}
|
||||
if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
|
||||
if (victim->player && (sector->Flags & SECF_ENDLEVEL) && victim->player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
|
||||
{
|
||||
Level->ExitLevel(0, false);
|
||||
}
|
||||
if (sector->Flags & SECF_DMGTERRAINFX)
|
||||
{
|
||||
P_HitWater(player->mo, player->mo->Sector, player->mo->Pos(), false, true, true);
|
||||
P_HitWater(victim, victim->Sector, victim->Pos(), false, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -499,14 +502,14 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
|
|||
{
|
||||
if (Level->time % sector->damageinterval == 0)
|
||||
{
|
||||
P_GiveBody(player->mo, -sector->damageamount, 100);
|
||||
P_GiveBody(victim, -sector->damageamount, 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (sector->isSecret())
|
||||
if (victim->player && sector->isSecret())
|
||||
{
|
||||
sector->ClearSecret();
|
||||
P_GiveSecret(Level, player->mo, true, true, sector->Index());
|
||||
P_GiveSecret(Level, victim, true, true, sector->Index());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -645,13 +648,13 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GiveSecret)
|
|||
|
||||
//============================================================================
|
||||
//
|
||||
// P_PlayerOnSpecialFlat
|
||||
// P_ActorOnSpecialFlat
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void P_PlayerOnSpecialFlat (player_t *player, int floorType)
|
||||
void P_ActorOnSpecialFlat (AActor *victim, int floorType)
|
||||
{
|
||||
auto Level = player->mo->Level;
|
||||
auto Level = victim->Level;
|
||||
|
||||
if (Terrains[floorType].DamageAmount &&
|
||||
!(Level->time % (Terrains[floorType].DamageTimeMask+1)))
|
||||
|
|
@ -661,7 +664,7 @@ void P_PlayerOnSpecialFlat (player_t *player, int floorType)
|
|||
if (Terrains[floorType].AllowProtection)
|
||||
{
|
||||
auto pitype = PClass::FindActor(NAME_PowerIronFeet);
|
||||
for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
|
||||
for (ironfeet = victim->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
|
||||
{
|
||||
if (ironfeet->IsKindOf (pitype))
|
||||
break;
|
||||
|
|
@ -671,20 +674,18 @@ void P_PlayerOnSpecialFlat (player_t *player, int floorType)
|
|||
int damage = 0;
|
||||
if (ironfeet == NULL)
|
||||
{
|
||||
damage = P_DamageMobj (player->mo, NULL, NULL, Terrains[floorType].DamageAmount,
|
||||
damage = P_DamageMobj (victim, NULL, NULL, Terrains[floorType].DamageAmount,
|
||||
Terrains[floorType].DamageMOD);
|
||||
}
|
||||
if (damage > 0 && Terrains[floorType].Splash != -1)
|
||||
{
|
||||
S_Sound (player->mo, CHAN_AUTO, 0,
|
||||
S_Sound (victim, CHAN_AUTO, 0,
|
||||
Splashes[Terrains[floorType].Splash].NormalSplashSound, 1,
|
||||
ATTN_IDLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// P_UpdateSpecials
|
||||
// Animate planes, scroll walls, etc.
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ bool P_ActivateLine (line_t *ld, AActor *mo, int side, int activationType, DVect
|
|||
bool P_TestActivateLine (line_t *ld, AActor *mo, int side, int activationType, DVector3 *optpos = NULL);
|
||||
bool P_PredictLine (line_t *ld, AActor *mo, int side, int activationType);
|
||||
|
||||
void P_PlayerInSpecialSector (player_t *player, sector_t * sector=NULL);
|
||||
void P_PlayerOnSpecialFlat (player_t *player, int floorType);
|
||||
void P_ActorInSpecialSector (AActor *victim, sector_t * sector=NULL);
|
||||
void P_ActorOnSpecialFlat (AActor *victim, int floorType);
|
||||
void P_SectorDamage(FLevelLocals *Level, int tag, int amount, FName type, PClassActor *protectClass, int flags);
|
||||
void P_SetSectorFriction (FLevelLocals *level, int tag, int amount, bool alterFlag);
|
||||
double FrictionToMoveFactor(double friction);
|
||||
|
|
|
|||
|
|
@ -520,6 +520,23 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, SetFOV)
|
|||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, SetSkin)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
PARAM_INT(skinIndex);
|
||||
if (skinIndex >= 0 && skinIndex < Skins.size())
|
||||
{
|
||||
// commented code - cvar_set calls this automatically, along with saving the skin selection.
|
||||
//self->userinfo.SkinNumChanged(skinIndex);
|
||||
cvar_set("skin", Skins[skinIndex].Name.GetChars());
|
||||
ACTION_RETURN_INT(self->userinfo.GetSkin());
|
||||
}
|
||||
else
|
||||
{
|
||||
ACTION_RETURN_INT(-1);
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// EnumColorsets
|
||||
|
|
@ -773,6 +790,12 @@ DEFINE_ACTION_FUNCTION(_PlayerInfo, GetSkin)
|
|||
ACTION_RETURN_INT(self->userinfo.GetSkin());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetSkinCount)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
ACTION_RETURN_INT(Skins.size());
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetGender)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
|
|
@ -1181,15 +1204,6 @@ DEFINE_ACTION_FUNCTION(APlayerPawn, CheckMusicChange)
|
|||
|
||||
void P_CheckEnvironment(player_t *player)
|
||||
{
|
||||
P_PlayerOnSpecial3DFloor(player);
|
||||
P_PlayerInSpecialSector(player);
|
||||
|
||||
if (!player->mo->isAbove(player->mo->Sector->floorplane.ZatPoint(player->mo)) ||
|
||||
player->mo->waterlevel)
|
||||
{
|
||||
// Player must be touching the floor
|
||||
P_PlayerOnSpecialFlat(player, P_GetThingFloorType(player->mo));
|
||||
}
|
||||
if (player->mo->Vel.Z <= -player->mo->FloatVar(NAME_FallingScreamMinSpeed) &&
|
||||
player->mo->Vel.Z >= -player->mo->FloatVar(NAME_FallingScreamMaxSpeed) && player->mo->alternative == nullptr &&
|
||||
player->mo->waterlevel == 0)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ inline AActor* CheckForShadows(AActor* self, AActor* other, DVector3 pos, double
|
|||
if ((other && (other->flags & MF_SHADOW)) || (self->flags9 & MF9_DOSHADOWBLOCK))
|
||||
{
|
||||
AActor* shadowBlock = P_CheckForShadowBlock(self, other, pos, penaltyFactor);
|
||||
if (other && !(other->flags & MF_SHADOW)) other = nullptr; //Other doesn't have MF_SHADOW, so don't count them as a valid return.
|
||||
return shadowBlock ? shadowBlock : other;
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -322,6 +322,7 @@ angle_t HWDrawInfo::FrustumAngle()
|
|||
{
|
||||
// If pitch is larger than this you can look all around at an FOV of 90 degrees
|
||||
if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 89.0) return 0xffffffff;
|
||||
else if (fabs(Viewpoint.HWAngles.Pitch.Degrees()) > 46.0 && !Viewpoint.IsAllowedOoB()) return 0xffffffff; // Just like 4.12.2 and older did
|
||||
int aspMult = AspectMultiplier(r_viewwindow.WidescreenRatio); // 48 == square window
|
||||
double absPitch = fabs(Viewpoint.HWAngles.Pitch.Degrees());
|
||||
// Smaller aspect ratios still clip too much. Need a better solution
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ EXTERN_CVAR(Bool, gl_aalines)
|
|||
CVAR(Bool, gl_usecolorblending, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, gl_sprite_blend, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||
CVAR(Int, gl_spriteclip, 2, CVAR_ARCHIVE)
|
||||
CVAR(Bool, r_debug_nolimitanamorphoses, false, 0)
|
||||
CVAR(Float, r_spriteclipanamorphicminbias, 0.6, CVAR_ARCHIVE)
|
||||
CVAR(Float, gl_sclipthreshold, 10.0, CVAR_ARCHIVE)
|
||||
CVAR(Float, gl_sclipfactor, 1.8f, CVAR_ARCHIVE)
|
||||
CVAR(Int, gl_particles_style, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 0 = square, 1 = round, 2 = smooth
|
||||
|
|
@ -1099,7 +1101,7 @@ void HWSprite::Process(HWDrawInfo *di, FRenderState& state, AActor* thing, secto
|
|||
|
||||
r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 * thing->isoscaleY : sprscale.Y * thing->isoscaleY);
|
||||
|
||||
if ((thing->renderflags & (RF_ROLLSPRITE|RF_FLATSPRITE)) || (thing->renderflags2 & RF2_SQUAREPIXELS))
|
||||
if ((thing->renderflags & RF_ROLLSPRITE) || (thing->renderflags2 & RF2_SQUAREPIXELS))
|
||||
{
|
||||
double ps = di->Level->pixelstretch;
|
||||
double mult = 1.0 / sqrt(ps); // shrink slightly
|
||||
|
|
@ -1180,6 +1182,56 @@ void HWSprite::Process(HWDrawInfo *di, FRenderState& state, AActor* thing, secto
|
|||
if(thing->renderflags2 & RF2_ISOMETRICSPRITES) depth = depth * vp.PitchCos - vp.PitchSin * z2; // Helps with stacking actors with small xy offsets
|
||||
if (isSpriteShadow) depth += 1.f/65536.f; // always sort shadows behind the sprite.
|
||||
|
||||
if (gl_spriteclip == -1 && (thing->renderflags & RF_SPRITETYPEMASK) == RF_FACESPRITE) // perform anamorphosis
|
||||
{
|
||||
float minbias = r_spriteclipanamorphicminbias;
|
||||
minbias = clamp(minbias, 0.3f, 1.0f);
|
||||
|
||||
float btm = thing->Sector->floorplane.ZatPoint(thing) - thing->Floorclip;
|
||||
float top = thing->Sector->ceilingplane.ZatPoint(thingpos);
|
||||
|
||||
float vbtm = thing->Sector->floorplane.ZatPoint(vp.Pos);
|
||||
float vtop = thing->Sector->ceilingplane.ZatPoint(vp.Pos);
|
||||
|
||||
float vpx = vp.Pos.X;
|
||||
float vpy = vp.Pos.Y;
|
||||
float vpz = vp.Pos.Z;
|
||||
|
||||
float tpx = thingpos.X;
|
||||
float tpy = thingpos.Y;
|
||||
float tpz = thingpos.Z;
|
||||
|
||||
if (!(r_debug_nolimitanamorphoses))
|
||||
{
|
||||
// this should help prevent clipping through walls ...
|
||||
float objradiusbias = 1.f - thing->radius / sqrt((vpx - tpx) * (vpx - tpx) + (vpy - tpy) * (vpy - tpy));
|
||||
minbias = max(minbias, objradiusbias);
|
||||
}
|
||||
|
||||
float bintersect, tintersect;
|
||||
if (z2 < vpz && vbtm < vpz)
|
||||
bintersect = min((btm - vpz) / (z2 - vpz), (vbtm - vpz) / (z2 - vpz));
|
||||
else
|
||||
bintersect = 1.0;
|
||||
|
||||
if (z1 > vpz && vtop > vpz)
|
||||
tintersect = min((top - vpz) / (z1 - vpz), (vtop - vpz) / (z1 - vpz));
|
||||
else
|
||||
tintersect = 1.0;
|
||||
|
||||
if (thing->waterlevel >= 1 && thing->waterlevel <= 2)
|
||||
bintersect = tintersect = 1.0f;
|
||||
|
||||
float spbias = clamp(min(bintersect, tintersect), minbias, 1.0f);
|
||||
float vpbias = 1.0 - spbias;
|
||||
x1 = x1 * spbias + vpx * vpbias;
|
||||
y1 = y1 * spbias + vpy * vpbias;
|
||||
z1 = z1 * spbias + vpz * vpbias;
|
||||
x2 = x2 * spbias + vpx * vpbias;
|
||||
y2 = y2 * spbias + vpy * vpbias;
|
||||
z2 = z2 * spbias + vpz * vpbias;
|
||||
}
|
||||
|
||||
// light calculation
|
||||
|
||||
bool enhancedvision = false;
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ void HandleActorFlag(FScanner &sc, Baggage &bag, const char *part1, const char *
|
|||
AActor *defaults = (AActor*)bag.Info->Defaults;
|
||||
if (fd->structoffset == -1) // this is a deprecated flag that has been changed into a real property
|
||||
{
|
||||
HandleDeprecatedFlags(defaults, bag.Info, mod=='+', fd->flagbit);
|
||||
HandleDeprecatedFlags(defaults, mod=='+', fd->flagbit);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -66,12 +66,13 @@ struct FFlagDef
|
|||
int structoffset;
|
||||
int fieldsize;
|
||||
int varflags;
|
||||
VersionInfo deprecationVersion;
|
||||
};
|
||||
|
||||
void FinalizeClass(PClass *cls, FStateDefinitions &statedef);
|
||||
FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bool strict = false);
|
||||
void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index);
|
||||
bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index);
|
||||
void HandleDeprecatedFlags(AActor *defaults, int set, int index);
|
||||
int CheckDeprecatedFlags(AActor *actor, int index);
|
||||
const char *GetFlagName(unsigned int flagnum, int flagoffset);
|
||||
void ModActorFlag(AActor *actor, FFlagDef *fd, bool set);
|
||||
bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printerror = true);
|
||||
|
|
@ -229,6 +230,9 @@ enum
|
|||
DEPF_DOOMBOUNCE = 11,
|
||||
DEPF_INTERHUBSTRIP = 12,
|
||||
DEPF_HIGHERMPROB = 13,
|
||||
// all that follow need ZScript emulation!
|
||||
DEPF_MISSILEMORE = 14,
|
||||
DEPF_MISSILEEVENMORE = 15
|
||||
};
|
||||
|
||||
// Types of old style decorations
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ extern float BackbuttonAlpha;
|
|||
#define DEFINE_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native }
|
||||
#define DEFINE_PROTECTED_FLAG(prefix, name, type, variable) { (unsigned int)prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_ReadOnly|VARF_InternalAccess }
|
||||
#define DEFINE_FLAG2(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native }
|
||||
#define DEFINE_FLAG2_DEPRECATED(symbol, name, type, variable) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_Deprecated }
|
||||
#define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1, 0, true }
|
||||
#define DEFINE_FLAG2_DEPRECATED(symbol, name, type, variable, version) { (unsigned int)symbol, #name, (int)(size_t)&((type*)1)->variable - 1, sizeof(((type *)0)->variable), VARF_Native|VARF_Deprecated }
|
||||
#define DEFINE_DEPRECATED_FLAG(name, version) { DEPF_##name, #name, -1, 0, VARF_Deprecated, version }
|
||||
#define DEFINE_DUMMY_FLAG(name, deprec) { DEPF_UNUSED, #name, -1, 0, deprec? VARF_Deprecated:0 }
|
||||
|
||||
// internal flags. These do not get exposed to actor definitions but scripts need to be able to access them as variables.
|
||||
|
|
@ -210,8 +210,6 @@ static FFlagDef ActorFlagDefs[]=
|
|||
DEFINE_FLAG(MF4, ACTLIKEBRIDGE, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, STRIFEDAMAGE, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, CANUSEWALLS, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, MISSILEMORE, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, MISSILEEVENMORE, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, FORCERADIUSDMG, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, DONTFALL, AActor, flags4),
|
||||
DEFINE_FLAG(MF4, SEESDAGGERS, AActor, flags4),
|
||||
|
|
@ -353,6 +351,8 @@ static FFlagDef ActorFlagDefs[]=
|
|||
DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9),
|
||||
DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9),
|
||||
DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9),
|
||||
DEFINE_FLAG(MF9, NOSECTORDAMAGE, AActor, flags9),
|
||||
DEFINE_PROTECTED_FLAG(MF9, ISPUFF, AActor, flags9), //[AA] was spawned by SpawnPuff
|
||||
|
||||
// Effect flags
|
||||
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
||||
|
|
@ -408,6 +408,11 @@ static FFlagDef ActorFlagDefs[]=
|
|||
DEFINE_FLAG2(BOUNCE_NotOnSky, DONTBOUNCEONSKY, AActor, BounceFlags),
|
||||
|
||||
DEFINE_FLAG2(OF_Transient, NOSAVEGAME, AActor, ObjectFlags),
|
||||
|
||||
// Deprecated flags which need a ZScript workaround.
|
||||
DEFINE_DEPRECATED_FLAG(MISSILEMORE, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(MISSILEEVENMORE, MakeVersion(4, 13, 0)),
|
||||
|
||||
};
|
||||
|
||||
// These won't be accessible through bitfield variables
|
||||
|
|
@ -415,24 +420,25 @@ static FFlagDef MoreFlagDefs[] =
|
|||
{
|
||||
|
||||
// Deprecated flags. Handling must be performed in HandleDeprecatedFlags
|
||||
DEFINE_DEPRECATED_FLAG(FIREDAMAGE),
|
||||
DEFINE_DEPRECATED_FLAG(ICEDAMAGE),
|
||||
DEFINE_DEPRECATED_FLAG(LOWGRAVITY),
|
||||
DEFINE_DEPRECATED_FLAG(SHORTMISSILERANGE),
|
||||
DEFINE_DEPRECATED_FLAG(LONGMELEERANGE),
|
||||
DEFINE_DEPRECATED_FLAG(QUARTERGRAVITY),
|
||||
DEFINE_DEPRECATED_FLAG(FIRERESIST),
|
||||
DEFINE_DEPRECATED_FLAG(HERETICBOUNCE),
|
||||
DEFINE_DEPRECATED_FLAG(HEXENBOUNCE),
|
||||
DEFINE_DEPRECATED_FLAG(DOOMBOUNCE),
|
||||
DEFINE_DEPRECATED_FLAG(HIGHERMPROB),
|
||||
// Note: Although deprecated since DECORATE times, they were never actually flagged as deprecated before 4.13.0 and no message was output...
|
||||
DEFINE_DEPRECATED_FLAG(FIREDAMAGE, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(ICEDAMAGE, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(LOWGRAVITY, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(SHORTMISSILERANGE, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(LONGMELEERANGE, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(QUARTERGRAVITY, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(FIRERESIST, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(HERETICBOUNCE, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(HEXENBOUNCE, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(DOOMBOUNCE, MakeVersion(4, 13, 0)),
|
||||
DEFINE_DEPRECATED_FLAG(HIGHERMPROB, MakeVersion(4, 13, 0)),
|
||||
|
||||
// Deprecated flags with no more existing functionality.
|
||||
DEFINE_DUMMY_FLAG(FASTER, true), // obsolete, replaced by 'Fast' state flag
|
||||
DEFINE_DUMMY_FLAG(FASTMELEE, true), // obsolete, replaced by 'Fast' state flag
|
||||
|
||||
// Deprecated name as an alias
|
||||
DEFINE_FLAG2_DEPRECATED(MF4_DONTHARMCLASS, DONTHURTSPECIES, AActor, flags4),
|
||||
DEFINE_FLAG2_DEPRECATED(MF4_DONTHARMCLASS, DONTHURTSPECIES, AActor, flags4, 0),
|
||||
|
||||
// Various Skulltag flags that are quite irrelevant to ZDoom
|
||||
// [BC] New DECORATE flag defines here.
|
||||
|
|
@ -914,6 +920,18 @@ void SynthesizeFlagFields()
|
|||
{
|
||||
cls->VMType->AddNativeField(FStringf("b%s", fl.Defs[i].name), (fl.Defs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), fl.Defs[i].structoffset, fl.Defs[i].varflags, fl.Defs[i].flagbit);
|
||||
}
|
||||
else if (fl.Defs[i].flagbit == DEPF_MISSILEMORE || fl.Defs[i].flagbit == DEPF_MISSILEEVENMORE) // these need script side emulation because they have been around for many years.
|
||||
{
|
||||
auto field = cls->VMType->AddNativeField(FStringf("b%s", fl.Defs[i].name), TypeSInt32, 0, VARF_Native);
|
||||
if (field)
|
||||
{
|
||||
// these are deprecated so flag accordingly with a proper message.
|
||||
field->DeprecationMessage = "Use missilechancemult property instead";
|
||||
field->mVersion = MakeVersion(4, 13, 0);
|
||||
field->Flags |= VARF_Deprecated;
|
||||
field->BitValue = fl.Defs[i].flagbit + 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printer
|
|||
|
||||
if (fd->structoffset == -1)
|
||||
{
|
||||
HandleDeprecatedFlags(actor, cls, set, fd->flagbit);
|
||||
HandleDeprecatedFlags(actor, set, fd->flagbit);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -214,7 +214,7 @@ INTBOOL CheckActorFlag(AActor *owner, FFlagDef *fd)
|
|||
{
|
||||
if (fd->structoffset == -1)
|
||||
{
|
||||
return CheckDeprecatedFlags(owner, owner->GetClass(), fd->flagbit);
|
||||
return CheckDeprecatedFlags(owner, fd->flagbit);
|
||||
}
|
||||
else
|
||||
#ifdef __BIG_ENDIAN__
|
||||
|
|
@ -270,70 +270,106 @@ INTBOOL CheckActorFlag(AActor *owner, const char *flagname, bool printerror)
|
|||
// Handles the deprecated flags and sets the respective properties
|
||||
// to appropriate values. This is solely intended for backwards
|
||||
// compatibility so mixing this with code that is aware of the real
|
||||
// properties is not recommended
|
||||
// properties is not recommended and may not do what is expected
|
||||
//
|
||||
//===========================================================================
|
||||
void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int index)
|
||||
void HandleDeprecatedFlags(AActor *actor, int set, int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case DEPF_FIREDAMAGE:
|
||||
defaults->DamageType = set? NAME_Fire : NAME_None;
|
||||
actor->DamageType = set? NAME_Fire : NAME_None;
|
||||
break;
|
||||
case DEPF_ICEDAMAGE:
|
||||
defaults->DamageType = set? NAME_Ice : NAME_None;
|
||||
actor->DamageType = set? NAME_Ice : NAME_None;
|
||||
break;
|
||||
case DEPF_LOWGRAVITY:
|
||||
defaults->Gravity = set ? 1. / 8 : 1.;
|
||||
actor->Gravity = set ? 1. / 8 : 1.;
|
||||
break;
|
||||
case DEPF_SHORTMISSILERANGE:
|
||||
defaults->maxtargetrange = set? 896. : 0.;
|
||||
actor->maxtargetrange = set? 896. : 0.;
|
||||
break;
|
||||
case DEPF_LONGMELEERANGE:
|
||||
defaults->meleethreshold = set? 196. : 0.;
|
||||
actor->meleethreshold = set? 196. : 0.;
|
||||
break;
|
||||
case DEPF_QUARTERGRAVITY:
|
||||
defaults->Gravity = set ? 1. / 4 : 1.;
|
||||
actor->Gravity = set ? 1. / 4 : 1.;
|
||||
break;
|
||||
case DEPF_FIRERESIST:
|
||||
info->SetDamageFactor(NAME_Fire, set ? 0.5 : 1.);
|
||||
actor->GetClass()->SetDamageFactor(NAME_Fire, set ? 0.5 : 1.);
|
||||
break;
|
||||
// the bounce flags will set the compatibility bounce modes to remain compatible
|
||||
case DEPF_HERETICBOUNCE:
|
||||
defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
|
||||
if (set) defaults->BounceFlags |= BOUNCE_HereticCompat;
|
||||
actor->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
|
||||
if (set) actor->BounceFlags |= BOUNCE_HereticCompat;
|
||||
break;
|
||||
case DEPF_HEXENBOUNCE:
|
||||
defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
|
||||
if (set) defaults->BounceFlags |= BOUNCE_HexenCompat;
|
||||
actor->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
|
||||
if (set) actor->BounceFlags |= BOUNCE_HexenCompat;
|
||||
break;
|
||||
case DEPF_DOOMBOUNCE:
|
||||
defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
|
||||
if (set) defaults->BounceFlags |= BOUNCE_DoomCompat;
|
||||
actor->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
|
||||
if (set) actor->BounceFlags |= BOUNCE_DoomCompat;
|
||||
break;
|
||||
case DEPF_PICKUPFLASH:
|
||||
if (set)
|
||||
{
|
||||
defaults->PointerVar<PClass>(NAME_PickupFlash) = FindClassTentative("PickupFlash", RUNTIME_CLASS(AActor));
|
||||
actor->PointerVar<PClass>(NAME_PickupFlash) = FindClassTentative("PickupFlash", RUNTIME_CLASS(AActor));
|
||||
}
|
||||
else
|
||||
{
|
||||
defaults->PointerVar<PClass>(NAME_PickupFlash) = nullptr;
|
||||
actor->PointerVar<PClass>(NAME_PickupFlash) = nullptr;
|
||||
}
|
||||
break;
|
||||
case DEPF_INTERHUBSTRIP: // Old system was 0 or 1, so if the flag is cleared, assume 1.
|
||||
defaults->IntVar(NAME_InterHubAmount) = set ? 0 : 1;
|
||||
actor->IntVar(NAME_InterHubAmount) = set ? 0 : 1;
|
||||
break;
|
||||
|
||||
case DEPF_HIGHERMPROB:
|
||||
defaults->MinMissileChance = set ? 160 : 200;
|
||||
actor->MinMissileChance = set ? 160 : 200;
|
||||
break;
|
||||
|
||||
case DEPF_MISSILEMORE:
|
||||
if (set)
|
||||
{
|
||||
if (actor->missilechancemult == 0.125) actor->missilechancemult = 0.0625;
|
||||
else actor->missilechancemult = 0.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (actor->missilechancemult == 0.0625) actor->missilechancemult = 0.125;
|
||||
else actor->missilechancemult = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DEPF_MISSILEEVENMORE:
|
||||
if (set)
|
||||
{
|
||||
if (actor->missilechancemult == 0.5) actor->missilechancemult = 0.0625;
|
||||
else actor->missilechancemult = 0.125;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (actor->missilechancemult == 0.0625) actor->missilechancemult = 0.5;
|
||||
else actor->missilechancemult = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break; // silence GCC
|
||||
}
|
||||
}
|
||||
|
||||
// the interface here works on object, but currently all deprecated flags affect subclasses of Actor only
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DObject, HandleDeprecatedFlags, HandleDeprecatedFlags)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(set);
|
||||
PARAM_INT(index);
|
||||
HandleDeprecatedFlags(self, set, index);
|
||||
return 0;
|
||||
}
|
||||
//===========================================================================
|
||||
//
|
||||
// CheckDeprecatedFlags
|
||||
|
|
@ -344,7 +380,7 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index)
|
||||
int CheckDeprecatedFlags(AActor *actor, int index)
|
||||
{
|
||||
// A deprecated flag is false if
|
||||
// a) it hasn't been added here
|
||||
|
|
@ -368,7 +404,7 @@ bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index)
|
|||
case DEPF_QUARTERGRAVITY:
|
||||
return actor->Gravity == 1./4;
|
||||
case DEPF_FIRERESIST:
|
||||
for (auto &df : info->ActorInfo()->DamageFactors)
|
||||
for (auto &df : actor->GetClass()->ActorInfo()->DamageFactors)
|
||||
{
|
||||
if (df.first == NAME_Fire) return df.second == 0.5;
|
||||
}
|
||||
|
|
@ -387,15 +423,28 @@ bool CheckDeprecatedFlags(AActor *actor, PClassActor *info, int index)
|
|||
return actor->PointerVar<PClass>(NAME_PickupFlash) == PClass::FindClass(NAME_PickupFlash);
|
||||
|
||||
case DEPF_INTERHUBSTRIP:
|
||||
return !(actor->IntVar(NAME_InterHubAmount));
|
||||
return actor->IntVar(NAME_InterHubAmount) == 0;
|
||||
|
||||
case DEPF_HIGHERMPROB:
|
||||
return actor->MinMissileChance <= 160;
|
||||
|
||||
case DEPF_MISSILEMORE:
|
||||
return actor->missilechancemult == 0.5 || actor->missilechancemult == 0.0625;
|
||||
|
||||
case DEPF_MISSILEEVENMORE:
|
||||
return actor->missilechancemult == 0.125 || actor->missilechancemult == 0.0625;
|
||||
}
|
||||
|
||||
return false; // Any entirely unknown flag is not set
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(DObject, CheckDeprecatedFlags, CheckDeprecatedFlags)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT(index);
|
||||
ACTION_RETURN_INT(CheckDeprecatedFlags(self, index));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
@ -642,6 +691,16 @@ DEFINE_PROPERTY(floatbobstrength, F, Actor)
|
|||
defaults->FloatBobStrength = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(floatbobfactor, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(id, 0);
|
||||
if (id <= 0) I_Error ("FloatBobFactor must be above 0.0");
|
||||
defaults->FloatBobFactor = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
|
|
|||
|
|
@ -2250,7 +2250,12 @@ void FormatMapName(FLevelLocals *self, int cr, FString *result)
|
|||
bool ishub = (cluster != nullptr && (cluster->flags & CLUSTER_HUB));
|
||||
|
||||
*result = "";
|
||||
if (am_showmaplabel == 1 || (am_showmaplabel == 2 && !ishub))
|
||||
// If a label is specified, use it uncontitionally here.
|
||||
if (self->info->MapLabel.IsNotEmpty())
|
||||
{
|
||||
*result << self->info->MapLabel << ": ";
|
||||
}
|
||||
else if (am_showmaplabel == 1 || (am_showmaplabel == 2 && !ishub))
|
||||
{
|
||||
*result << self->MapName << ": ";
|
||||
}
|
||||
|
|
@ -2755,6 +2760,7 @@ DEFINE_FIELD_X(LevelInfo, level_info_t, Music)
|
|||
DEFINE_FIELD_X(LevelInfo, level_info_t, LightningSound)
|
||||
DEFINE_FIELD_X(LevelInfo, level_info_t, LevelName)
|
||||
DEFINE_FIELD_X(LevelInfo, level_info_t, AuthorName)
|
||||
DEFINE_FIELD_X(LevelInfo, level_info_t, MapLabel)
|
||||
DEFINE_FIELD_X(LevelInfo, level_info_t, musicorder)
|
||||
DEFINE_FIELD_X(LevelInfo, level_info_t, skyspeed1)
|
||||
DEFINE_FIELD_X(LevelInfo, level_info_t, skyspeed2)
|
||||
|
|
|
|||
|
|
@ -2005,6 +2005,7 @@ DEFINE_FIELD(AActor, strafecount)
|
|||
DEFINE_FIELD(AActor, target)
|
||||
DEFINE_FIELD(AActor, master)
|
||||
DEFINE_FIELD(AActor, tracer)
|
||||
DEFINE_FIELD(AActor, damagesource)
|
||||
DEFINE_FIELD(AActor, LastHeard)
|
||||
DEFINE_FIELD(AActor, lastenemy)
|
||||
DEFINE_FIELD(AActor, LastLookActor)
|
||||
|
|
@ -2035,6 +2036,7 @@ DEFINE_FIELD(AActor, DamageType)
|
|||
DEFINE_FIELD(AActor, DamageTypeReceived)
|
||||
DEFINE_FIELD(AActor, FloatBobPhase)
|
||||
DEFINE_FIELD(AActor, FloatBobStrength)
|
||||
DEFINE_FIELD(AActor, FloatBobFactor)
|
||||
DEFINE_FIELD(AActor, RipperLevel)
|
||||
DEFINE_FIELD(AActor, RipLevelMin)
|
||||
DEFINE_FIELD(AActor, RipLevelMax)
|
||||
|
|
@ -2042,6 +2044,7 @@ DEFINE_FIELD(AActor, Species)
|
|||
DEFINE_FIELD(AActor, alternative)
|
||||
DEFINE_FIELD(AActor, goal)
|
||||
DEFINE_FIELD(AActor, MinMissileChance)
|
||||
DEFINE_FIELD(AActor, missilechancemult)
|
||||
DEFINE_FIELD(AActor, LastLookPlayerNumber)
|
||||
DEFINE_FIELD(AActor, SpawnFlags)
|
||||
DEFINE_FIELD(AActor, meleethreshold)
|
||||
|
|
|
|||
|
|
@ -795,13 +795,14 @@ void ZCCDoomCompiler::ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg)
|
|||
auto fd = FindFlag(cls, n1, n2, true);
|
||||
if (fd != nullptr)
|
||||
{
|
||||
if (fd->varflags & VARF_Deprecated)
|
||||
if ((fd->varflags & VARF_Deprecated) && fd->deprecationVersion <= this->mVersion)
|
||||
{
|
||||
Warn(flg, "Deprecated flag '%s%s%s' used", n1, n2 ? "." : "", n2 ? n2 : "");
|
||||
Warn(flg, "Deprecated flag '%s%s%s' used, deprecated since %d.%d.%d", n1, n2 ? "." : "", n2 ? n2 : "",
|
||||
fd->deprecationVersion.major, fd->deprecationVersion.minor, fd->deprecationVersion.revision);
|
||||
}
|
||||
if (fd->structoffset == -1)
|
||||
{
|
||||
HandleDeprecatedFlags((AActor*)cls->Defaults, cls, flg->set, fd->flagbit);
|
||||
HandleDeprecatedFlags((AActor*)cls->Defaults, flg->set, fd->flagbit);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
548
src/wi_stuff.cpp
548
src/wi_stuff.cpp
|
|
@ -57,6 +57,9 @@
|
|||
#include "texturemanager.h"
|
||||
#include "v_draw.h"
|
||||
|
||||
#include "serializer.h"
|
||||
#include "s_music.h"
|
||||
|
||||
CVAR(Bool, wi_percents, true, CVAR_ARCHIVE)
|
||||
CVAR(Bool, wi_showtotaltime, true, CVAR_ARCHIVE)
|
||||
CVAR(Bool, wi_noautostartmap, false, CVAR_USERINFO | CVAR_ARCHIVE)
|
||||
|
|
@ -109,6 +112,8 @@ class DInterBackground : public DObject
|
|||
{
|
||||
ANIM_ALWAYS, // determined by patch entry
|
||||
ANIM_PIC, // continuous
|
||||
ANIM_FRAME, // determined by frame properties
|
||||
ANIM_NONE, // frozen (used for infinite duration frames)
|
||||
|
||||
// condition bitflags
|
||||
ANIM_IFVISITED = 8,
|
||||
|
|
@ -137,13 +142,41 @@ class DInterBackground : public DObject
|
|||
FString Level;
|
||||
};
|
||||
|
||||
struct frame_t
|
||||
{
|
||||
FTextureID image;
|
||||
uint32_t type;
|
||||
// In tics!
|
||||
int duration;
|
||||
int max_duration;
|
||||
};
|
||||
|
||||
enum ECondition
|
||||
{
|
||||
COND_NONE = 0, // None.
|
||||
COND_GREATER = 1, // Parameter is greater than current map number.
|
||||
COND_EQUAL = 2, // Parameter is equal to current map number.
|
||||
COND_VISITED = 3, // Map number corresponding to parameter is visited.
|
||||
COND_NOTSECRET = 4, // Current map is not a secret one.
|
||||
COND_SECRETVISTED = 5, // Any secret map was visited.
|
||||
COND_TALLY = 6, // Tally screen.
|
||||
COND_ENTERING = 7, // "Entering" screen.
|
||||
};
|
||||
|
||||
struct condition_t
|
||||
{
|
||||
ECondition condition;
|
||||
int param;
|
||||
};
|
||||
|
||||
struct in_anim_t
|
||||
{
|
||||
int type; // Made an int so I can use '|'
|
||||
int period; // period in tics between animations
|
||||
yahpt_t loc; // location of animation
|
||||
int data; // ALWAYS: n/a, RANDOM: period deviation (<256)
|
||||
TArray<FTextureID> frames; // actual graphics for frames of animations
|
||||
TArray<frame_t> frames; // actual graphics for frames of animations
|
||||
TArray<condition_t> conditions; // conditions to display the animation
|
||||
|
||||
// following must be initialized to zero before use!
|
||||
int nexttic; // next value of bcnt (used in conjunction with period)
|
||||
|
|
@ -162,9 +195,15 @@ class DInterBackground : public DObject
|
|||
}
|
||||
};
|
||||
|
||||
struct in_layer_t
|
||||
{
|
||||
TArray<in_anim_t> anims;
|
||||
TArray<condition_t> conditions; // conditions to display the animations.
|
||||
};
|
||||
|
||||
private:
|
||||
TArray<lnode_t> lnodes;
|
||||
TArray<in_anim_t> anims;
|
||||
TArray<in_layer_t> layers;
|
||||
int bcnt = 0; // used for timing of background animation
|
||||
TArray<FTextureID> yah; // You Are Here graphic
|
||||
FTextureID splat{}; // splat
|
||||
|
|
@ -174,12 +213,14 @@ private:
|
|||
int bgwidth = -1;
|
||||
int bgheight = -1;
|
||||
bool tilebackground = false;
|
||||
FString muslump;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
DInterBackground(wbstartstruct_t *wbst);
|
||||
bool LoadBackground(bool isenterpic);
|
||||
bool IsUsingMusic();
|
||||
void updateAnimatedBack();
|
||||
void drawBackground(int state, bool drawsplat, bool snl_pointeron);
|
||||
|
||||
|
|
@ -242,6 +283,70 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
// Draws the splats and the 'You are here' arrows
|
||||
//
|
||||
//====================================================================
|
||||
bool ConditionsMet(int state, TArray<condition_t>& conditions)
|
||||
{
|
||||
for (auto& condition : conditions)
|
||||
{
|
||||
switch (condition.condition)
|
||||
{
|
||||
case ECondition::COND_NONE:
|
||||
break;
|
||||
case ECondition::COND_EQUAL:
|
||||
{
|
||||
auto* li = FindLevelInfo(state != StatCount ? wbs->next.GetChars() : wbs->current.GetChars());
|
||||
if (!li)
|
||||
return false;
|
||||
if (li->broken_id24_levelnum != condition.param)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ECondition::COND_GREATER:
|
||||
{
|
||||
auto* li = FindLevelInfo(state != StatCount ? wbs->next.GetChars() : wbs->current.GetChars());
|
||||
if (!li)
|
||||
return false;
|
||||
if (li->broken_id24_levelnum <= condition.param)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ECondition::COND_VISITED:
|
||||
{
|
||||
auto* li = FindLevelByNum(condition.param);
|
||||
if (li == NULL || !(li->flags & LEVEL_VISITED))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ECondition::COND_NOTSECRET:
|
||||
{
|
||||
auto* li = FindLevelInfo(state != StatCount ? wbs->next.GetChars() : wbs->current.GetChars());
|
||||
if (!li)
|
||||
return false;
|
||||
if (li->flags3 & LEVEL3_SECRET)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ECondition::COND_SECRETVISTED:
|
||||
if (!SecretLevelVisited())
|
||||
return false;
|
||||
break;
|
||||
case ECondition::COND_TALLY:
|
||||
if (state != StatCount)
|
||||
return false;
|
||||
break;
|
||||
case ECondition::COND_ENTERING:
|
||||
if (state == StatCount)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
DInterBackground:: DInterBackground(wbstartstruct_t *wbst)
|
||||
|
|
@ -270,11 +375,13 @@ bool DInterBackground::LoadBackground(bool isenterpic)
|
|||
{
|
||||
const char* lumpname = nullptr;
|
||||
const char* exitpic = nullptr;
|
||||
const char* exitanim = nullptr;
|
||||
char buffer[10];
|
||||
in_anim_t an;
|
||||
lnode_t pt;
|
||||
FTextureID texture;
|
||||
bool noautostartmap = false;
|
||||
bool id24anim = false;
|
||||
|
||||
bcnt = 0;
|
||||
|
||||
|
|
@ -284,8 +391,17 @@ bool DInterBackground::LoadBackground(bool isenterpic)
|
|||
level_info_t* li = FindLevelInfo(wbs->current.GetChars());
|
||||
if (li != nullptr)
|
||||
{
|
||||
exitpic = li->ExitPic.GetChars();
|
||||
if (li->ExitPic.IsNotEmpty()) tilebackground = false;
|
||||
if (li->ExitAnim.IsNotEmpty())
|
||||
{
|
||||
id24anim = true;
|
||||
exitpic = li->ExitAnim.GetChars();
|
||||
tilebackground = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
exitpic = li->ExitPic.GetChars();
|
||||
if (li->ExitPic.IsNotEmpty()) tilebackground = false;
|
||||
}
|
||||
}
|
||||
lumpname = exitpic;
|
||||
|
||||
|
|
@ -294,8 +410,17 @@ bool DInterBackground::LoadBackground(bool isenterpic)
|
|||
level_info_t* li = FindLevelInfo(wbs->next.GetChars());
|
||||
if (li != NULL)
|
||||
{
|
||||
lumpname = li->EnterPic.GetChars();
|
||||
if (li->EnterPic.IsNotEmpty()) tilebackground = false;
|
||||
if (li->EnterAnim.IsNotEmpty())
|
||||
{
|
||||
id24anim = true;
|
||||
lumpname = li->EnterAnim.GetChars();
|
||||
tilebackground = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
lumpname = li->EnterPic.GetChars();
|
||||
if (li->EnterPic.IsNotEmpty()) tilebackground = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,12 +507,251 @@ bool DInterBackground::LoadBackground(bool isenterpic)
|
|||
}
|
||||
|
||||
lnodes.Clear();
|
||||
anims.Clear();
|
||||
layers.Clear();
|
||||
yah.Clear();
|
||||
splat.SetInvalid();
|
||||
if (!id24anim)
|
||||
layers.Resize(1);
|
||||
|
||||
if (id24anim)
|
||||
{
|
||||
try
|
||||
{
|
||||
int lumpnum = fileSystem.CheckNumForFullName(lumpname, true);
|
||||
if (lumpnum == -1)
|
||||
{
|
||||
I_Error("Intermission animation lump %s not found!", lumpname);
|
||||
}
|
||||
auto data = fileSystem.ReadFile(lumpnum);
|
||||
FSerializer jsonReader;
|
||||
jsonReader.mLumpName = fileSystem.GetFileFullPath(lumpnum);
|
||||
lumpname = jsonReader.mLumpName.GetChars();
|
||||
if (jsonReader.OpenReader(data.string(), data.size()))
|
||||
{
|
||||
FString type = jsonReader.GetString("type");
|
||||
if (type.Compare("interlevel"))
|
||||
{
|
||||
I_Error("Interlevel lump %s is not interlevel!", lumpname);
|
||||
}
|
||||
if (jsonReader.BeginObject("data"))
|
||||
{
|
||||
FString music = jsonReader.GetString("music");
|
||||
if (music.IsEmpty())
|
||||
{
|
||||
I_Error("No music lump specified for intermission animation %s!", lumpname);
|
||||
}
|
||||
muslump = music;
|
||||
if (!MusicExists(muslump.GetChars()))
|
||||
{
|
||||
I_Error("Music lump %s not found!", muslump.GetChars());
|
||||
}
|
||||
|
||||
// Check for background lump.
|
||||
FString backgroundimage = jsonReader.GetString("backgroundimage");
|
||||
texture = TexMan.CheckForTexture(backgroundimage.GetChars(), ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny);
|
||||
if (!texture.isValid())
|
||||
{
|
||||
if (backgroundimage.IsEmpty())
|
||||
{
|
||||
I_Error("No background image specified for intermission animation %s!", lumpname);
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("Texture %s not found!", backgroundimage.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
if (!jsonReader.IsKeyNull("layers") && jsonReader.BeginArray("layers"))
|
||||
{
|
||||
int size = jsonReader.ArraySize();
|
||||
|
||||
if (size == 0)
|
||||
I_Error("Zero-length 'layers' array in %s", lumpname);
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (jsonReader.BeginObject(nullptr))
|
||||
{
|
||||
layers.Reserve(1);
|
||||
auto& layer = layers.back();
|
||||
if (!jsonReader.IsKeyNull("conditions") && jsonReader.BeginArray("conditions"))
|
||||
{
|
||||
int condition_size = jsonReader.ArraySize();
|
||||
if (condition_size == 0)
|
||||
{
|
||||
I_Error("Condition array empty and not null for layer %d in lump %s", layers.Size(), lumpname);
|
||||
}
|
||||
for (int j = 0; j < condition_size; j++)
|
||||
{
|
||||
if (jsonReader.BeginObject(nullptr))
|
||||
{
|
||||
ECondition cond = COND_NONE;
|
||||
int param = 0;
|
||||
::Serialize(jsonReader, "condition", (int&)cond, nullptr);
|
||||
::Serialize(jsonReader, "param", param, nullptr);
|
||||
layer.conditions.Push(condition_t{ cond, param });
|
||||
jsonReader.EndObject();
|
||||
}
|
||||
}
|
||||
jsonReader.EndArray();
|
||||
}
|
||||
|
||||
// Read anims.
|
||||
if (jsonReader.BeginArray("anims"))
|
||||
{
|
||||
int anim_size = jsonReader.ArraySize();
|
||||
if (anim_size == 0)
|
||||
{
|
||||
I_Error("No animations defined for layer %d in lump %s", layers.Size(), lumpname);
|
||||
}
|
||||
|
||||
for (int j = 0; j < anim_size; j++)
|
||||
{
|
||||
if (jsonReader.BeginObject(nullptr))
|
||||
{
|
||||
layer.anims.Reserve(1);
|
||||
auto& anim = layer.anims.back();
|
||||
|
||||
anim.Reset();
|
||||
anim.type = ANIM_FRAME;
|
||||
anim.ctr = 0;
|
||||
anim.data = 0;
|
||||
|
||||
::Serialize(jsonReader, "x", anim.loc.x, nullptr);
|
||||
::Serialize(jsonReader, "y", anim.loc.y, nullptr);
|
||||
|
||||
if (!jsonReader.IsKeyNull("conditions") && jsonReader.BeginArray("conditions"))
|
||||
{
|
||||
int condition_size = jsonReader.ArraySize();
|
||||
if (condition_size == 0)
|
||||
{
|
||||
I_Error("Condition array empty and not null for anim %d, layer %d in lump %s", layer.anims.Size(), layers.Size(), lumpname);
|
||||
}
|
||||
for (int k = 0; k < condition_size; k++)
|
||||
{
|
||||
if (jsonReader.BeginObject(nullptr))
|
||||
{
|
||||
ECondition cond = COND_NONE;
|
||||
int param = 0;
|
||||
::Serialize(jsonReader, "condition", (int&)cond, nullptr);
|
||||
::Serialize(jsonReader, "param", param, nullptr);
|
||||
anim.conditions.Push(condition_t{ cond, param });
|
||||
jsonReader.EndObject();
|
||||
}
|
||||
}
|
||||
jsonReader.EndArray();
|
||||
}
|
||||
|
||||
if (jsonReader.BeginArray("frames"))
|
||||
{
|
||||
int frames = jsonReader.ArraySize();
|
||||
|
||||
if (frames == 0)
|
||||
{
|
||||
I_Error("No frames defined for anim %d, layer %d in lump %s", layer.anims.Size(), layers.Size(), lumpname);
|
||||
}
|
||||
for (int k = 0; k < frames; k++)
|
||||
{
|
||||
if (jsonReader.BeginObject(nullptr))
|
||||
{
|
||||
double duration = 0.0;
|
||||
double maxduration = 0.0;
|
||||
anim.frames.Reserve(1);
|
||||
auto& frame = anim.frames.back();
|
||||
|
||||
::Serialize(jsonReader, "duration", duration, nullptr);
|
||||
::Serialize(jsonReader, "maxduration", maxduration, nullptr);
|
||||
::Serialize(jsonReader, "type", frame.type, nullptr);
|
||||
|
||||
FString image = jsonReader.GetString("image");
|
||||
if (image.IsEmpty())
|
||||
{
|
||||
I_Error("No image defined for frame %d, anim %d, layer %d in lump %s", anim.frames.Size(), layer.anims.Size(), layers.Size(), lumpname);
|
||||
}
|
||||
|
||||
frame.image = TexMan.CheckForTexture(image.GetChars(), ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny);
|
||||
if (!frame.image.isValid())
|
||||
{
|
||||
I_Error("Texture '%s' not found!", image.GetChars());
|
||||
}
|
||||
|
||||
frame.duration = round(duration * (double)TICRATE);
|
||||
frame.max_duration = round(maxduration * (double)TICRATE);
|
||||
|
||||
if (frame.duration <= 0 && duration > 0.0)
|
||||
{
|
||||
frame.duration = 1;
|
||||
}
|
||||
|
||||
if (frame.max_duration <= 0 && maxduration > 0.0)
|
||||
{
|
||||
frame.max_duration = 1;
|
||||
}
|
||||
|
||||
if (anim.frames.Size() == 1)
|
||||
{
|
||||
if (frame.type & 0x1000)
|
||||
{
|
||||
frame.type &= ~0x1000;
|
||||
anim.nexttic = 1 + (M_Random() % frame.duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
switch (frame.type)
|
||||
{
|
||||
case 0x1:
|
||||
anim.type = ANIM_NONE;
|
||||
break;
|
||||
case 0x4:
|
||||
anim.nexttic = 1 + M_Random(frame.max_duration - frame.duration + 1) + frame.duration;
|
||||
break;
|
||||
case 0x2:
|
||||
anim.nexttic = 1 + frame.duration;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jsonReader.EndObject();
|
||||
}
|
||||
}
|
||||
jsonReader.EndArray();
|
||||
}
|
||||
|
||||
jsonReader.EndObject();
|
||||
}
|
||||
}
|
||||
|
||||
jsonReader.EndArray();
|
||||
}
|
||||
|
||||
jsonReader.EndObject();
|
||||
}
|
||||
}
|
||||
jsonReader.EndArray();
|
||||
}
|
||||
|
||||
jsonReader.EndObject();
|
||||
}
|
||||
jsonReader.Close();
|
||||
}
|
||||
}
|
||||
// This is deliberate. Errors coming from here shouldn't cause a console abort.
|
||||
catch (CRecoverableError& error)
|
||||
{
|
||||
Printf(TEXTCOLOR_RED "Failed to parse intermission anim definition %s: %s.\nFalling back to non-anim definitions.\n", lumpname, error.GetMessage());
|
||||
|
||||
if (isenterpic)
|
||||
li->EnterAnim = "";
|
||||
else
|
||||
li->ExitAnim = "";
|
||||
|
||||
return LoadBackground(isenterpic);
|
||||
}
|
||||
}
|
||||
// a name with a starting '$' indicates an intermission script
|
||||
if (*lumpname != '$')
|
||||
else if (*lumpname != '$')
|
||||
{
|
||||
texture = TexMan.CheckForTexture(lumpname, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny);
|
||||
}
|
||||
|
|
@ -520,18 +884,20 @@ bool DInterBackground::LoadBackground(bool isenterpic)
|
|||
if (!sc.CheckString("{"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
an.frames.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny));
|
||||
auto textureId = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny);
|
||||
an.frames.Push(frame_t{ textureId, 0, 0, 0 });
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!sc.CheckString("}"))
|
||||
{
|
||||
sc.MustGetString();
|
||||
an.frames.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny));
|
||||
auto textureId = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny);
|
||||
an.frames.Push(frame_t{ textureId, 0, 0, 0 });
|
||||
}
|
||||
}
|
||||
an.ctr = -1;
|
||||
anims.Push(an);
|
||||
layers[0].anims.Push(an);
|
||||
break;
|
||||
|
||||
case 13: // Pic
|
||||
|
|
@ -542,8 +908,8 @@ bool DInterBackground::LoadBackground(bool isenterpic)
|
|||
an.loc.y = sc.Number;
|
||||
sc.MustGetString();
|
||||
an.frames.Reserve(1); // allocate exactly one element
|
||||
an.frames[0] = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny);
|
||||
anims.Push(an);
|
||||
an.frames[0].image = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny);
|
||||
layers[0].anims.Push(an);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -554,6 +920,7 @@ bool DInterBackground::LoadBackground(bool isenterpic)
|
|||
}
|
||||
else
|
||||
{
|
||||
|
||||
Printf("Intermission script %s not found!\n", lumpname + 1);
|
||||
texture = TexMan.GetTextureID("INTERPIC", ETextureType::MiscPatch);
|
||||
}
|
||||
|
|
@ -585,27 +952,59 @@ void DInterBackground::updateAnimatedBack()
|
|||
unsigned int i;
|
||||
|
||||
bcnt++;
|
||||
for (i = 0; i<anims.Size(); i++)
|
||||
if (bcnt == 1 && muslump.IsNotEmpty())
|
||||
{
|
||||
in_anim_t * a = &anims[i];
|
||||
switch (a->type & ANIM_TYPE)
|
||||
S_ChangeMusic(muslump.GetChars());
|
||||
}
|
||||
|
||||
for (auto& layer : layers)
|
||||
{
|
||||
auto& anims = layer.anims;
|
||||
for (i = 0; i < anims.Size(); i++)
|
||||
{
|
||||
case ANIM_ALWAYS:
|
||||
if (bcnt >= a->nexttic)
|
||||
in_anim_t* a = &anims[i];
|
||||
switch (a->type & ANIM_TYPE)
|
||||
{
|
||||
if (++a->ctr >= (int)a->frames.Size())
|
||||
case ANIM_NONE:
|
||||
break;
|
||||
|
||||
case ANIM_FRAME:
|
||||
if (bcnt >= a->nexttic)
|
||||
{
|
||||
if (a->data == 0) a->ctr = 0;
|
||||
else a->ctr--;
|
||||
if (++a->ctr >= (int)a->frames.Size())
|
||||
a->ctr = 0;
|
||||
|
||||
switch (a->frames[a->ctr].type & 0x7) {
|
||||
case 0x1:
|
||||
a->type &= ANIM_CONDITION;
|
||||
a->type = ANIM_NONE;
|
||||
break;
|
||||
case 0x4:
|
||||
a->nexttic = bcnt + M_Random(a->frames[a->ctr].max_duration - a->frames[a->ctr].duration + 1) + a->frames[a->ctr].duration;
|
||||
break;
|
||||
case 0x2:
|
||||
a->nexttic = bcnt + a->frames[a->ctr].duration;
|
||||
break;
|
||||
}
|
||||
}
|
||||
a->nexttic = bcnt + a->period;
|
||||
break;
|
||||
case ANIM_ALWAYS:
|
||||
if (bcnt >= a->nexttic)
|
||||
{
|
||||
if (++a->ctr >= (int)a->frames.Size())
|
||||
{
|
||||
if (a->data == 0) a->ctr = 0;
|
||||
else a->ctr--;
|
||||
}
|
||||
a->nexttic = bcnt + a->period;
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIM_PIC:
|
||||
a->ctr = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case ANIM_PIC:
|
||||
a->ctr = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -656,51 +1055,59 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe
|
|||
ClearRect(twod, 0, 0, twod->GetWidth(), twod->GetHeight(), 0, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i<anims.Size(); i++)
|
||||
for (auto& layer : layers)
|
||||
{
|
||||
in_anim_t * a = &anims[i];
|
||||
level_info_t *li;
|
||||
auto& anims = layer.anims;
|
||||
|
||||
switch (a->type & ANIM_CONDITION)
|
||||
if (!ConditionsMet(state, layer.conditions))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < anims.Size(); i++)
|
||||
{
|
||||
case ANIM_IFVISITED:
|
||||
li = FindLevelInfo(a->LevelName.GetChars());
|
||||
if (li == NULL || !(li->flags & LEVEL_VISITED)) continue;
|
||||
break;
|
||||
in_anim_t* a = &anims[i];
|
||||
level_info_t* li;
|
||||
|
||||
case ANIM_IFNOTVISITED:
|
||||
li = FindLevelInfo(a->LevelName.GetChars());
|
||||
if (li == NULL || (li->flags & LEVEL_VISITED)) continue;
|
||||
break;
|
||||
switch (a->type & ANIM_CONDITION)
|
||||
{
|
||||
case ANIM_IFVISITED:
|
||||
li = FindLevelInfo(a->LevelName.GetChars());
|
||||
if (li == NULL || !(li->flags & LEVEL_VISITED)) continue;
|
||||
break;
|
||||
|
||||
// StatCount means 'leaving' - everything else means 'entering'!
|
||||
case ANIM_IFENTERING:
|
||||
if (state == StatCount || a->LevelName.CompareNoCase(wbs->next, 8)) continue;
|
||||
break;
|
||||
case ANIM_IFNOTVISITED:
|
||||
li = FindLevelInfo(a->LevelName.GetChars());
|
||||
if (li == NULL || (li->flags & LEVEL_VISITED)) continue;
|
||||
break;
|
||||
|
||||
case ANIM_IFNOTENTERING:
|
||||
if (state != StatCount && !a->LevelName.CompareNoCase(wbs->next, 8)) continue;
|
||||
break;
|
||||
// StatCount means 'leaving' - everything else means 'entering'!
|
||||
case ANIM_IFENTERING:
|
||||
if (state == StatCount || a->LevelName.CompareNoCase(wbs->next, 8)) continue;
|
||||
break;
|
||||
|
||||
case ANIM_IFLEAVING:
|
||||
if (state != StatCount || a->LevelName.CompareNoCase(wbs->current, 8)) continue;
|
||||
break;
|
||||
case ANIM_IFNOTENTERING:
|
||||
if (state != StatCount && !a->LevelName.CompareNoCase(wbs->next, 8)) continue;
|
||||
break;
|
||||
|
||||
case ANIM_IFNOTLEAVING:
|
||||
if (state == StatCount && !a->LevelName.CompareNoCase(wbs->current, 8)) continue;
|
||||
break;
|
||||
case ANIM_IFLEAVING:
|
||||
if (state != StatCount || a->LevelName.CompareNoCase(wbs->current, 8)) continue;
|
||||
break;
|
||||
|
||||
case ANIM_IFTRAVELLING:
|
||||
if (a->LevelName2.CompareNoCase(wbs->current, 8) || a->LevelName.CompareNoCase(wbs->next, 8)) continue;
|
||||
break;
|
||||
case ANIM_IFNOTLEAVING:
|
||||
if (state == StatCount && !a->LevelName.CompareNoCase(wbs->current, 8)) continue;
|
||||
break;
|
||||
|
||||
case ANIM_IFNOTTRAVELLING:
|
||||
if (!a->LevelName2.CompareNoCase(wbs->current, 8) && !a->LevelName.CompareNoCase(wbs->next, 8)) continue;
|
||||
break;
|
||||
case ANIM_IFTRAVELLING:
|
||||
if (a->LevelName2.CompareNoCase(wbs->current, 8) || a->LevelName.CompareNoCase(wbs->next, 8)) continue;
|
||||
break;
|
||||
|
||||
case ANIM_IFNOTTRAVELLING:
|
||||
if (!a->LevelName2.CompareNoCase(wbs->current, 8) && !a->LevelName.CompareNoCase(wbs->next, 8)) continue;
|
||||
break;
|
||||
}
|
||||
if (a->ctr >= 0 && ConditionsMet(state, a->conditions))
|
||||
DrawTexture(twod, a->frames[a->ctr].image, false, a->loc.x, a->loc.y,
|
||||
DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, DTA_FullscreenScale, FSMode_ScaleToFit43, TAG_DONE);
|
||||
}
|
||||
if (a->ctr >= 0)
|
||||
DrawTexture(twod, a->frames[a->ctr], false, a->loc.x, a->loc.y,
|
||||
DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, DTA_FullscreenScale, FSMode_ScaleToFit43, TAG_DONE);
|
||||
}
|
||||
|
||||
if (drawsplat)
|
||||
|
|
@ -731,6 +1138,23 @@ DEFINE_ACTION_FUNCTION(DInterBackground, drawBackground)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//====================================================================
|
||||
|
||||
bool DInterBackground::IsUsingMusic()
|
||||
{
|
||||
return muslump.IsNotEmpty();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(DInterBackground, IsUsingMusic)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(DInterBackground);
|
||||
ACTION_RETURN_BOOL(self->IsUsingMusic());
|
||||
}
|
||||
|
||||
IMPLEMENT_CLASS(DInterBackground, true, false)
|
||||
|
||||
//====================================================================
|
||||
|
|
|
|||
|
|
@ -2516,6 +2516,7 @@ OptionValue "SpriteclipModes"
|
|||
1, "$OPTVAL_SMART"
|
||||
2, "$OPTVAL_ALWAYS"
|
||||
3, "$OPTVAL_SMARTER"
|
||||
-1, "$OPTVAL_ANAMORPHIC"
|
||||
}
|
||||
|
||||
OptionValue "EnhancedStealth"
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ class Actor : Thinker native
|
|||
native Actor Target;
|
||||
native Actor Master;
|
||||
native Actor Tracer;
|
||||
native readonly Actor DamageSource;
|
||||
native Actor LastHeard;
|
||||
native Actor LastEnemy;
|
||||
native Actor LastLookActor;
|
||||
|
|
@ -178,6 +179,7 @@ class Actor : Thinker native
|
|||
native name DamageTypeReceived;
|
||||
native uint8 FloatBobPhase;
|
||||
native double FloatBobStrength;
|
||||
native double FloatBobFactor;
|
||||
native int RipperLevel;
|
||||
native int RipLevelMin;
|
||||
native int RipLevelMax;
|
||||
|
|
@ -185,6 +187,7 @@ class Actor : Thinker native
|
|||
native Actor Alternative;
|
||||
native Actor goal;
|
||||
native uint8 MinMissileChance;
|
||||
native double MissileChanceMult;
|
||||
native int8 LastLookPlayerNumber;
|
||||
native uint SpawnFlags;
|
||||
native double meleethreshold;
|
||||
|
|
@ -337,6 +340,7 @@ class Actor : Thinker native
|
|||
property WeaveIndexXY: WeaveIndexXY;
|
||||
property WeaveIndexZ: WeaveIndexZ;
|
||||
property MinMissileChance: MinMissileChance;
|
||||
property MissileChanceMult: MissileChanceMult;
|
||||
property MaxStepHeight: MaxStepHeight;
|
||||
property MaxDropoffHeight: MaxDropoffHeight;
|
||||
property MaxSlopeSteepness: MaxSlopeSteepness;
|
||||
|
|
@ -403,6 +407,7 @@ class Actor : Thinker native
|
|||
RenderStyle 'Normal';
|
||||
Alpha 1;
|
||||
MinMissileChance 200;
|
||||
MissileChanceMult 1.0;
|
||||
MeleeRange 64 - MELEEDELTA;
|
||||
MaxDropoffHeight 24;
|
||||
MaxStepHeight 24;
|
||||
|
|
@ -413,6 +418,7 @@ class Actor : Thinker native
|
|||
FloatSpeed 4;
|
||||
FloatBobPhase -1; // randomly initialize by default
|
||||
FloatBobStrength 1.0;
|
||||
FloatBobFactor 1.0;
|
||||
Gravity 1;
|
||||
Friction 1;
|
||||
DamageFactor 1.0; // damage multiplier as target of damage.
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ extend class Actor
|
|||
else if (originator.player)
|
||||
{
|
||||
// A player always spawns a monster friendly to him
|
||||
mo.bFriendly = true;
|
||||
mo.A_SetFriendly(true);
|
||||
mo.SetFriendPlayer(originator.player);
|
||||
|
||||
Actor attacker=originator.player.attacker;
|
||||
|
|
@ -609,6 +609,7 @@ extend class Actor
|
|||
if (flags & XF_THRUSTLESS) pflags |= RADF_THRUSTLESS;
|
||||
if (flags & XF_NOALLIES) pflags |= RADF_NOALLIES;
|
||||
if (flags & XF_CIRCULAR) pflags |= RADF_CIRCULAR;
|
||||
if (flags & XF_CIRCULARTHRUST) pflags |= RADF_CIRCULARTHRUST;
|
||||
|
||||
int count = RadiusAttack (target, damage, distance, damagetype, pflags, fulldamagedistance);
|
||||
if (!(flags & XF_NOSPLASH)) CheckSplash(distance);
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ class Cyberdemon : Actor
|
|||
PainChance 20;
|
||||
Monster;
|
||||
MinMissileChance 160;
|
||||
MissileChanceMult 0.5;
|
||||
+BOSS
|
||||
+MISSILEMORE
|
||||
+FLOORCLIP
|
||||
+NORADIUSDMG
|
||||
+DONTMORPH
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ class LostSoul : Actor
|
|||
Speed 8;
|
||||
Damage 3;
|
||||
PainChance 256;
|
||||
MissileChanceMult 0.5;
|
||||
Monster;
|
||||
+FLOAT +NOGRAVITY +MISSILEMORE +DONTFALL +NOICEDEATH +ZDOOMTRANS +RETARGETAFTERSLAM
|
||||
+FLOAT +NOGRAVITY +DONTFALL +NOICEDEATH +ZDOOMTRANS +RETARGETAFTERSLAM
|
||||
AttackSound "skull/melee";
|
||||
PainSound "skull/pain";
|
||||
DeathSound "skull/death";
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ extend class Actor
|
|||
{
|
||||
if (target && IsFriend(target))
|
||||
{ // And I thought you were my friend!
|
||||
bFriendly = false;
|
||||
A_SetFriendly(false);
|
||||
}
|
||||
A_NoBlocking();
|
||||
A_PainShootSkull(spawntype, angle + 90);
|
||||
|
|
|
|||
|
|
@ -342,12 +342,16 @@ extend class Actor
|
|||
|
||||
void A_CPosRefire()
|
||||
{
|
||||
if (HitFriend())
|
||||
{
|
||||
SetState(SeeState);
|
||||
return;
|
||||
}
|
||||
// keep firing unless target got out of sight
|
||||
A_FaceTarget();
|
||||
if (Random[CPosRefire](0, 255) >= 40)
|
||||
{
|
||||
if (!target
|
||||
|| HitFriend()
|
||||
|| target.health <= 0
|
||||
|| !CheckSight(target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class Revenant : Actor
|
|||
PainChance 100;
|
||||
Monster;
|
||||
MeleeThreshold 196;
|
||||
+MISSILEMORE
|
||||
MissileChanceMult 0.5;
|
||||
+FLOORCLIP
|
||||
SeeSound "skeleton/sight";
|
||||
PainSound "skeleton/pain";
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ class SpiderMastermind : Actor
|
|||
Mass 1000;
|
||||
Speed 12;
|
||||
PainChance 40;
|
||||
MissileChanceMult 0.5;
|
||||
Monster;
|
||||
+BOSS
|
||||
+MISSILEMORE
|
||||
+FLOORCLIP
|
||||
+NORADIUSDMG
|
||||
+DONTMORPH
|
||||
|
|
@ -73,12 +73,16 @@ extend class Actor
|
|||
{
|
||||
void A_SpidRefire()
|
||||
{
|
||||
if (HitFriend())
|
||||
{
|
||||
SetState(SeeState);
|
||||
return;
|
||||
}
|
||||
// keep firing unless target got out of sight
|
||||
A_FaceTarget();
|
||||
if (Random[CPosRefire](0, 255) >= 10)
|
||||
{
|
||||
if (!target
|
||||
|| HitFriend()
|
||||
|| target.health <= 0
|
||||
|| !CheckSight(target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ class HereticImp : Actor
|
|||
Mass 50;
|
||||
Speed 10;
|
||||
Painchance 200;
|
||||
MissileChanceMult 0.5;
|
||||
Monster;
|
||||
+FLOAT
|
||||
+NOGRAVITY
|
||||
+SPAWNFLOAT
|
||||
+DONTOVERLAP
|
||||
+MISSILEMORE
|
||||
SeeSound "himp/sight";
|
||||
AttackSound "himp/attack";
|
||||
PainSound "himp/pain";
|
||||
|
|
@ -159,7 +159,7 @@ class HereticImpLeader : HereticImp
|
|||
{
|
||||
Species "HereticImpLeader";
|
||||
Health 80;
|
||||
-MISSILEMORE
|
||||
MissileChanceMult 1;
|
||||
AttackSound "himp/leaderattack";
|
||||
}
|
||||
States
|
||||
|
|
|
|||
|
|
@ -2867,6 +2867,7 @@ struct PlayerInfo native play // self is what internally is known as player_t
|
|||
native clearscope int GetColorSet() const;
|
||||
native clearscope int GetPlayerClassNum() const;
|
||||
native clearscope int GetSkin() const;
|
||||
native clearscope int GetSkinCount() const;
|
||||
native clearscope bool GetNeverSwitch() const;
|
||||
native clearscope int GetGender() const;
|
||||
native clearscope int GetTeam() const;
|
||||
|
|
@ -2878,6 +2879,7 @@ struct PlayerInfo native play // self is what internally is known as player_t
|
|||
native bool GetFViewBob() const;
|
||||
native double GetStillBob() const;
|
||||
native void SetFOV(float fov);
|
||||
native int SetSkin(int skinIndex);
|
||||
native clearscope bool GetClassicFlight() const;
|
||||
native void SendPitchLimits();
|
||||
native clearscope bool HasWeaponsInSlot(int slot) const;
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ class Acolyte : StrifeHumanoid
|
|||
void A_BeShadowyFoe()
|
||||
{
|
||||
A_SetRenderStyle(HR_SHADOW, STYLE_Translucent);
|
||||
bFriendly = false;
|
||||
A_SetFriendly(false);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
|
@ -155,7 +155,7 @@ class AcolyteTan : Acolyte
|
|||
{
|
||||
Default
|
||||
{
|
||||
+MISSILEMORE +MISSILEEVENMORE
|
||||
MissileChanceMult 0.0625;
|
||||
DropItem "ClipOfBullets";
|
||||
}
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ class AcolyteRed : Acolyte
|
|||
{
|
||||
Default
|
||||
{
|
||||
+MISSILEMORE +MISSILEEVENMORE
|
||||
MissileChanceMult 0.0625;
|
||||
Translation 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -177,7 +177,7 @@ class AcolyteRust : Acolyte
|
|||
{
|
||||
Default
|
||||
{
|
||||
+MISSILEMORE +MISSILEEVENMORE
|
||||
MissileChanceMult 0.0625;
|
||||
Translation 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ class AcolyteGray : Acolyte
|
|||
{
|
||||
Default
|
||||
{
|
||||
+MISSILEMORE +MISSILEEVENMORE
|
||||
MissileChanceMult 0.0625;
|
||||
Translation 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ class AcolyteDGreen : Acolyte
|
|||
{
|
||||
Default
|
||||
{
|
||||
+MISSILEMORE +MISSILEEVENMORE
|
||||
MissileChanceMult 0.0625;
|
||||
Translation 3;
|
||||
}
|
||||
}
|
||||
|
|
@ -210,7 +210,7 @@ class AcolyteGold : Acolyte
|
|||
{
|
||||
Default
|
||||
{
|
||||
+MISSILEMORE +MISSILEEVENMORE
|
||||
MissileChanceMult 0.0625;
|
||||
Translation 4;
|
||||
}
|
||||
}
|
||||
|
|
@ -243,7 +243,7 @@ class AcolyteShadow : Acolyte
|
|||
{
|
||||
Default
|
||||
{
|
||||
+MISSILEMORE
|
||||
MissileChanceMult 0.5;
|
||||
DropItem "ClipOfBullets";
|
||||
}
|
||||
States
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ class Crusader : Actor
|
|||
Mass 400;
|
||||
Health 400;
|
||||
Painchance 128;
|
||||
MissileChanceMult 0.5;
|
||||
Monster;
|
||||
+FLOORCLIP
|
||||
+DONTMORPH
|
||||
+MISSILEMORE
|
||||
+INCOMBAT
|
||||
+NOICEDEATH
|
||||
+NOBLOOD
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class Sentinel : Actor
|
|||
Radius 23;
|
||||
Height 53;
|
||||
Mass 300;
|
||||
MissileChanceMult 0.5;
|
||||
Monster;
|
||||
+SPAWNCEILING
|
||||
+NOGRAVITY
|
||||
|
|
@ -18,7 +19,6 @@ class Sentinel : Actor
|
|||
+NOBLOOD
|
||||
+NOBLOCKMONST
|
||||
+INCOMBAT
|
||||
+MISSILEMORE
|
||||
+LOOKALLAROUND
|
||||
+NEVERRESPAWN
|
||||
MinMissileChance 150;
|
||||
|
|
@ -164,13 +164,17 @@ extend class Actor
|
|||
void A_SentinelRefire()
|
||||
{
|
||||
A_FaceTarget ();
|
||||
if (HitFriend())
|
||||
{
|
||||
SetState(SeeState);
|
||||
return;
|
||||
}
|
||||
|
||||
if (random[SentinelRefire]() >= 30)
|
||||
{
|
||||
if (target == NULL ||
|
||||
target.health <= 0 ||
|
||||
!CheckSight (target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) ||
|
||||
HitFriend() ||
|
||||
(MissileState == NULL && !CheckMeleeRange()) ||
|
||||
random[SentinelRefire]() < 40)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ enum EExplodeFlags
|
|||
XF_THRUSTLESS = 64,
|
||||
XF_NOALLIES = 128,
|
||||
XF_CIRCULAR = 256,
|
||||
XF_CIRCULARTHRUST = 512,
|
||||
};
|
||||
|
||||
// Flags for A_RadiusThrust
|
||||
|
|
@ -276,6 +277,7 @@ enum ERadiusThrustFlags
|
|||
RTF_NOIMPACTDAMAGE = 2,
|
||||
RTF_NOTMISSILE = 4,
|
||||
RTF_THRUSTZ = 16,
|
||||
RTF_CIRCULARTHRUST = 512,
|
||||
};
|
||||
|
||||
// Flags for A_RadiusDamageSelf
|
||||
|
|
@ -1254,7 +1256,8 @@ enum RadiusDamageFlags
|
|||
RADF_OLDRADIUSDAMAGE = 32,
|
||||
RADF_THRUSTLESS = 64,
|
||||
RADF_NOALLIES = 128,
|
||||
RADF_CIRCULAR = 256
|
||||
RADF_CIRCULAR = 256,
|
||||
RADF_CIRCULARTHRUST = 512,
|
||||
};
|
||||
|
||||
enum IntermissionSequenceType
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ struct LevelInfo native
|
|||
native readonly String LightningSound;
|
||||
native readonly String Music;
|
||||
native readonly String LevelName;
|
||||
native readonly String MapLabel;
|
||||
native readonly String AuthorName;
|
||||
native readonly int musicorder;
|
||||
native readonly float skyspeed1;
|
||||
|
|
|
|||
|
|
@ -143,6 +143,15 @@ enum EPrintLevel
|
|||
PRINT_NOLOG = 2048, // Flag - do not print to log file
|
||||
};
|
||||
|
||||
enum EDebugLevel
|
||||
{
|
||||
DMSG_OFF, // no developer messages.
|
||||
DMSG_ERROR, // general notification messages
|
||||
DMSG_WARNING, // warnings
|
||||
DMSG_NOTIFY, // general notification messages
|
||||
DMSG_SPAMMY, // for those who want to see everything, regardless of its usefulness.
|
||||
};
|
||||
|
||||
enum EConsoleState
|
||||
{
|
||||
c_up = 0,
|
||||
|
|
@ -665,6 +674,7 @@ struct Console native
|
|||
native static void HideConsole();
|
||||
native static vararg void Printf(string fmt, ...);
|
||||
native static vararg void PrintfEx(int printlevel, string fmt, ...);
|
||||
native static vararg void DebugPrintf(int debuglevel, string fmt, ...);
|
||||
}
|
||||
|
||||
struct CVar native
|
||||
|
|
@ -750,6 +760,8 @@ class Object native
|
|||
private native static Class<Object> BuiltinNameToClass(Name nm, Class<Object> filter);
|
||||
private native static Object BuiltinClassCast(Object inptr, Class<Object> test);
|
||||
private native static Function<void> BuiltinFunctionPtrCast(Function<void> inptr, voidptr newtype);
|
||||
private native static void HandleDeprecatedFlags(Object obj, bool set, int index);
|
||||
private native static bool CheckDeprecatedFlags(Object obj, int index);
|
||||
|
||||
native static uint MSTime();
|
||||
native static double MSTimeF();
|
||||
|
|
|
|||
|
|
@ -435,6 +435,11 @@ struct Sector native play
|
|||
SECMF_UNDERWATERMASK = 32+64,
|
||||
SECMF_DRAWN = 128, // sector has been drawn at least once
|
||||
SECMF_HIDDEN = 256, // Do not draw on textured automap
|
||||
SECMF_OVERLAPPING = 512, // floor and ceiling overlap and require special renderer action.
|
||||
SECMF_NOSKYWALLS = 1024, // Do not draw "sky walls"
|
||||
SECMF_LIFT = 2048, // For MBF monster AI
|
||||
SECMF_HURTMONSTERS = 4096, // Monsters in this sector are hurt like players.
|
||||
SECMF_HARMINAIR = 8192, // Actors in this sector are also hurt mid-air.
|
||||
}
|
||||
native uint16 MoreFlags;
|
||||
|
||||
|
|
@ -452,6 +457,9 @@ struct Sector native play
|
|||
SECF_ENDLEVEL = 512, // ends level when health goes below 10
|
||||
SECF_HAZARD = 1024, // Change to Strife's delayed damage handling.
|
||||
SECF_NOATTACK = 2048, // monsters cannot start attacks in this sector.
|
||||
SECF_EXIT1 = 4096,
|
||||
SECF_EXIT2 = 8192,
|
||||
SECF_KILLMONSTERS = 16384,// Monsters in this sector are instantly killed.
|
||||
|
||||
SECF_WASSECRET = 1 << 30, // a secret that was discovered
|
||||
SECF_SECRET = 1 << 31, // a secret sector
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ class InterBackground native ui version("2.5")
|
|||
native virtual bool LoadBackground(bool isenterpic);
|
||||
native virtual void updateAnimatedBack();
|
||||
native virtual void drawBackground(int CurState, bool drawsplat, bool snl_pointeron);
|
||||
native virtual bool IsUsingMusic();
|
||||
}
|
||||
|
||||
// This is obsolete. Hopefully this was never used...
|
||||
|
|
@ -825,7 +826,8 @@ class StatusScreen : ScreenJob abstract version("2.5")
|
|||
|
||||
virtual void StartMusic()
|
||||
{
|
||||
Level.SetInterMusic(wbs.next);
|
||||
if (!bg.IsUsingMusic())
|
||||
Level.SetInterMusic(wbs.next);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue