diff --git a/docs/licenses/README.TXT b/docs/licenses/README.TXT index f60796436..cef723395 100644 --- a/docs/licenses/README.TXT +++ b/docs/licenses/README.TXT @@ -1,11 +1,14 @@ The original Doom source code was released by id Software under the Doom Source Code License. See doomlic.txt. -Parts of the renderer use code from the BUILD engine by Ken Silverman. -See buildlic.txt. +Parts of the voxel code in the software renderer use code from the +BUILD engine by Ken Silverman. See buildlic.txt. The majority of original code uses a BSD-like lincese. See bsd.txt. +The OpenGL renderer is released under the LGPL v3, except some bits +of code that were inherited fro ZDoomGL. + This software is based in part on the work of the Independent JPEG Group. This software uses the 'zlib' general purpose compression library by diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4986bb872..190f953a0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1200,10 +1200,8 @@ set (PCH_SOURCES g_inventory/a_ammo.cpp g_inventory/a_armor.cpp g_inventory/a_artifacts.cpp - g_inventory/a_health.cpp g_inventory/a_keys.cpp g_inventory/a_pickups.cpp - g_inventory/a_puzzleitems.cpp g_inventory/a_weaponpiece.cpp g_inventory/a_weapons.cpp g_strife/strife_sbar.cpp @@ -1213,9 +1211,6 @@ set (PCH_SOURCES g_shared/a_lightning.cpp g_shared/a_morph.cpp g_shared/a_quake.cpp - g_shared/a_skies.cpp - g_shared/a_soundenvironment.cpp - g_shared/a_soundsequence.cpp g_shared/a_specialspot.cpp g_shared/hudmessages.cpp g_shared/sbarinfo.cpp diff --git a/src/b_think.cpp b/src/b_think.cpp index e41433fa3..1501a03ac 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -22,7 +22,6 @@ #include "d_player.h" #include "vectors.h" #include "a_ammo.h" -#include "a_health.h" static FRandom pr_botmove ("BotMove"); @@ -360,7 +359,7 @@ void DBot::WhatToGet (AActor *item) } else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere) return; - else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina) + else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina) return; if ((dest == NULL || diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 41b89f7c4..7b43de020 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -76,7 +76,6 @@ #include "vmbuilder.h" #include "a_armor.h" #include "a_ammo.h" -#include "a_health.h" // [SO] Just the way Randy said to do it :) // [RH] Made this CVAR_SERVERINFO @@ -1971,21 +1970,21 @@ static int PatchMisc (int dummy) barmor->MaxSaveAmount = deh.MaxArmor; } - AHealth *health; - health = static_cast (GetDefaultByName ("HealthBonus")); + AInventory *health; + health = static_cast (GetDefaultByName ("HealthBonus")); if (health!=NULL) { health->MaxAmount = 2 * deh.MaxHealth; } - health = static_cast (GetDefaultByName ("Soulsphere")); + health = static_cast (GetDefaultByName ("Soulsphere")); if (health!=NULL) { health->Amount = deh.SoulsphereHealth; health->MaxAmount = deh.MaxSoulsphere; } - health = static_cast (GetDefaultByName ("MegasphereHealth")); + health = static_cast (GetDefaultByName ("MegasphereHealth")); if (health!=NULL) { health->Amount = health->MaxAmount = deh.MegasphereHealth; diff --git a/src/d_net.cpp b/src/d_net.cpp index 0ebb7de38..c47ae6bd1 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -2248,11 +2248,11 @@ void Net_DoCommand (int type, BYTE **stream, int player) if (gamestate == GS_LEVEL && !paused) { AInventory *item = players[player].mo->Inventory; - + auto pitype = PClass::FindActor(NAME_PuzzleItem); while (item != NULL) { AInventory *next = item->Inventory; - if (item->ItemFlags & IF_INVBAR && !(item->IsKindOf(RUNTIME_CLASS(APuzzleItem)))) + if (item->ItemFlags & IF_INVBAR && !(item->IsKindOf(pitype))) { players[player].mo->UseInventory (item); } diff --git a/src/dobject.cpp b/src/dobject.cpp index 30c3c1710..aa3736147 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -480,11 +480,11 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld, bool s changed += players[i].FixPointers (old, notOld); } - for (auto &s : sectorPortals) + for (auto &s : level.sectorPortals) { if (s.mSkybox == old) { - s.mSkybox = static_cast(notOld); + s.mSkybox = static_cast(notOld); changed++; } } @@ -566,3 +566,16 @@ DEFINE_ACTION_FUNCTION(DObject, GetClassName) PARAM_SELF_PROLOGUE(DObject); ACTION_RETURN_INT(self->GetClass()->TypeName); } + + +void *DObject::ScriptVar(FName field, PType *type) +{ + auto sym = dyn_cast(GetClass()->Symbols.FindSymbol(field, true)); + if (sym && sym->Type == type) + { + return (((char*)this) + sym->Offset); + } + // This is only for internal use so I_Error is fine. + I_Error("Variable %s not found in %s\n", field.GetChars(), GetClass()->TypeName.GetChars()); + return nullptr; +} diff --git a/src/dobject.h b/src/dobject.h index 0f99361ef..b37380342 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -39,7 +39,7 @@ #include "i_system.h" class PClass; - +class PType; class FSerializer; class DObject; @@ -94,8 +94,6 @@ enum CLASSREG_PClass, CLASSREG_PClassActor, CLASSREG_PClassInventory, - CLASSREG_PClassHealth, - CLASSREG_PClassPuzzleItem, CLASSREG_PClassWeapon, CLASSREG_PClassPlayerPawn, CLASSREG_PClassType, @@ -453,6 +451,8 @@ public: DObject *GCNext; // Next object in this collection list uint32 ObjectFlags; // Flags for this object + void *ScriptVar(FName field, PType *type); + public: DObject (); DObject (PClass *inClass); @@ -476,6 +476,10 @@ public: virtual void OnDestroy() {} void Destroy(); + // Add other types as needed. + int &IntVar(FName field); + double &FloatVar(FName field); + // If you need to replace one object with another and want to // change any pointers from the old object to the new object, // use this method. diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 625f80678..230dbeac7 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -329,7 +329,7 @@ static void MarkRoot() DThinker::MarkRoots(); FCanvasTextureInfo::Mark(); Mark(DACSThinker::ActiveThinker); - for (auto &s : sectorPortals) + for (auto &s : level.sectorPortals) { Mark(s.mSkybox); } diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index bde74f649..6e42e2919 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -51,7 +51,6 @@ #include "doomerrors.h" #include "fragglescript/t_fs.h" #include "a_keys.h" -#include "a_health.h" // MACROS ------------------------------------------------------------------ @@ -2609,6 +2608,27 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue else BitValue = -1; } +/* PProperty *****************************************************************/ + +IMPLEMENT_CLASS(PProperty, false, false) + +//========================================================================== +// +// PField - Default Constructor +// +//========================================================================== + +PProperty::PProperty() + : PSymbol(NAME_None) +{ +} + +PProperty::PProperty(FName name, TArray &fields) + : PSymbol(name) +{ + Variables = std::move(fields); +} + /* PPrototype *************************************************************/ IMPLEMENT_CLASS(PPrototype, false, false) @@ -3094,8 +3114,6 @@ PClass *ClassReg::RegisterClass() &PClass::RegistrationInfo, &PClassActor::RegistrationInfo, &PClassInventory::RegistrationInfo, - &PClassHealth::RegistrationInfo, - &PClassPuzzleItem::RegistrationInfo, &PClassWeapon::RegistrationInfo, &PClassPlayerPawn::RegistrationInfo, &PClassType::RegistrationInfo, @@ -3234,7 +3252,7 @@ DObject *PClass::CreateNew() const ConstructNative (mem); ((DObject *)mem)->SetClass (const_cast(this)); - InitializeSpecials(mem); + InitializeSpecials(mem, Defaults); return (DObject *)mem; } @@ -3246,7 +3264,7 @@ DObject *PClass::CreateNew() const // //========================================================================== -void PClass::InitializeSpecials(void *addr) const +void PClass::InitializeSpecials(void *addr, void *defaults) const { // Once we reach a native class, we can stop going up the family tree, // since native classes handle initialization natively. @@ -3255,10 +3273,10 @@ void PClass::InitializeSpecials(void *addr) const return; } assert(ParentClass != NULL); - ParentClass->InitializeSpecials(addr); + ParentClass->InitializeSpecials(addr, defaults); for (auto tao : SpecialInits) { - tao.first->InitializeValue((BYTE*)addr + tao.second, Defaults == nullptr? nullptr : Defaults + tao.second); + tao.first->InitializeValue((char*)addr + tao.second, defaults == nullptr? nullptr : ((char*)defaults) + tao.second); } } @@ -3332,7 +3350,7 @@ void PClass::InitializeDefaults() { // Copy parent values from the parent defaults. assert(ParentClass != NULL); - ParentClass->InitializeSpecials(Defaults); + ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults); for (const PField *field : Fields) { @@ -3923,6 +3941,13 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) return sym; } +void PSymbolTable::RemoveSymbol(PSymbol *sym) +{ + auto mysym = Symbols.CheckKey(sym->SymbolName); + if (mysym == nullptr || *mysym != sym) return; + Symbols.Remove(sym->SymbolName); +} + PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) { // If a symbol with a matching name exists, take its place and return it. diff --git a/src/dobjtype.h b/src/dobjtype.h index 6f33483fc..156818147 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -29,11 +29,12 @@ enum VARF_In = (1<<10), VARF_Out = (1<<11), VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures) - VARF_Static = (1<<13), // static class data (by necessity read only.) + VARF_Static = (1<<13), VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code. VARF_Override = (1<<15), // overrides a virtual function from the parent class. VARF_Ref = (1<<16), // argument is passed by reference. - VARF_Transient = (1<<17) // don't auto serialize field. + VARF_Transient = (1<<17), // don't auto serialize field. + VARF_Meta = (1<<18), // static class data (by necessity read only.) }; // Symbol information ------------------------------------------------------- @@ -137,6 +138,8 @@ struct PSymbolTable // to be in the table with this name, if any. PSymbol *ReplaceSymbol(PSymbol *sym); + void RemoveSymbol(PSymbol *sym); + // Frees all symbols from this table. void ReleaseSymbols(); @@ -621,6 +624,21 @@ protected: PField(); }; +// Struct/class fields ------------------------------------------------------ + +// A PField describes a symbol that takes up physical space in the struct. +class PProperty : public PSymbol +{ + DECLARE_CLASS(PProperty, PSymbol); +public: + PProperty(FName name, TArray &variables); + + TArray Variables; + +protected: + PProperty(); +}; + // Compound types ----------------------------------------------------------- class PEnum : public PNamedType @@ -807,7 +825,7 @@ protected: enum { MetaClassNum = CLASSREG_PClassClass }; TArray SpecialInits; void Derive(PClass *newclass, FName name); - void InitializeSpecials(void *addr) const; + void InitializeSpecials(void *addr, void *defaults) const; void SetSuper(); public: typedef PClassClass MetaClass; @@ -1041,4 +1059,15 @@ enum ETypeVal : BYTE VAL_Class, }; +inline int &DObject::IntVar(FName field) +{ + return *(int*)ScriptVar(field, TypeSInt32); +} + +inline double &DObject::FloatVar(FName field) +{ + return *(double*)ScriptVar(field, TypeFloat64); +} + + #endif diff --git a/src/doomtype.h b/src/doomtype.h index 264713d1b..248aee33b 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -186,6 +186,13 @@ private: int texnum; }; +// This is for the script interface which needs to do casts from int to texture. +class FSetTextureID : public FTextureID +{ +public: + FSetTextureID(int v) : FTextureID(v) {} +}; + // Screenshot buffer image data types diff --git a/src/dsectoreffect.cpp b/src/dsectoreffect.cpp index 22acf74bc..466675dbc 100644 --- a/src/dsectoreffect.cpp +++ b/src/dsectoreffect.cpp @@ -25,6 +25,7 @@ #include "dsectoreffect.h" #include "gi.h" #include "p_local.h" +#include "g_levellocals.h" #include "p_3dmidtex.h" #include "r_data/r_interpolate.h" #include "statnums.h" diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index ce46daeb3..7c5adb6bc 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -2623,7 +2623,7 @@ void FParser::SF_MaxPlayerAmmo() } else if(t_argc >= 3) { - AAmmo * iammo = (AAmmo*)players[playernum].mo->FindInventory(ammotype); + auto iammo = players[playernum].mo->FindInventory(ammotype); amount = intvalue(t_argv[2]); if(amount < 0) amount = 0; if (!iammo) @@ -2637,14 +2637,14 @@ void FParser::SF_MaxPlayerAmmo() for (AInventory *item = players[playernum].mo->Inventory; item != NULL; item = item->Inventory) { - if (item->IsKindOf(RUNTIME_CLASS(ABackpackItem))) + if (item->IsKindOf(PClass::FindClass(NAME_BackpackItem))) { if (t_argc>=4) amount = intvalue(t_argv[3]); else amount*=2; break; } } - iammo->BackpackMaxAmount=amount; + ((AAmmo*)iammo)->BackpackMaxAmount=amount; } t_return.type = svt_int; diff --git a/src/g_inventory/a_ammo.cpp b/src/g_inventory/a_ammo.cpp index 6ef2c64d4..b1765e1e4 100644 --- a/src/g_inventory/a_ammo.cpp +++ b/src/g_inventory/a_ammo.cpp @@ -84,282 +84,8 @@ PClassActor *AAmmo::GetParentAmmo () const return static_cast(type); } -//=========================================================================== -// -// AAmmo :: HandlePickup -// -//=========================================================================== -EXTERN_CVAR(Bool, sv_unlimited_pickup) - -bool AAmmo::HandlePickup (AInventory *item) +DEFINE_ACTION_FUNCTION(AAmmo, GetParentAmmo) { - if (GetClass() == item->GetClass() || - (item->IsKindOf (RUNTIME_CLASS(AAmmo)) && static_cast(item)->GetParentAmmo() == GetClass())) - { - if (Amount < MaxAmount || sv_unlimited_pickup) - { - int receiving = item->Amount; - - if (!(item->ItemFlags & IF_IGNORESKILL)) - { // extra ammo in baby mode and nightmare mode - receiving = int(receiving * G_SkillProperty(SKILLP_AmmoFactor)); - } - int oldamount = Amount; - - if (Amount > 0 && Amount + receiving < 0) - { - Amount = 0x7fffffff; - } - else - { - Amount += receiving; - } - if (Amount > MaxAmount && !sv_unlimited_pickup) - { - Amount = MaxAmount; - } - item->ItemFlags |= IF_PICKUPGOOD; - - // If the player previously had this ammo but ran out, possibly switch - // to a weapon that uses it, but only if the player doesn't already - // have a weapon pending. - - assert (Owner != NULL); - - if (oldamount == 0 && Owner != NULL && Owner->player != NULL) - { - barrier_cast(Owner)->CheckWeaponSwitch(GetClass()); - } - } - return true; - } - return false; + PARAM_SELF_PROLOGUE(AAmmo); + ACTION_RETURN_OBJECT(self->GetParentAmmo()); } - -//=========================================================================== -// -// AAmmo :: CreateCopy -// -//=========================================================================== - -AInventory *AAmmo::CreateCopy (AActor *other) -{ - AInventory *copy; - int amount = Amount; - - // extra ammo in baby mode and nightmare mode - if (!(ItemFlags&IF_IGNORESKILL)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - - if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo) && GetClass() != RUNTIME_CLASS(AAmmo)) - { - PClassActor *type = GetParentAmmo(); - if (!GoAway ()) - { - Destroy (); - } - - copy = static_cast(Spawn (type)); - copy->Amount = amount; - copy->BecomeItem (); - } - else - { - copy = Super::CreateCopy (other); - copy->Amount = amount; - } - if (copy->Amount > copy->MaxAmount) - { // Don't pick up more ammo than you're supposed to be able to carry. - copy->Amount = copy->MaxAmount; - } - return copy; -} - -//=========================================================================== -// -// AAmmo :: CreateTossable -// -//=========================================================================== - -AInventory *AAmmo::CreateTossable() -{ - AInventory *copy = Super::CreateTossable(); - if (copy != NULL) - { // Do not increase ammo by dropping it and picking it back up at - // certain skill levels. - copy->ItemFlags |= IF_IGNORESKILL; - } - return copy; -} - - -// Backpack ----------------------------------------------------------------- - -IMPLEMENT_CLASS(ABackpackItem, false, false) - -DEFINE_FIELD(ABackpackItem, bDepleted) - -//=========================================================================== -// -// ABackpackItem :: Serialize -// -//=========================================================================== - -void ABackpackItem::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - auto def = (ABackpackItem*)GetDefault(); - arc("bdepleted", bDepleted, def->bDepleted); -} - -//=========================================================================== -// -// ABackpackItem :: CreateCopy -// -// A backpack is being added to a player who doesn't yet have one. Give them -// every kind of ammo, and increase their max amounts. -// -//=========================================================================== - -AInventory *ABackpackItem::CreateCopy (AActor *other) -{ - // Find every unique type of ammo. Give it to the player if - // he doesn't have it already, and double its maximum capacity. - for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) - { - PClass *type = PClassActor::AllActorClasses[i]; - - if (type->ParentClass == RUNTIME_CLASS(AAmmo)) - { - PClassActor *atype = static_cast(type); - AAmmo *ammo = static_cast(other->FindInventory(atype)); - int amount = static_cast(GetDefaultByType(type))->BackpackAmount; - // extra ammo in baby mode and nightmare mode - if (!(ItemFlags&IF_IGNORESKILL)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - if (amount < 0) amount = 0; - if (ammo == NULL) - { // The player did not have the ammo. Add it. - ammo = static_cast(Spawn(atype)); - ammo->Amount = bDepleted ? 0 : amount; - if (ammo->BackpackMaxAmount > ammo->MaxAmount) - { - ammo->MaxAmount = ammo->BackpackMaxAmount; - } - if (ammo->Amount > ammo->MaxAmount) - { - ammo->Amount = ammo->MaxAmount; - } - ammo->AttachToOwner (other); - } - else - { // The player had the ammo. Give some more. - if (ammo->MaxAmount < ammo->BackpackMaxAmount) - { - ammo->MaxAmount = ammo->BackpackMaxAmount; - } - if (!bDepleted && ammo->Amount < ammo->MaxAmount) - { - ammo->Amount += amount; - if (ammo->Amount > ammo->MaxAmount) - { - ammo->Amount = ammo->MaxAmount; - } - } - } - } - } - return Super::CreateCopy (other); -} - -//=========================================================================== -// -// ABackpackItem :: HandlePickup -// -// When the player picks up another backpack, just give them more ammo. -// -//=========================================================================== - -bool ABackpackItem::HandlePickup (AInventory *item) -{ - // Since you already have a backpack, that means you already have every - // kind of ammo in your inventory, so we don't need to look at the - // entire PClass list to discover what kinds of ammo exist, and we don't - // have to alter the MaxAmount either. - if (item->IsKindOf (RUNTIME_CLASS(ABackpackItem))) - { - for (AInventory *probe = Owner->Inventory; probe != NULL; probe = probe->Inventory) - { - if (probe->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo)) - { - if (probe->Amount < probe->MaxAmount || sv_unlimited_pickup) - { - int amount = static_cast(probe->GetDefault())->BackpackAmount; - // extra ammo in baby mode and nightmare mode - if (!(item->ItemFlags&IF_IGNORESKILL)) - { - amount = int(amount * G_SkillProperty(SKILLP_AmmoFactor)); - } - probe->Amount += amount; - if (probe->Amount > probe->MaxAmount && !sv_unlimited_pickup) - { - probe->Amount = probe->MaxAmount; - } - } - } - } - // The pickup always succeeds, even if you didn't get anything - item->ItemFlags |= IF_PICKUPGOOD; - return true; - } - return false; -} - -//=========================================================================== -// -// ABackpackItem :: CreateTossable -// -// The tossed backpack must not give out any more ammo, otherwise a player -// could cheat by dropping their backpack and picking it up for more ammo. -// -//=========================================================================== - -AInventory *ABackpackItem::CreateTossable () -{ - ABackpackItem *pack = static_cast(Super::CreateTossable()); - if (pack != NULL) - { - pack->bDepleted = true; - } - return pack; -} - -//=========================================================================== -// -// ABackpackItem :: DetachFromOwner -// -//=========================================================================== - -void ABackpackItem::DetachFromOwner () -{ - // When removing a backpack, drop the player's ammo maximums to normal - AInventory *item; - - for (item = Owner->Inventory; item != NULL; item = item->Inventory) - { - if (item->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo) && - item->MaxAmount == static_cast(item)->BackpackMaxAmount) - { - item->MaxAmount = static_cast(item->GetDefault())->MaxAmount; - if (item->Amount > item->MaxAmount) - { - item->Amount = item->MaxAmount; - } - } - } -} - diff --git a/src/g_inventory/a_ammo.h b/src/g_inventory/a_ammo.h index fbe96e4bc..445f44a34 100644 --- a/src/g_inventory/a_ammo.h +++ b/src/g_inventory/a_ammo.h @@ -7,29 +7,8 @@ class AAmmo : public AInventory public: virtual void Serialize(FSerializer &arc) override; - virtual AInventory *CreateCopy (AActor *other) override; - virtual bool HandlePickup (AInventory *item) override; - virtual AInventory *CreateTossable () override; PClassActor *GetParentAmmo () const; int BackpackAmount, BackpackMaxAmount, DropAmount; }; - -// A backpack gives you one clip of each ammo and doubles your -// normal maximum ammo amounts. -class ABackpackItem : public AInventory -{ - DECLARE_CLASS (ABackpackItem, AInventory) -public: - - virtual void Serialize(FSerializer &arc) override; - virtual bool HandlePickup (AInventory *item) override; - virtual AInventory *CreateCopy (AActor *other) override; - virtual AInventory *CreateTossable () override; - virtual void DetachFromOwner () override; - - bool bDepleted; -}; - - diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index afe676ccf..80c423b45 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -904,334 +904,6 @@ void APowerMask::DoEffect () } } -// Light-Amp Powerup --------------------------------------------------------- - -IMPLEMENT_CLASS(APowerLightAmp, false, false) - -//=========================================================================== -// -// APowerLightAmp :: DoEffect -// -//=========================================================================== - -void APowerLightAmp::DoEffect () -{ - Super::DoEffect (); - - if (Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS) - { - if (!isBlinking()) - { - Owner->player->fixedlightlevel = 1; - } - else - { - Owner->player->fixedlightlevel = -1; - } - } -} - -//=========================================================================== -// -// APowerLightAmp :: EndEffect -// -//=========================================================================== - -void APowerLightAmp::EndEffect () -{ - Super::EndEffect(); - if (Owner != NULL && Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS) - { - Owner->player->fixedlightlevel = -1; - } -} - -// Torch Powerup ------------------------------------------------------------- - -IMPLEMENT_CLASS(APowerTorch, false, false) - -//=========================================================================== -// -// APowerTorch :: Serialize -// -//=========================================================================== - -void APowerTorch::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("newtorch", NewTorch) - ("newtorchdelta", NewTorchDelta); -} - -//=========================================================================== -// -// APowerTorch :: DoEffect -// -//=========================================================================== - -void APowerTorch::DoEffect () -{ - if (Owner == NULL || Owner->player == NULL) - { - return; - } - - if (EffectTics <= BLINKTHRESHOLD || Owner->player->fixedcolormap >= NUMCOLORMAPS) - { - Super::DoEffect (); - } - else - { - APowerup::DoEffect (); - - if (!(level.time & 16) && Owner->player != NULL) - { - if (NewTorch != 0) - { - if (Owner->player->fixedlightlevel + NewTorchDelta > 7 - || Owner->player->fixedlightlevel + NewTorchDelta < 0 - || NewTorch == Owner->player->fixedlightlevel) - { - NewTorch = 0; - } - else - { - Owner->player->fixedlightlevel += NewTorchDelta; - } - } - else - { - NewTorch = (pr_torch() & 7) + 1; - NewTorchDelta = (NewTorch == Owner->player->fixedlightlevel) ? - 0 : ((NewTorch > Owner->player->fixedlightlevel) ? 1 : -1); - } - } - } -} - -// Flight (aka Wings of Wrath) powerup --------------------------------------- - -IMPLEMENT_CLASS(APowerFlight, false, false) - -//=========================================================================== -// -// APowerFlight :: Serialize -// -//=========================================================================== - -void APowerFlight::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("hitcenterframe", HitCenterFrame); -} - -//=========================================================================== -// -// APowerFlight :: InitEffect -// -//=========================================================================== - -void APowerFlight::InitEffect () -{ - Super::InitEffect(); - Owner->flags2 |= MF2_FLY; - Owner->flags |= MF_NOGRAVITY; - if (Owner->Z() <= Owner->floorz) - { - Owner->Vel.Z = 4;; // thrust the player in the air a bit - } - if (Owner->Vel.Z <= -35) - { // stop falling scream - S_StopSound (Owner, CHAN_VOICE); - } -} - -//=========================================================================== -// -// APowerFlight :: DoEffect -// -//=========================================================================== - -void APowerFlight::Tick () -{ - // The Wings of Wrath only expire in multiplayer and non-hub games - if (!multiplayer && (level.flags2 & LEVEL2_INFINITE_FLIGHT)) - { - assert(EffectTics < INT_MAX); // I can't see a game lasting nearly two years, but... - EffectTics++; - } - - Super::Tick (); - -// Owner->flags |= MF_NOGRAVITY; -// Owner->flags2 |= MF2_FLY; -} - -//=========================================================================== -// -// APowerFlight :: EndEffect -// -//=========================================================================== - -void APowerFlight::EndEffect () -{ - Super::EndEffect(); - if (Owner == NULL || Owner->player == NULL) - { - return; - } - - if (!(Owner->flags7 & MF7_FLYCHEAT)) - { - if (Owner->Z() != Owner->floorz) - { - Owner->player->centering = true; - } - Owner->flags2 &= ~MF2_FLY; - Owner->flags &= ~MF_NOGRAVITY; - } -// BorderTopRefresh = screen->GetPageCount (); //make sure the sprite's cleared out -} - -//=========================================================================== -// -// APowerFlight :: DrawPowerup -// -//=========================================================================== - -bool APowerFlight::DrawPowerup (int x, int y) -{ - // If this item got a valid icon use that instead of the default spinning wings. - if (Icon.isValid()) - { - return Super::DrawPowerup(x, y); - } - - if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16)) - { - FTextureID picnum = TexMan.CheckForTexture ("SPFLY0", FTexture::TEX_MiscPatch); - int frame = (level.time/3) & 15; - - if (!picnum.isValid()) - { - return false; - } - if (Owner->flags & MF_NOGRAVITY) - { - if (HitCenterFrame && (frame != 15 && frame != 0)) - { - screen->DrawTexture (TexMan[picnum+15], x, y, - DTA_HUDRules, HUD_Normal, TAG_DONE); - } - else - { - screen->DrawTexture (TexMan[picnum+frame], x, y, - DTA_HUDRules, HUD_Normal, TAG_DONE); - HitCenterFrame = false; - } - } - else - { - if (!HitCenterFrame && (frame != 15 && frame != 0)) - { - screen->DrawTexture (TexMan[picnum+frame], x, y, - DTA_HUDRules, HUD_Normal, TAG_DONE); - HitCenterFrame = false; - } - else - { - screen->DrawTexture (TexMan[picnum+15], x, y, - DTA_HUDRules, HUD_Normal, TAG_DONE); - HitCenterFrame = true; - } - } - } - return true; -} - -// Weapon Level 2 (aka Tome of Power) Powerup -------------------------------- - -IMPLEMENT_CLASS(APowerWeaponLevel2, false, false) - -//=========================================================================== -// -// APowerWeaponLevel2 :: InitEffect -// -//=========================================================================== - -void APowerWeaponLevel2::InitEffect () -{ - AWeapon *weapon, *sister; - - Super::InitEffect(); - - if (Owner->player == nullptr) - return; - - weapon = Owner->player->ReadyWeapon; - - if (weapon == nullptr) - return; - - sister = weapon->SisterWeapon; - - if (sister == nullptr) - return; - - if (!(sister->WeaponFlags & WIF_POWERED_UP)) - return; - - assert (sister->SisterWeapon == weapon); - - - if (weapon->GetReadyState() != sister->GetReadyState()) - { - Owner->player->ReadyWeapon = sister; - P_SetPsprite(Owner->player, PSP_WEAPON, sister->GetReadyState()); - } - else - { - DPSprite *psp = Owner->player->FindPSprite(PSP_WEAPON); - if (psp != nullptr && psp->GetCaller() == Owner->player->ReadyWeapon) - { - // If the weapon changes but the state does not, we have to manually change the PSprite's caller here. - psp->SetCaller(sister); - Owner->player->ReadyWeapon = sister; - } - else - { - // Something went wrong. Initiate a regular weapon change. - Owner->player->PendingWeapon = sister; - } - } -} - -//=========================================================================== -// -// APowerWeaponLevel2 :: EndEffect -// -//=========================================================================== - -void APowerWeaponLevel2::EndEffect () -{ - player_t *player = Owner != NULL ? Owner->player : NULL; - - Super::EndEffect(); - if (player != NULL) - { - if (player->ReadyWeapon != NULL && - player->ReadyWeapon->WeaponFlags & WIF_POWERED_UP) - { - player->ReadyWeapon->CallEndPowerup (); - } - if (player->PendingWeapon != NULL && player->PendingWeapon != WP_NOCHANGE && - player->PendingWeapon->WeaponFlags & WIF_POWERED_UP && - player->PendingWeapon->SisterWeapon != NULL) - { - player->PendingWeapon = player->PendingWeapon->SisterWeapon; - } - } -} // Speed Powerup ------------------------------------------------------------- @@ -1251,178 +923,6 @@ void APowerSpeed::Serialize(FSerializer &arc) arc("speedflags", SpeedFlags); } -//=========================================================================== -// -// APowerSpeed :: DoEffect -// -//=========================================================================== - -void APowerSpeed::DoEffect () -{ - Super::DoEffect (); - - if (Owner == NULL || Owner->player == NULL) - return; - - if (Owner->player->cheats & CF_PREDICTING) - return; - - if (SpeedFlags & PSF_NOTRAIL) - return; - - if (level.time & 1) - return; - - // Check if another speed item is present to avoid multiple drawing of the speed trail. - // Only the last PowerSpeed without PSF_NOTRAIL set will actually draw the trail. - for (AInventory *item = Inventory; item != NULL; item = item->Inventory) - { - if (item->IsKindOf(RUNTIME_CLASS(APowerSpeed)) && - !(static_cast(item)->SpeedFlags & PSF_NOTRAIL)) - { - return; - } - } - - if (Owner->Vel.LengthSquared() <= 12*12) - return; - - AActor *speedMo = Spawn("PlayerSpeedTrail", Owner->Pos(), NO_REPLACE); - if (speedMo) - { - speedMo->Angles.Yaw = Owner->Angles.Yaw; - speedMo->Translation = Owner->Translation; - speedMo->target = Owner; - speedMo->sprite = Owner->sprite; - speedMo->frame = Owner->frame; - speedMo->Floorclip = Owner->Floorclip; - - // [BC] Also get the scale from the owner. - speedMo->Scale = Owner->Scale; - - if (Owner == players[consoleplayer].camera && - !(Owner->player->cheats & CF_CHASECAM)) - { - speedMo->renderflags |= RF_INVISIBLE; - } - } -} - -// Targeter powerup --------------------------------------------------------- - -IMPLEMENT_CLASS(APowerTargeter, false, false) - -void APowerTargeter::Travelled () -{ - CallInitEffect (); -} - -void APowerTargeter::InitEffect () -{ - // Why is this called when the inventory isn't even attached yet - // in APowerup::CreateCopy? - if (!Owner->FindInventory(GetClass(), true)) - return; - - player_t *player; - - Super::InitEffect(); - - if ((player = Owner->player) == nullptr) - return; - - FState *state = FindState("Targeter"); - - if (state != nullptr) - { - P_SetPsprite(player, PSP_TARGETCENTER, state + 0); - P_SetPsprite(player, PSP_TARGETLEFT, state + 1); - P_SetPsprite(player, PSP_TARGETRIGHT, state + 2); - } - - player->GetPSprite(PSP_TARGETCENTER)->x = (160-3); - player->GetPSprite(PSP_TARGETCENTER)->y = - player->GetPSprite(PSP_TARGETLEFT)->y = - player->GetPSprite(PSP_TARGETRIGHT)->y = (100-3); - PositionAccuracy (); -} - -void APowerTargeter::AttachToOwner(AActor *other) -{ - Super::AttachToOwner(other); - - // Let's actually properly call this for the targeters. - CallInitEffect(); -} - -bool APowerTargeter::HandlePickup(AInventory *item) -{ - if (Super::HandlePickup(item)) - { - CallInitEffect(); // reset the HUD sprites - return true; - } - return false; -} - -void APowerTargeter::DoEffect () -{ - Super::DoEffect (); - - if (Owner != nullptr && Owner->player != nullptr) - { - player_t *player = Owner->player; - - PositionAccuracy (); - if (EffectTics < 5*TICRATE) - { - FState *state = FindState("Targeter"); - - if (state != nullptr) - { - if (EffectTics & 32) - { - P_SetPsprite(player, PSP_TARGETRIGHT, nullptr); - P_SetPsprite(player, PSP_TARGETLEFT, state + 1); - } - else if (EffectTics & 16) - { - P_SetPsprite(player, PSP_TARGETRIGHT, state + 2); - P_SetPsprite(player, PSP_TARGETLEFT, nullptr); - } - } - } - } -} - -void APowerTargeter::EndEffect () -{ - Super::EndEffect(); - if (Owner != nullptr && Owner->player != nullptr) - { - // Calling GetPSprite here could crash if we're creating a new game. - // This is because P_SetupLevel nulls the player's mo before destroying - // every DThinker which in turn ends up calling this. - // However P_SetupLevel is only called after G_NewInit which calls - // every player's dtor which destroys all their psprites. - DPSprite *pspr; - if ((pspr = Owner->player->FindPSprite(PSP_TARGETCENTER)) != nullptr) pspr->SetState(nullptr); - if ((pspr = Owner->player->FindPSprite(PSP_TARGETLEFT)) != nullptr) pspr->SetState(nullptr); - if ((pspr = Owner->player->FindPSprite(PSP_TARGETRIGHT)) != nullptr) pspr->SetState(nullptr); - } -} - -void APowerTargeter::PositionAccuracy () -{ - player_t *player = Owner->player; - - if (player != nullptr) - { - player->GetPSprite(PSP_TARGETLEFT)->x = (160-3) - ((100 - player->mo->accuracy)); - player->GetPSprite(PSP_TARGETRIGHT)->x = (160-3)+ ((100 - player->mo->accuracy)); - } -} - // Morph powerup ------------------------------------------------------ IMPLEMENT_CLASS(APowerMorph, false, true) diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index 6cd10f637..d72ed42c3 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -105,55 +105,10 @@ public: virtual void DoEffect () override; }; -class APowerLightAmp : public APowerup -{ - DECLARE_CLASS (APowerLightAmp, APowerup) -protected: - virtual void DoEffect () override; - virtual void EndEffect () override; -}; - -class APowerTorch : public APowerLightAmp -{ - DECLARE_CLASS (APowerTorch, APowerLightAmp) -public: - - virtual void Serialize(FSerializer &arc) override; -protected: - virtual void DoEffect () override; - int NewTorch, NewTorchDelta; -}; - -class APowerFlight : public APowerup -{ - DECLARE_CLASS (APowerFlight, APowerup) -public: - virtual bool DrawPowerup (int x, int y) override; - virtual void Serialize(FSerializer &arc) override; - -protected: - virtual void InitEffect () override; - virtual void Tick () override; - virtual void EndEffect () override; - -private: - bool HitCenterFrame; -}; - -class APowerWeaponLevel2 : public APowerup -{ - DECLARE_CLASS (APowerWeaponLevel2, APowerup) -protected: - virtual void InitEffect () override; - virtual void EndEffect () override; -}; - class APowerSpeed : public APowerup { DECLARE_CLASS (APowerSpeed, APowerup) protected: - virtual void DoEffect () override; - virtual void Serialize(FSerializer &arc) override; public: int SpeedFlags; @@ -161,19 +116,6 @@ public: #define PSF_NOTRAIL 1 -class APowerTargeter : public APowerup -{ - DECLARE_CLASS (APowerTargeter, APowerup) -protected: - virtual void InitEffect () override; - virtual void DoEffect () override; - virtual void EndEffect () override; - void PositionAccuracy (); - virtual void Travelled () override; - virtual void AttachToOwner(AActor *other) override; - virtual bool HandlePickup(AInventory *item) override; -}; - class APowerMorph : public APowerup { DECLARE_CLASS( APowerMorph, APowerup ) diff --git a/src/g_inventory/a_health.cpp b/src/g_inventory/a_health.cpp deleted file mode 100644 index 58cd86e2a..000000000 --- a/src/g_inventory/a_health.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* -** a_health.cpp -** All health items -** -**--------------------------------------------------------------------------- -** Copyright 2000-2016 Randy Heit -** Copyright 2006-2016 Cheistoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "d_player.h" -#include "a_morph.h" -#include "a_health.h" -#include "serializer.h" - -//--------------------------------------------------------------------------- -// -// FUNC P_GiveBody -// -// Returns false if the body isn't needed at all. -// -//--------------------------------------------------------------------------- - -bool P_GiveBody (AActor *actor, int num, int max) -{ - if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD)) - { // Do not heal dead things. - return false; - } - - player_t *player = actor->player; - - num = clamp(num, -65536, 65536); // prevent overflows for bad values - if (player != NULL) - { - // Max is 0 by default, preserving default behavior for P_GiveBody() - // calls while supporting AHealth. - if (max <= 0) - { - max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; - // [MH] First step in predictable generic morph effects - if (player->morphTics) - { - if (player->MorphStyle & MORPH_FULLHEALTH) - { - if (!(player->MorphStyle & MORPH_ADDSTAMINA)) - { - max -= player->mo->stamina; - } - } - else // old health behaviour - { - max = MAXMORPHHEALTH; - if (player->MorphStyle & MORPH_ADDSTAMINA) - { - max += player->mo->stamina; - } - } - } - } - // [RH] For Strife: A negative body sets you up with a percentage - // of your full health. - if (num < 0) - { - num = max * -num / 100; - if (player->health < num) - { - player->health = num; - actor->health = num; - return true; - } - } - else if (num > 0) - { - if (player->health < max) - { - num = int(num * G_SkillProperty(SKILLP_HealthFactor)); - if (num < 1) num = 1; - player->health += num; - if (player->health > max) - { - player->health = max; - } - actor->health = player->health; - return true; - } - } - } - else - { - // Parameter value for max is ignored on monsters, preserving original - // behaviour on AHealth as well as on existing calls to P_GiveBody(). - max = actor->SpawnHealth(); - if (num < 0) - { - num = max * -num / 100; - if (actor->health < num) - { - actor->health = num; - return true; - } - } - else if (actor->health < max) - { - actor->health += num; - if (actor->health > max) - { - actor->health = max; - } - return true; - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(AActor, GiveBody) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_INT(num); - PARAM_INT_DEF(max); - ACTION_RETURN_BOOL(P_GiveBody(self, num, max)); -} - -//=========================================================================== -// -// Classes -// -//=========================================================================== - -IMPLEMENT_CLASS(PClassHealth, false, false) -IMPLEMENT_CLASS(AHealth, false, false) -DEFINE_FIELD(AHealth, PrevHealth) - -//=========================================================================== -// -// PClassHealth Constructor -// -//=========================================================================== - -PClassHealth::PClassHealth() -{ - LowHealth = 0; -} - -//=========================================================================== -// -// PClassHealth :: DeriveData -// -//=========================================================================== - -void PClassHealth::DeriveData(PClass *newclass) -{ - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth))); - Super::DeriveData(newclass); - PClassHealth *newc = static_cast(newclass); - - newc->LowHealth = LowHealth; - newc->LowHealthMessage = LowHealthMessage; -} - - -//=========================================================================== -// -// AHealth :: PickupMessage -// -//=========================================================================== -FString AHealth::PickupMessage () -{ - int threshold = GetClass()->LowHealth; - - if (PrevHealth < threshold) - { - FString message = GetClass()->LowHealthMessage; - - if (message.IsNotEmpty()) - { - return message; - } - } - return Super::PickupMessage(); -} - -//=========================================================================== -// -// AHealth :: TryPickup -// -//=========================================================================== - -bool AHealth::TryPickup (AActor *&other) -{ - PrevHealth = other->player != NULL ? other->player->health : other->health; - - // P_GiveBody adds one new feature, applied only if it is possible to pick up negative health: - // Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount. - if (P_GiveBody(other, Amount, MaxAmount)) - { - GoAwayAndDie(); - return true; - } - return false; -} - -IMPLEMENT_CLASS(AHealthPickup, false, false) - -DEFINE_FIELD(AHealthPickup, autousemode) - -//=========================================================================== -// -// AHealthPickup :: CreateCopy -// -//=========================================================================== - -AInventory *AHealthPickup::CreateCopy (AActor *other) -{ - AInventory *copy = Super::CreateCopy (other); - copy->health = health; - return copy; -} - -//=========================================================================== -// -// AHealthPickup :: CreateTossable -// -//=========================================================================== - -AInventory *AHealthPickup::CreateTossable () -{ - AInventory *copy = Super::CreateTossable (); - if (copy != NULL) - { - copy->health = health; - } - return copy; -} - -//=========================================================================== -// -// AHealthPickup :: HandlePickup -// -//=========================================================================== - -bool AHealthPickup::HandlePickup (AInventory *item) -{ - // HealthPickups that are the same type but have different health amounts - // do not count as the same item. - if (item->health == health) - { - return Super::HandlePickup (item); - } - return false; -} - -//=========================================================================== -// -// AHealthPickup :: Use -// -//=========================================================================== - -bool AHealthPickup::Use (bool pickup) -{ - return P_GiveBody (Owner, health, 0); -} - -//=========================================================================== -// -// AHealthPickup :: Serialize -// -//=========================================================================== - -void AHealthPickup::Serialize(FSerializer &arc) -{ - Super::Serialize(arc); - auto def = (AHealthPickup*)GetDefault(); - arc("autousemode", autousemode, def->autousemode); -} - diff --git a/src/g_inventory/a_health.h b/src/g_inventory/a_health.h deleted file mode 100644 index af282031c..000000000 --- a/src/g_inventory/a_health.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "a_pickups.h" - -// Health is some item that gives the player health when picked up. -class PClassHealth : public PClassInventory -{ - DECLARE_CLASS(PClassHealth, PClassInventory) -protected: -public: - PClassHealth(); - virtual void DeriveData(PClass *newclass); - - FString LowHealthMessage; - int LowHealth; -}; - -class AHealth : public AInventory -{ - DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth) - -public: - int PrevHealth; - virtual bool TryPickup (AActor *&other) override; - virtual FString PickupMessage () override; -}; - -// HealthPickup is some item that gives the player health when used. -class AHealthPickup : public AInventory -{ - DECLARE_CLASS (AHealthPickup, AInventory) -public: - int autousemode; - - - virtual void Serialize(FSerializer &arc) override; - virtual AInventory *CreateCopy (AActor *other) override; - virtual AInventory *CreateTossable () override; - virtual bool HandlePickup (AInventory *item) override; - virtual bool Use (bool pickup) override; -}; - diff --git a/src/g_inventory/a_keys.cpp b/src/g_inventory/a_keys.cpp index a2b5b308a..31237018c 100644 --- a/src/g_inventory/a_keys.cpp +++ b/src/g_inventory/a_keys.cpp @@ -530,35 +530,8 @@ bool P_CheckKeys (AActor *owner, int keynum, bool remote) //========================================================================== IMPLEMENT_CLASS(AKey, false, false) - DEFINE_FIELD(AKey, KeyNumber) -bool AKey::HandlePickup (AInventory *item) -{ - // In single player, you can pick up an infinite number of keys - // even though you can only hold one of each. - if (multiplayer) - { - return Super::HandlePickup (item); - } - if (GetClass() == item->GetClass()) - { - item->ItemFlags |= IF_PICKUPGOOD; - return true; - } - return false; -} - -//=========================================================================== -// -// -//=========================================================================== - -bool AKey::ShouldStay () -{ - return !!multiplayer; -} - //========================================================================== // // These functions can be used to get color information for diff --git a/src/g_inventory/a_keys.h b/src/g_inventory/a_keys.h index eda0473a3..a62670413 100644 --- a/src/g_inventory/a_keys.h +++ b/src/g_inventory/a_keys.h @@ -7,12 +7,7 @@ class AKey : public AInventory { DECLARE_CLASS (AKey, AInventory) public: - virtual bool HandlePickup (AInventory *item) override; - BYTE KeyNumber; - -protected: - virtual bool ShouldStay () override; }; bool P_CheckKeys (AActor *owner, int keynum, bool remote); @@ -21,28 +16,4 @@ void P_DeinitKeyMessages (); int P_GetMapColorForLock (int lock); int P_GetMapColorForKey (AInventory *key); - -// PuzzleItems work in conjunction with the UsePuzzleItem special -class PClassPuzzleItem : public PClassInventory -{ - DECLARE_CLASS(PClassPuzzleItem, PClassInventory); -protected: -public: - virtual void DeriveData(PClass *newclass); - FString PuzzFailMessage; -}; - -class APuzzleItem : public AInventory -{ - DECLARE_CLASS_WITH_META(APuzzleItem, AInventory, PClassPuzzleItem) -public: - - virtual bool ShouldStay () override; - virtual bool Use (bool pickup) override; - virtual bool HandlePickup (AInventory *item) override; - - int PuzzleItemNumber; -}; - - #endif diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 1b26a2db4..72e51b0c9 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -368,19 +368,6 @@ void AInventory::CallDoEffect() } -//=========================================================================== -// -// AInventory :: Travelled -// -// Called when an item in somebody's inventory is carried over to another -// map, in case it needs to do special reinitialization. -// -//=========================================================================== - -void AInventory::Travelled () -{ -} - //=========================================================================== // // AInventory :: OwnerDied @@ -486,6 +473,12 @@ bool AInventory::GoAway () return true; } +DEFINE_ACTION_FUNCTION(AInventory, GoAway) +{ + PARAM_SELF_PROLOGUE(AInventory); + ACTION_RETURN_BOOL(self->GoAway()); +} + //=========================================================================== // // AInventory :: GoAwayAndDie @@ -1286,6 +1279,14 @@ bool AInventory::DrawPowerup (int x, int y) return false; } +DEFINE_ACTION_FUNCTION(AInventory, DrawPowerup) +{ + PARAM_SELF_PROLOGUE(AInventory); + PARAM_INT(x); + PARAM_INT(y); + ACTION_RETURN_BOOL(self->DrawPowerup(x, y)); +} + //=========================================================================== // // AInventory :: DoRespawn @@ -1397,7 +1398,7 @@ bool AInventory::TryPickup (AActor *&toucher) copy->ItemFlags &= ~IF_CREATECOPYMOVED; } // Continue onwards with the rest - copy->AttachToOwner (newtoucher); + copy->CallAttachToOwner (newtoucher); if (ItemFlags & IF_AUTOACTIVATE) { if (copy->CallUse (true)) diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 894849ef2..9cd49bbaf 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -140,7 +140,6 @@ public: double GetSpeedFactor(); bool GetNoTeleportFreeze(); // Stuff for later when more features are exported. - virtual void Travelled(); virtual void OwnerDied(); diff --git a/src/g_inventory/a_puzzleitems.cpp b/src/g_inventory/a_puzzleitems.cpp deleted file mode 100644 index 7617f6383..000000000 --- a/src/g_inventory/a_puzzleitems.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* -** a_puzzleitems.cpp -** Implements Hexen's puzzle items. -** -**--------------------------------------------------------------------------- -** Copyright 2002-2016 Randy Heit -** Copyright 2006-2016 Cheistoph Oelckers -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "info.h" -#include "a_pickups.h" -#include "a_artifacts.h" -#include "gstrings.h" -#include "p_local.h" -#include "s_sound.h" -#include "c_console.h" -#include "doomstat.h" -#include "v_font.h" -#include "a_keys.h" - - -IMPLEMENT_CLASS(PClassPuzzleItem, false, false) -IMPLEMENT_CLASS(APuzzleItem, false, false) - -DEFINE_FIELD(APuzzleItem, PuzzleItemNumber) - -//=========================================================================== -// -// -// -//=========================================================================== - -void PClassPuzzleItem::DeriveData(PClass *newclass) -{ - Super::DeriveData(newclass); - assert(newclass->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); - static_cast(newclass)->PuzzFailMessage = PuzzFailMessage; -} - - -//=========================================================================== -// -// -// -//=========================================================================== - -bool APuzzleItem::HandlePickup (AInventory *item) -{ - // Can't carry more than 1 of each puzzle item in coop netplay - if (multiplayer && !deathmatch && item->GetClass() == GetClass()) - { - return true; - } - return Super::HandlePickup (item); -} - -//=========================================================================== -// -// -// -//=========================================================================== - -bool APuzzleItem::Use (bool pickup) -{ - if (P_UsePuzzleItem (Owner, PuzzleItemNumber)) - { - return true; - } - // [RH] Always play the sound if the use fails. - S_Sound (Owner, CHAN_VOICE, "*puzzfail", 1, ATTN_IDLE); - if (Owner != NULL && Owner->CheckLocalView (consoleplayer)) - { - FString message = GetClass()->PuzzFailMessage; - if (message.IsNotEmpty() && message[0] == '$') message = GStrings[&message[1]]; - if (message.IsEmpty()) message = GStrings("TXT_USEPUZZLEFAILED"); - C_MidPrintBold (SmallFont, message); - } - return false; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -bool APuzzleItem::ShouldStay () -{ - return !!multiplayer; -} - diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 750aad952..02aa8480e 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -311,7 +311,7 @@ bool AWeapon::Use (bool pickup) // weapon, if one exists. if (SisterWeapon != NULL && SisterWeapon->WeaponFlags & WIF_POWERED_UP && - Owner->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true)) + Owner->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true)) { useweap = SisterWeapon; } @@ -824,18 +824,6 @@ DEFINE_ACTION_FUNCTION(AWeapon, EndPowerup) return 0; } -void AWeapon::CallEndPowerup() -{ - IFVIRTUAL(AWeapon, EndPowerup) - { - // Without the type cast this picks the 'void *' assignment... - VMValue params[1] = { (DObject*)this }; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } - else EndPowerup(); -} - - //=========================================================================== // // AWeapon :: GetUpState diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 564c0df02..55354c139 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -161,7 +161,6 @@ public: virtual void EndPowerup (); - void CallEndPowerup(); enum { diff --git a/src/g_level.cpp b/src/g_level.cpp index 7e60a7ac9..43ee0af43 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -84,6 +84,7 @@ #include "r_utility.h" #include "p_spec.h" #include "serializer.h" +#include "virtual.h" #include "gi.h" @@ -1313,7 +1314,13 @@ void G_FinishTravel () { inv->ChangeStatNum (STAT_INVENTORY); inv->LinkToWorld (nullptr); - inv->Travelled (); + + IFVIRTUALPTR(inv, AInventory, Travelled) + { + VMValue params[1] = { inv }; + VMFrameStack stack; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } if (ib_compatflags & BCOMPATF_RESETPLAYERSPEED) { @@ -1891,6 +1898,7 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND) DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS) DEFINE_FIELD_BIT(FLevelLocals, flags2, frozen, LEVEL2_FROZEN) +DEFINE_FIELD_BIT(FLevelLocals, flags2, infinite_flight, LEVEL2_INFINITE_FLIGHT) //========================================================================== // diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 08b18145d..357e2e154 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -32,6 +32,9 @@ struct FLevelLocals TStaticArray lines; TStaticArray sides; + TArray sectorPortals; + + DWORD flags; DWORD flags2; DWORD flags3; @@ -95,7 +98,37 @@ inline int line_t::Index() const return int(this - &level.lines[0]); } +inline FSectorPortal *line_t::GetTransferredPortal() +{ + return portaltransferred >= level.sectorPortals.Size() ? (FSectorPortal*)nullptr : &level.sectorPortals[portaltransferred]; +} + inline int sector_t::Index() const { return int(this - &level.sectors[0]); } + +inline FSectorPortal *sector_t::GetPortal(int plane) +{ + return &level.sectorPortals[Portals[plane]]; +} + +inline double sector_t::GetPortalPlaneZ(int plane) +{ + return level.sectorPortals[Portals[plane]].mPlaneZ; +} + +inline DVector2 sector_t::GetPortalDisplacement(int plane) +{ + return level.sectorPortals[Portals[plane]].mDisplacement; +} + +inline int sector_t::GetPortalType(int plane) +{ + return level.sectorPortals[Portals[plane]].mType; +} + +inline int sector_t::GetOppositePortalGroup(int plane) +{ + return level.sectorPortals[Portals[plane]].mDestination->PortalGroup; +} diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index ca92e731f..ddfd23268 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -12,10 +12,6 @@ #include "serializer.h" #include "r_data/r_translate.h" -static FRandom pr_freezedeath ("FreezeDeath"); -static FRandom pr_freeze ("FreezeDeathChunks"); - - //---------------------------------------------------------------------------- // // PROC A_NoBlocking @@ -74,137 +70,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking) return 0; } -//============================================================================ -// -// A_FreezeDeath -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath) -{ - PARAM_SELF_PROLOGUE(AActor); - - int t = pr_freezedeath(); - self->tics = 75+t+pr_freezedeath(); - self->flags |= MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_ICECORPSE; - self->flags2 |= MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ|MF2_SLIDE; - self->flags3 |= MF3_CRASHED; - self->Height = self->GetDefault()->Height; - // Remove fuzz effects from frozen actors. - if (self->RenderStyle.BlendOp >= STYLEOP_Fuzz && self->RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub) - { - self->RenderStyle = STYLE_Normal; - } - - S_Sound (self, CHAN_BODY, "misc/freeze", 1, ATTN_NORM); - - // [RH] Andy Baker's stealth monsters - if (self->flags & MF_STEALTH) - { - self->Alpha = 1; - self->visdir = 0; - } - - if (self->player) - { - self->player->damagecount = 0; - self->player->poisoncount = 0; - self->player->bonuscount = 0; - } - else if (self->flags3 & MF3_ISMONSTER && self->special) - { // Initiate monster death actions - P_ExecuteSpecial(self->special, NULL, self, false, self->args[0], - self->args[1], self->args[2], self->args[3], self->args[4]); - self->special = 0; - } - return 0; -} - -//============================================================================ -// -// A_FreezeDeathChunks -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - int numChunks; - AActor *mo; - - if (!self->Vel.isZero() && !(self->flags6 & MF6_SHATTERING)) - { - self->tics = 3*TICRATE; - return 0; - } - self->Vel.Zero(); - S_Sound (self, CHAN_BODY, "misc/icebreak", 1, ATTN_NORM); - - // [RH] In Hexen, this creates a random number of shards (range [24,56]) - // with no relation to the size of the self shattering. I think it should - // base the number of shards on the size of the dead thing, so bigger - // things break up into more shards than smaller things. - // An actor with radius 20 and height 64 creates ~40 chunks. - numChunks = MAX(4, int(self->radius * self->Height)/32); - i = (pr_freeze.Random2()) % (numChunks/4); - for (i = MAX (24, numChunks + i); i >= 0; i--) - { - double xo = (pr_freeze() - 128)*self->radius / 128; - double yo = (pr_freeze() - 128)*self->radius / 128; - double zo = (pr_freeze()*self->Height / 255); - - mo = Spawn("IceChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE); - if (mo) - { - mo->SetState (mo->SpawnState + (pr_freeze()%3)); - mo->Vel.X = pr_freeze.Random2() / 128.; - mo->Vel.Y = pr_freeze.Random2() / 128.; - mo->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4; - mo->RenderStyle = self->RenderStyle; - mo->Alpha = self->Alpha; - } - } - if (self->player) - { // attach the player's view to a chunk of ice - AActor *head = Spawn("IceChunkHead", self->PosPlusZ(self->player->mo->ViewHeight), ALLOW_REPLACE); - if (head != NULL) - { - head->Vel.X = pr_freeze.Random2() / 128.; - head->Vel.Y = pr_freeze.Random2() / 128.; - head->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4; - - head->health = self->health; - head->Angles.Yaw = self->Angles.Yaw; - if (head->IsKindOf(RUNTIME_CLASS(APlayerPawn))) - { - head->player = self->player; - head->player->mo = static_cast(head); - self->player = NULL; - head->ObtainInventory (self); - } - head->Angles.Pitch = 0.; - head->RenderStyle = self->RenderStyle; - head->Alpha = self->Alpha; - if (head->player->camera == self) - { - head->player->camera = head; - } - } - } - - // [RH] Do some stuff to make this more useful outside Hexen - if (self->flags4 & MF4_BOSSDEATH) - { - A_BossDeath(self); - } - A_Unblock(self, true); - - self->SetState(self->FindState(NAME_Null)); - return 0; -} - //---------------------------------------------------------------------------- // // CorpseQueue Routines (used by Hexen) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index bb03ff489..d18ec7e02 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -58,9 +58,9 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp if ((p->mo->GetClass() == spawntype) && (p->mo->PlayerFlags & PPF_CANSUPERMORPH) && (p->morphTics < (((duration) ? duration : MORPHTICS) - TICRATE)) - && (p->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true) == nullptr)) + && (p->mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true) == nullptr)) { // Make a super chicken - p->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); + p->mo->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2)); } return false; } @@ -263,7 +263,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, player->MorphStyle = 0; player->MorphExitFlash = nullptr; player->viewheight = mo->ViewHeight; - AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true); + AInventory *level2 = mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true); if (level2 != nullptr) { level2->Destroy (); diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp deleted file mode 100644 index 497e4014a..000000000 --- a/src/g_shared/a_skies.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* -** a_skies.cpp -** Skybox-related actors -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "actor.h" -#include "a_sharedglobal.h" -#include "p_local.h" -#include "p_lnspec.h" -#include "r_sky.h" -#include "r_state.h" -#include "portal.h" - -// arg0 = Visibility*4 for this skybox - -IMPLEMENT_CLASS(ASkyViewpoint, false, false) - -// If this actor has no TID, make it the default sky box -void ASkyViewpoint::BeginPlay () -{ - Super::BeginPlay (); - - if (tid == 0 && sectorPortals[0].mSkybox == nullptr) - { - sectorPortals[0].mSkybox = this; - sectorPortals[0].mDestination = Sector; - } -} - -void ASkyViewpoint::OnDestroy () -{ - // remove all sector references to ourselves. - for (auto &s : sectorPortals) - { - if (s.mSkybox == this) - { - s.mSkybox = 0; - // This is necessary to entirely disable EE-style skyboxes - // if their viewpoint gets deleted. - s.mFlags |= PORTSF_SKYFLATONLY; - } - } - - Super::OnDestroy(); -} - -IMPLEMENT_CLASS(ASkyCamCompat, false, false) - -void ASkyCamCompat::BeginPlay() -{ - // Do not call the SkyViewpoint's super method because it would trash our setup - AActor::BeginPlay(); -} - -//--------------------------------------------------------------------------- - -// arg0 = tid of matching SkyViewpoint -// A value of 0 means to use a regular stretched texture, in case -// there is a default SkyViewpoint in the level. -// -// arg1 = 0: set both floor and ceiling skybox -// = 1: set only ceiling skybox -// = 2: set only floor skybox - -class ASkyPicker : public AActor -{ - DECLARE_CLASS (ASkyPicker, AActor) -public: - void PostBeginPlay (); -}; - -IMPLEMENT_CLASS(ASkyPicker, false, false) - -void ASkyPicker::PostBeginPlay () -{ - ASkyViewpoint *box; - Super::PostBeginPlay (); - - if (args[0] == 0) - { - box = NULL; - } - else - { - TActorIterator iterator (args[0]); - box = iterator.Next (); - } - - if (box == NULL && args[0] != 0) - { - Printf ("Can't find SkyViewpoint %d for sector %d\n", args[0], Sector->sectornum); - } - else - { - int boxindex = P_GetSkyboxPortal(box); - // Do not override special portal types, only regular skies. - if (0 == (args[1] & 2)) - { - if (Sector->GetPortalType(sector_t::ceiling) == PORTS_SKYVIEWPOINT) - Sector->Portals[sector_t::ceiling] = boxindex; - } - if (0 == (args[1] & 1)) - { - if (Sector->GetPortalType(sector_t::floor) == PORTS_SKYVIEWPOINT) - Sector->Portals[sector_t::floor] = boxindex; - } - } - Destroy (); -} - -//--------------------------------------------------------------------------- -// Stacked sectors. - -// arg0 = opacity of plane; 0 = invisible, 255 = fully opaque - -IMPLEMENT_CLASS(AStackPoint, false, false) - -void AStackPoint::BeginPlay () -{ - // Skip SkyViewpoint's initialization - AActor::BeginPlay (); -} - diff --git a/src/g_shared/a_soundenvironment.cpp b/src/g_shared/a_soundenvironment.cpp deleted file mode 100644 index 25088ae44..000000000 --- a/src/g_shared/a_soundenvironment.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -** a_soundenvironment.cpp -** Actor that controls the reverb settings in its zone -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#include "info.h" -#include "r_defs.h" -#include "s_sound.h" -#include "r_state.h" - -class ASoundEnvironment : public AActor -{ - DECLARE_CLASS (ASoundEnvironment, AActor) -public: - void PostBeginPlay (); - void Deactivate (AActor *activator); - void Activate (AActor *deactivator); -}; - -IMPLEMENT_CLASS(ASoundEnvironment, false, false) - -void ASoundEnvironment::PostBeginPlay () -{ - Super::PostBeginPlay (); - if (!(flags2 & MF2_DORMANT)) - { - CallActivate (this); - } -} - -void ASoundEnvironment::Activate (AActor *activator) -{ - Zones[Sector->ZoneNumber].Environment = S_FindEnvironment ((args[0]<<8) | (args[1])); -} - -// Deactivate just exists so that you can flag the thing as dormant in an editor -// and not have it take effect. This is so you can use multiple environments in -// a single zone, with only one set not-dormant, so you know which one will take -// effect at the start. -void ASoundEnvironment::Deactivate (AActor *deactivator) -{ - flags2 |= MF2_DORMANT; -} diff --git a/src/g_shared/a_soundsequence.cpp b/src/g_shared/a_soundsequence.cpp deleted file mode 100644 index 1352e72de..000000000 --- a/src/g_shared/a_soundsequence.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* -** a_soundsequence.cpp -** Actors for independantly playing sound sequences in a map. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** A SoundSequence actor has two modes of operation: -** -** 1. If the sound sequence assigned to it has a slot, then a separate -** SoundSequenceSlot actor is spawned (if not already present), and -** this actor's sound sequence is added to its list of choices. This -** actor is then destroyed, never to be heard from again. The sound -** sequence for the slot is automatically played on the new -** SoundSequenceSlot actor, and it should at some point execute the -** randomsequence command so that it can pick one of the other -** sequences to play. The slot sequence should also end with restart -** so that more than one sequence will have a chance to play. -** -** In this mode, it is very much like world $ambient sounds defined -** in SNDINFO but more flexible. -** -** 2. If the sound sequence assigned to it has no slot, then it will play -** the sequence when activated and cease playing the sequence when -** deactivated. -** -** In this mode, it is very much like point $ambient sounds defined -** in SNDINFO but more flexible. -** -** To assign a sound sequence, set the SoundSequence's first argument to -** the ID of the corresponding environment sequence you want to use. If -** that sequence is a multiple-choice sequence, then the second argument -** selects which choice it picks. -*/ - -#include - -#include "actor.h" -#include "info.h" -#include "s_sound.h" -#include "m_random.h" -#include "s_sndseq.h" -#include "serializer.h" - -// SoundSequenceSlot -------------------------------------------------------- - -class ASoundSequenceSlot : public AActor -{ - DECLARE_CLASS (ASoundSequenceSlot, AActor) - HAS_OBJECT_POINTERS -public: - - void Serialize(FSerializer &arc); - - TObjPtr Sequence; -}; - -IMPLEMENT_CLASS(ASoundSequenceSlot, false, true) - -IMPLEMENT_POINTERS_START(ASoundSequenceSlot) - IMPLEMENT_POINTER(Sequence) -IMPLEMENT_POINTERS_END - -//========================================================================== -// -// ASoundSequenceSlot :: Serialize -// -//========================================================================== - -void ASoundSequenceSlot::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("sequence", Sequence); -} - -// SoundSequence ------------------------------------------------------------ - -class ASoundSequence : public AActor -{ - DECLARE_CLASS (ASoundSequence, AActor) -public: - void OnDestroy() override; - void PostBeginPlay (); - void Activate (AActor *activator); - void Deactivate (AActor *activator); - void MarkPrecacheSounds () const; -}; - -IMPLEMENT_CLASS(ASoundSequence, false, false) - -//========================================================================== -// -// ASoundSequence :: Destroy -// -//========================================================================== - -void ASoundSequence::OnDestroy () -{ - SN_StopSequence (this); - Super::OnDestroy(); -} - -//========================================================================== -// -// ASoundSequence :: PostBeginPlay -// -//========================================================================== - -void ASoundSequence::PostBeginPlay () -{ - FName slot = SN_GetSequenceSlot (args[0], SEQ_ENVIRONMENT); - - if (slot != NAME_None) - { // This is a slotted sound, so add it to the master for that slot - ASoundSequenceSlot *master; - TThinkerIterator locator; - - while (NULL != (master = locator.Next ())) - { - if (master->Sequence->GetSequenceName() == slot) - { - break; - } - } - if (master == NULL) - { - master = Spawn (); - master->Sequence = SN_StartSequence (master, slot, 0); - GC::WriteBarrier(master, master->Sequence); - } - master->Sequence->AddChoice (args[0], SEQ_ENVIRONMENT); - Destroy (); - } -} - -//========================================================================== -// -// ASoundSequence :: MarkPrecacheSounds -// -//========================================================================== - -void ASoundSequence::MarkPrecacheSounds() const -{ - Super::MarkPrecacheSounds(); - SN_MarkPrecacheSounds(args[0], SEQ_ENVIRONMENT); -} - -//========================================================================== -// -// ASoundSequence :: Activate -// -//========================================================================== - -void ASoundSequence::Activate (AActor *activator) -{ - SN_StartSequence (this, args[0], SEQ_ENVIRONMENT, args[1]); -} - -//========================================================================== -// -// ASoundSequence :: Deactivate -// -//========================================================================== - -void ASoundSequence::Deactivate (AActor *activator) -{ - SN_StopSequence (this); -} diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 009b480b7..6a790f845 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -56,6 +56,7 @@ #include "r_utility.h" #include "cmdlib.h" #include "g_levellocals.h" +#include "virtual.h" #include "../version.h" @@ -1529,13 +1530,22 @@ void DBaseStatusBar::DrawPowerups () + (ST_IsLatencyVisible() ? yshift : 0); for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory) { - if (item->DrawPowerup (x, y)) + IFVIRTUALPTR(item, AInventory, DrawPowerup) { - x -= POWERUPICONSIZE; - if (x < -POWERUPICONSIZE*5) + VMValue params[3] = { item, x, y }; + VMReturn ret; + int retv; + + ret.IntAt(&retv); + GlobalVMStack.Call(func, params, 3, &ret, 1); + if (retv) { - x = -20; - y += POWERUPICONSIZE*2; + x -= POWERUPICONSIZE; + if (x < -POWERUPICONSIZE * 5) + { + x = -20; + y += POWERUPICONSIZE * 2; + } } } } diff --git a/src/gl/data/gl_data.h b/src/gl/data/gl_data.h index bb57c9139..d5bdeb46a 100644 --- a/src/gl/data/gl_data.h +++ b/src/gl/data/gl_data.h @@ -46,7 +46,6 @@ inline int getExtraLight() void gl_RecalcVertexHeights(vertex_t * v); FTextureID gl_GetSpriteFrame(unsigned sprite, int frame, int rot, angle_t ang, bool *mirror); -class AStackPoint; struct GLSectorStackPortal; struct FPortal diff --git a/src/gl/data/gl_setup.cpp b/src/gl/data/gl_setup.cpp index 7959b2083..c34b149d5 100644 --- a/src/gl/data/gl_setup.cpp +++ b/src/gl/data/gl_setup.cpp @@ -399,20 +399,15 @@ static void AddToVertex(const sector_t * sec, TArray & list) static void InitVertexData() { - TArray * vt_sectorlists; - - int i,j,k; - - vt_sectorlists = new TArray[level.vertexes.Size()]; - + auto vt_sectorlists = new TArray[level.vertexes.Size()]; for(auto &line : level.lines) { - for(j=0;j<2;j++) + for(int j = 0; j < 2; ++j) { vertex_t * v = j==0? line.v1 : line.v2; - for(k=0;k<2;k++) + for(int k = 0; k < 2; ++k) { sector_t * sec = k==0? line.frontsector : line.backsector; @@ -427,7 +422,7 @@ static void InitVertexData() } } - for(i=0;i 1) qsort(level.sides[i].segs, level.sides[i].numsegs, sizeof(seg_t*), segcmp); } diff --git a/src/gl/scene/gl_fakeflat.cpp b/src/gl/scene/gl_fakeflat.cpp index 7fcc6d239..98a70a1a8 100644 --- a/src/gl/scene/gl_fakeflat.cpp +++ b/src/gl/scene/gl_fakeflat.cpp @@ -27,6 +27,7 @@ #include "p_lnspec.h" #include "p_local.h" +#include "g_levellocals.h" #include "a_sharedglobal.h" #include "r_sky.h" #include "gl/renderer/gl_renderer.h" diff --git a/src/gl/scene/gl_portal.h b/src/gl/scene/gl_portal.h index 8a40ec2e2..3adaa4aa4 100644 --- a/src/gl/scene/gl_portal.h +++ b/src/gl/scene/gl_portal.h @@ -43,9 +43,6 @@ #include "gl/utility/gl_templates.h" #include "gl/data/gl_data.h" -class ASkyViewpoint; - - struct GLHorizonInfo { GLSectorPlane plane; diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 9a9a994bd..1ee1b1b5c 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -767,16 +767,18 @@ void FGLRenderer::SetFixedColormap (player_t *player) } else if (cplayer->fixedlightlevel != -1) { + auto torchtype = PClass::FindActor(NAME_PowerTorch); + auto litetype = PClass::FindActor(NAME_PowerLightAmp); for(AInventory * in = cplayer->mo->Inventory; in; in = in->Inventory) { PalEntry color = in->GetBlend (); // Need special handling for light amplifiers - if (in->IsKindOf(RUNTIME_CLASS(APowerTorch))) + if (in->IsKindOf(torchtype)) { gl_fixedcolormap = cplayer->fixedlightlevel + CM_TORCH; } - else if (in->IsKindOf(RUNTIME_CLASS(APowerLightAmp))) + else if (in->IsKindOf(litetype)) { gl_fixedcolormap = CM_LITE; } diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 36c6249cd..46f18d96f 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -218,7 +218,7 @@ void cht_DoCheat (player_t *player, int cheat) case CHT_POWER: if (player->mo != NULL && player->health >= 0) { - item = player->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true); + item = player->mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true); if (item != NULL) { item->Destroy (); @@ -226,7 +226,7 @@ void cht_DoCheat (player_t *player, int cheat) } else { - player->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); + player->mo->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2)); msg = GStrings("TXT_CHEATPOWERON"); } } @@ -747,6 +747,8 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "artifacts") == 0) { + auto pitype = PClass::FindActor(NAME_PuzzleItem); + for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; @@ -754,7 +756,7 @@ void cht_Give (player_t *player, const char *name, int amount) { AInventory *def = (AInventory*)GetDefaultByType (type); if (def->Icon.isValid() && def->MaxAmount > 1 && - !type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem)) && + !type->IsDescendantOf (pitype) && !type->IsDescendantOf (RUNTIME_CLASS(APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS(AArmor))) { @@ -772,10 +774,11 @@ void cht_Give (player_t *player, const char *name, int amount) if (giveall || stricmp (name, "puzzlepieces") == 0) { + auto pitype = PClass::FindActor(NAME_PuzzleItem); for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; - if (type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem))) + if (type->IsDescendantOf (pitype)) { AInventory *def = (AInventory*)GetDefaultByType (type); if (def->Icon.isValid()) @@ -859,7 +862,7 @@ void cht_Take (player_t *player, const char *name, int amount) { PClass *type = PClassActor::AllActorClasses[i]; - if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem))) + if (type->IsDescendantOf(PClass::FindClass(NAME_BackpackItem))) { AInventory *pack = player->mo->FindInventory(static_cast(type)); @@ -954,13 +957,14 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "artifacts") == 0) { + auto pitype = PClass::FindActor(NAME_PuzzleItem); for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { - if (!type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem)) && + if (!type->IsDescendantOf (pitype) && !type->IsDescendantOf (RUNTIME_CLASS (APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS (AArmor)) && !type->IsDescendantOf (RUNTIME_CLASS (AWeapon)) && @@ -980,11 +984,12 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall || stricmp (name, "puzzlepieces") == 0) { + auto pitype = PClass::FindActor(NAME_PuzzleItem); for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; - if (type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem))) + if (type->IsDescendantOf (pitype)) { AActor *puzzlepiece = player->mo->FindInventory(static_cast(type)); diff --git a/src/namedef.h b/src/namedef.h index aa7969193..c37ee5577 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -165,6 +165,22 @@ xx(FlameThrower) xx(MiniMissileLauncher) xx(StrifeGrenadeLauncher) xx(Mauler) +xx(BackpackItem) +xx(PuzzleItem) +xx(PuzzleItemNumber) +xx(HealthPickup) +xx(autousemode) +xx(Ammo) +xx(PowerTargeter) +xx(PowerInvulnerable) +xx(PowerStrength) +xx(PowerInvisibility) +xx(PowerIronFeet) +xx(PowerLightAmp) +xx(PowerWeaponLevel2) +xx(PowerFlight) +xx(PowerSpeed) +xx(PowerTorch) xx(AcolyteBlue) xx(SpectralLightningV1) @@ -292,6 +308,7 @@ xx(Random2) xx(RandomPick) xx(FRandomPick) xx(GetClass) +xx(GetParentClass) xx(GetDefaultByType) xx(Exp) xx(Log10) diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 735ee10f7..19dc16b61 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -1053,7 +1053,7 @@ void FNodeBuilder::PrintSet (int l, DWORD set) Printf (PRINT_LOG, "set %d:\n", l); for (; set != DWORD_MAX; set = Segs[set].next) { - Printf (PRINT_LOG, "\t%u(%td)%c%d(%d,%d)-%d(%d,%d)\n", set, Segs[set].frontsector->sectornum, + Printf (PRINT_LOG, "\t%u(%d)%c%d(%d,%d)-%d(%d,%d)\n", set, Segs[set].frontsector->sectornum, Segs[set].linedef == -1 ? '+' : ':', Segs[set].v1, Vertices[Segs[set].v1].x>>16, Vertices[Segs[set].v1].y>>16, diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index b47788212..3c7eeca07 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -79,7 +79,6 @@ #include "thingdef.h" #include "math/cmath.h" #include "a_armor.h" -#include "a_health.h" #include "g_levellocals.h" AActor *SingleActorFromTID(int tid, AActor *defactor); @@ -2400,7 +2399,7 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) { return false; } - if (item->IsKindOf(RUNTIME_CLASS(AHealth))) + if (item->IsKindOf(PClass::FindActor(NAME_Health))) { item->Amount *= amount; } @@ -5655,7 +5654,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) { // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight. AInventory *gift = static_cast(Spawn(item)); - if (gift->IsKindOf(RUNTIME_CLASS(AHealth))) + if (gift->IsKindOf(PClass::FindActor(NAME_Health))) { gift->Amount *= amount; } diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 51e59ec08..bfe341265 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -376,7 +376,9 @@ static bool LoadGLSegs(FileReader * lump) { // check for gl-vertices segs[i].v1 = &level.vertexes[checkGLVertex3(LittleLong(ml->v1))]; segs[i].v2 = &level.vertexes[checkGLVertex3(LittleLong(ml->v2))]; - segs[i].PartnerSeg = LittleLong(ml->partner) == 0xffffffffu? nullptr : &segs[LittleLong(ml->partner)]; + + const DWORD partner = LittleLong(ml->partner); + segs[i].PartnerSeg = DWORD_MAX == partner ? nullptr : &segs[partner]; if(ml->linedef != 0xffff) // skip minisegs { diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 43cafeebc..97787fd9c 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -59,7 +59,6 @@ #include "d_netinf.h" #include "a_morph.h" #include "virtual.h" -#include "a_health.h" #include "g_levellocals.h" static FRandom pr_obituary ("Obituary"); @@ -477,7 +476,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) if (source->player->morphTics) { // Make a super chicken - source->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); + source->GiveInventoryType (PClass::FindActor(NAME_PowerWeaponLevel2)); } if (deathmatch && cl_showsprees) @@ -840,11 +839,12 @@ void P_AutoUseHealth(player_t *player, int saveHealth) TArray NormalHealthItems; TArray LargeHealthItems; + auto hptype = PClass::FindActor(NAME_HealthPickup); for(AInventory *inv = player->mo->Inventory; inv != NULL; inv = inv->Inventory) { - if (inv->Amount > 0 && inv->IsKindOf(RUNTIME_CLASS(AHealthPickup))) + if (inv->Amount > 0 && inv->IsKindOf(hptype)) { - int mode = static_cast(inv)->autousemode; + int mode = inv->IntVar(NAME_autousemode); if (mode == 1) NormalHealthItems.Push(inv); else if (mode == 2) LargeHealthItems.Push(inv); @@ -884,12 +884,12 @@ void P_AutoUseStrifeHealth (player_t *player) { TArray Items; + auto hptype = PClass::FindActor(NAME_HealthPickup); for(AInventory *inv = player->mo->Inventory; inv != NULL; inv = inv->Inventory) { - if (inv->Amount > 0 && inv->IsKindOf(RUNTIME_CLASS(AHealthPickup))) + if (inv->Amount > 0 && inv->IsKindOf(hptype)) { - int mode = static_cast(inv)->autousemode; - + int mode = inv->IntVar(NAME_autousemode); if (mode == 3) Items.Push(inv); } } diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 9fde1af22..f26f617a9 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -2138,11 +2138,12 @@ FUNC(LS_UsePuzzleItem) if (!it) return false; // Check player's inventory for puzzle item + auto pitype = PClass::FindActor(NAME_PuzzleItem); for (item = it->Inventory; item != NULL; item = item->Inventory) { - if (item->IsKindOf (RUNTIME_CLASS(APuzzleItem))) + if (item->IsKindOf (pitype)) { - if (static_cast(item)->PuzzleItemNumber == arg0) + if (item->IntVar(NAME_PuzzleItemNumber) == arg0) { if (it->UseInventory (item)) { @@ -2840,23 +2841,23 @@ FUNC(LS_SetPlayerProperty) // Add or remove a power if (arg2 >= PROP_INVULNERABILITY && arg2 <= PROP_SPEED) { - static PClass * const *powers[11] = + static ENamedName powers[11] = { - &RUNTIME_CLASS_CASTLESS(APowerInvulnerable), - &RUNTIME_CLASS_CASTLESS(APowerStrength), - &RUNTIME_CLASS_CASTLESS(APowerInvisibility), - &RUNTIME_CLASS_CASTLESS(APowerIronFeet), - NULL, // MapRevealer - &RUNTIME_CLASS_CASTLESS(APowerLightAmp), - &RUNTIME_CLASS_CASTLESS(APowerWeaponLevel2), - &RUNTIME_CLASS_CASTLESS(APowerFlight), - NULL, - NULL, - &RUNTIME_CLASS_CASTLESS(APowerSpeed) + NAME_PowerInvulnerable, + NAME_PowerStrength, + NAME_PowerInvisibility, + NAME_PowerIronFeet, + NAME_None, + NAME_PowerLightAmp, + NAME_PowerWeaponLevel2, + NAME_PowerFlight, + NAME_None, + NAME_None, + NAME_PowerSpeed }; int power = arg2 - PROP_INVULNERABILITY; - if (power > 4 && powers[power] == NULL) + if (power > 4 && powers[power] == NAME_None) { return false; } @@ -2867,7 +2868,7 @@ FUNC(LS_SetPlayerProperty) { // Give power to activator if (power != 4) { - APowerup *item = static_cast(it->GiveInventoryType(static_cast(*powers[power]))); + APowerup *item = static_cast(it->GiveInventoryType(PClass::FindActor(powers[power]))); if (item != NULL && power == 0 && arg1 == 1) { item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP); @@ -2882,7 +2883,7 @@ FUNC(LS_SetPlayerProperty) { // Take power from activator if (power != 4) { - AInventory *item = it->FindInventory(static_cast(*powers[power]), true); + AInventory *item = it->FindInventory(PClass::FindActor(powers[power]), true); if (item != NULL) { item->Destroy (); @@ -2907,7 +2908,7 @@ FUNC(LS_SetPlayerProperty) { // Give power if (power != 4) { - APowerup *item = static_cast(players[i].mo->GiveInventoryType (static_cast(*powers[power]))); + APowerup *item = static_cast(players[i].mo->GiveInventoryType ((PClass::FindActor(powers[power])))); if (item != NULL && power == 0 && arg1 == 1) { item->BlendColor = MakeSpecialColormap(INVERSECOLORMAP); @@ -2922,7 +2923,7 @@ FUNC(LS_SetPlayerProperty) { // Take power if (power != 4) { - AInventory *item = players[i].mo->FindInventory (static_cast(*powers[power])); + AInventory *item = players[i].mo->FindInventory (PClass::FindActor(powers[power])); if (item != NULL) { item->Destroy (); diff --git a/src/p_map.cpp b/src/p_map.cpp index c3fd2dc88..ae3dfd0f2 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5515,6 +5515,13 @@ bool P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType) return false; } +DEFINE_ACTION_FUNCTION(AActor, UsePuzzleItem) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(puzznum); + ACTION_RETURN_BOOL(P_UsePuzzleItem(self, puzznum)); +} + //========================================================================== // // RADIUS ATTACK diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5d116f101..b40b8baa3 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -71,8 +71,8 @@ #include "virtual.h" #include "a_armor.h" #include "a_ammo.h" -#include "a_health.h" #include "g_levellocals.h" +#include "a_morph.h" // MACROS ------------------------------------------------------------------ @@ -1199,18 +1199,7 @@ void AActor::ClearInventory() AInventory *inv = *invp; if (!(inv->ItemFlags & IF_UNDROPPABLE)) { - // For the sake of undroppable weapons, never remove ammo once - // it has been acquired; just set its amount to 0. - if (inv->IsKindOf(RUNTIME_CLASS(AAmmo))) - { - AAmmo *ammo = static_cast(inv); - ammo->Amount = 0; - invp = &inv->Inventory; - } - else - { - inv->Destroy (); - } + inv->DepleteOrDestroy(); } else if (inv->GetClass() == RUNTIME_CLASS(AHexenArmor)) { @@ -1311,6 +1300,122 @@ void AActor::ObtainInventory (AActor *other) } } +DEFINE_ACTION_FUNCTION(AActor, ObtainInventory) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(other, AActor); + self->ObtainInventory(other); + return 0; +} + +//--------------------------------------------------------------------------- +// +// FUNC P_GiveBody +// +// Returns false if the body isn't needed at all. +// +//--------------------------------------------------------------------------- + +bool P_GiveBody(AActor *actor, int num, int max) +{ + if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD)) + { // Do not heal dead things. + return false; + } + + player_t *player = actor->player; + + num = clamp(num, -65536, 65536); // prevent overflows for bad values + if (player != NULL) + { + // Max is 0 by default, preserving default behavior for P_GiveBody() + // calls while supporting health pickups. + if (max <= 0) + { + max = static_cast(actor)->GetMaxHealth() + player->mo->stamina; + // [MH] First step in predictable generic morph effects + if (player->morphTics) + { + if (player->MorphStyle & MORPH_FULLHEALTH) + { + if (!(player->MorphStyle & MORPH_ADDSTAMINA)) + { + max -= player->mo->stamina; + } + } + else // old health behaviour + { + max = MAXMORPHHEALTH; + if (player->MorphStyle & MORPH_ADDSTAMINA) + { + max += player->mo->stamina; + } + } + } + } + // [RH] For Strife: A negative body sets you up with a percentage + // of your full health. + if (num < 0) + { + num = max * -num / 100; + if (player->health < num) + { + player->health = num; + actor->health = num; + return true; + } + } + else if (num > 0) + { + if (player->health < max) + { + num = int(num * G_SkillProperty(SKILLP_HealthFactor)); + if (num < 1) num = 1; + player->health += num; + if (player->health > max) + { + player->health = max; + } + actor->health = player->health; + return true; + } + } + } + else + { + // Parameter value for max is ignored on monsters, preserving original + // behaviour of health as well as on existing calls to P_GiveBody(). + max = actor->SpawnHealth(); + if (num < 0) + { + num = max * -num / 100; + if (actor->health < num) + { + actor->health = num; + return true; + } + } + else if (actor->health < max) + { + actor->health += num; + if (actor->health > max) + { + actor->health = max; + } + return true; + } + } + return false; +} + +DEFINE_ACTION_FUNCTION(AActor, GiveBody) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(num); + PARAM_INT_DEF(max); + ACTION_RETURN_BOOL(P_GiveBody(self, num, max)); +} + //============================================================================ // // AActor :: CheckLocalView @@ -4832,6 +4937,13 @@ void AActor::MarkPrecacheSounds() const CrushPainSound.MarkUsed(); } +DEFINE_ACTION_FUNCTION(AActor, MarkPrecacheSounds) +{ + PARAM_SELF_PROLOGUE(AActor); + self->MarkPrecacheSounds(); + return 0; +} + bool AActor::isFast() { if (flags5&MF5_ALWAYSFAST) return true; @@ -5539,9 +5651,10 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // [RH] Other things that shouldn't be spawned depending on dmflags if (deathmatch || alwaysapplydmflags) { + // Fixme: This needs to be done differently, it's quite broken. if (dmflags & DF_NO_HEALTH) { - if (i->IsDescendantOf (RUNTIME_CLASS(AHealth))) + if (i->IsDescendantOf (PClass::FindActor(NAME_Health))) return NULL; if (i->TypeName == NAME_Berserk) return NULL; diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 7662f3240..e46b63436 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -237,7 +237,7 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) { if (mo != nullptr) { - newcaller = mo->FindInventory(RUNTIME_CLASS(APowerTargeter), true); + newcaller = mo->FindInventory(PClass::FindActor(NAME_PowerTargeter), true); } } else if (layer == PSP_STRIFEHANDS) @@ -485,7 +485,7 @@ void P_BringUpWeapon (player_t *player) if (weapon != nullptr && weapon->SisterWeapon && weapon->SisterWeapon->WeaponFlags & WIF_POWERED_UP && - player->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true)) + player->mo->FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true)) { weapon = weapon->SisterWeapon; } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 8dc46e922..04c35d157 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -378,7 +378,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, subsector_t *&ss, subs .StringPtr(nullptr, str) .EndArray(); - if (num_verts == level.vertexes.Size() && num_subs == numsubsectors && hasglnodes) + if (num_verts == (int)level.vertexes.Size() && num_subs == numsubsectors && hasglnodes) { success = true; int sub = 0; @@ -964,7 +964,7 @@ void G_SerializeLevel(FSerializer &arc, bool hubload) arc.Array("sectors", &level.sectors[0], &loadsectors[0], level.sectors.Size()); arc("zones", Zones); arc("lineportals", linePortals); - arc("sectorportals", sectorPortals); + arc("sectorportals", level.sectorPortals); if (arc.isReading()) P_CollectLinkedPortals(); DThinker::SerializeThinkers(arc, !hubload); @@ -1009,4 +1009,4 @@ void P_FreeMapDataBackup() loadsectors.Clear(); loadlines.Clear(); loadsides.Clear(); -} \ No newline at end of file +} diff --git a/src/p_scroll.cpp b/src/p_scroll.cpp index 11de6023f..8dcf18a53 100644 --- a/src/p_scroll.cpp +++ b/src/p_scroll.cpp @@ -529,7 +529,7 @@ void P_SpawnScrollers(void) FLineIdIterator itr(l->args[0]); while ((s = itr.Next()) >= 0) { - if (s != i) + if (s != (int)i) new DScroller(dx, dy, &level.lines[s], control, accel); } break; diff --git a/src/p_secnodes.cpp b/src/p_secnodes.cpp index 8edfc0c70..b351f0e58 100644 --- a/src/p_secnodes.cpp +++ b/src/p_secnodes.cpp @@ -21,6 +21,7 @@ // //----------------------------------------------------------------------------- +#include "g_levellocals.h" #include "r_state.h" #include "p_maputl.h" #include "p_blockmap.h" diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 5c14d56a0..e85fd744f 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -1673,12 +1673,6 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) ACTION_RETURN_INT(self->GetPlaneLight(pos)); } - class FSetTextureID : public FTextureID - { - public: - FSetTextureID(int v) : FTextureID(v) {} - }; - DEFINE_ACTION_FUNCTION(_Sector, SetTexture) { PARAM_SELF_STRUCT_PROLOGUE(sector_t); @@ -1837,6 +1831,22 @@ DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt) ACTION_RETURN_INT(ndx); } + DEFINE_ACTION_FUNCTION(_Sector, SetEnvironmentID) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(envnum); + Zones[self->ZoneNumber].Environment = S_FindEnvironment(envnum); + return 0; + } + + DEFINE_ACTION_FUNCTION(_Sector, SetEnvironment) + { + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_STRING(env); + Zones[self->ZoneNumber].Environment = S_FindEnvironment(env); + return 0; + } + //=========================================================================== // // line_t exports diff --git a/src/p_setup.cpp b/src/p_setup.cpp index c7c59aaa9..b94e12b9b 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -2298,7 +2298,7 @@ static void P_AllocateSideDefs (MapData *map, int count) sidetemp[i].a.alpha = SHRT_MIN; sidetemp[i].a.map = NO_SIDE; } - auto numsides = map->Size(ML_SIDEDEFS) / sizeof(mapsidedef_t); + int numsides = map->Size(ML_SIDEDEFS) / sizeof(mapsidedef_t); if (count < numsides) { Printf ("Map has %d unused sidedefs\n", numsides - count); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index b3953b1bd..0909da70f 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -845,12 +845,12 @@ void DWallLightTransfer::DoTransfer (short lightlevel, int target, BYTE flags) //--------------------------------------------------------------------------- // Upper stacks go in the top sector. Lower stacks go in the bottom sector. -static void SetupFloorPortal (AStackPoint *point) +static void SetupFloorPortal (AActor *point) { NActorIterator it (NAME_LowerStackLookOnly, point->tid); sector_t *Sector = point->Sector; - ASkyViewpoint *skyv = static_cast(it.Next()); - if (skyv != NULL) + auto skyv = it.Next(); + if (skyv != nullptr) { skyv->target = point; if (Sector->GetAlpha(sector_t::floor) == 1.) @@ -860,12 +860,12 @@ static void SetupFloorPortal (AStackPoint *point) } } -static void SetupCeilingPortal (AStackPoint *point) +static void SetupCeilingPortal (AActor *point) { NActorIterator it (NAME_UpperStackLookOnly, point->tid); sector_t *Sector = point->Sector; - ASkyViewpoint *skyv = static_cast(it.Next()); - if (skyv != NULL) + auto skyv = it.Next(); + if (skyv != nullptr) { skyv->target = point; if (Sector->GetAlpha(sector_t::ceiling) == 1.) @@ -877,9 +877,9 @@ static void SetupCeilingPortal (AStackPoint *point) void P_SetupPortals() { - TThinkerIterator it; - AStackPoint *pt; - TArray points; + TThinkerIterator it("StackPoint"); + AActor *pt; + TArray points; while ((pt = it.Next())) { @@ -897,21 +897,21 @@ void P_SetupPortals() } // the semantics here are incredibly lax so the final setup can only be done once all portals have been created, // because later stackpoints will happily overwrite info in older ones, if there are multiple links. - for (auto &s : sectorPortals) + for (auto &s : level.sectorPortals) { if (s.mType == PORTS_STACKEDSECTORTHING && s.mSkybox) { - for (auto &ss : sectorPortals) + for (auto &ss : level.sectorPortals) { if (ss.mType == PORTS_STACKEDSECTORTHING && ss.mSkybox == s.mSkybox->target) { - s.mPartner = unsigned((&ss) - §orPortals[0]); + s.mPartner = unsigned((&ss) - &level.sectorPortals[0]); } } } } // Now we can finally set the displacement and delete the stackpoint reference. - for (auto &s : sectorPortals) + for (auto &s : level.sectorPortals) { if (s.mType == PORTS_STACKEDSECTORTHING && s.mSkybox) { @@ -932,7 +932,7 @@ static void SetPortal(sector_t *sector, int plane, unsigned pnum, double alpha) if (sector->GetAlpha(sector_t::ceiling) == 1.) sector->SetAlpha(sector_t::ceiling, alpha); - if (sectorPortals[pnum].mFlags & PORTSF_SKYFLATONLY) + if (level.sectorPortals[pnum].mFlags & PORTSF_SKYFLATONLY) sector->SetTexture(sector_t::ceiling, skyflatnum); } } @@ -945,7 +945,7 @@ static void SetPortal(sector_t *sector, int plane, unsigned pnum, double alpha) if (sector->GetAlpha(sector_t::floor) == 1.) sector->SetAlpha(sector_t::floor, alpha); - if (sectorPortals[pnum].mFlags & PORTSF_SKYFLATONLY) + if (level.sectorPortals[pnum].mFlags & PORTSF_SKYFLATONLY) sector->SetTexture(sector_t::floor, skyflatnum); } } @@ -1027,7 +1027,7 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int bytealpha, int li // This searches the viewpoint's sector // for a skybox line special, gets its tag and transfers the skybox to all tagged sectors. -void P_SpawnSkybox(ASkyViewpoint *origin) +void P_SpawnSkybox(AActor *origin) { sector_t *Sector = origin->Sector; if (Sector == NULL) @@ -1260,8 +1260,8 @@ void P_SpawnSpecials (void) P_SpawnFriction(); // phares 3/12/98: New friction model using linedefs P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs - TThinkerIterator it2; - ASkyCamCompat *pt2; + TThinkerIterator it2("SkyCamCompat"); + AActor *pt2; while ((pt2 = it2.Next())) { P_SpawnSkybox(pt2); diff --git a/src/p_user.cpp b/src/p_user.cpp index b68cad604..952a88632 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -948,7 +948,7 @@ AWeapon *APlayerPawn::BestWeapon(PClassInventory *ammotype) int bestOrder = INT_MAX; AInventory *item; AWeapon *weap; - bool tomed = NULL != FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true); + bool tomed = NULL != FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true); // Find the best weapon the player has. for (item = Inventory; item != NULL; item = item->Inventory) @@ -1048,6 +1048,13 @@ void APlayerPawn::CheckWeaponSwitch(PClassInventory *ammotype) } } +DEFINE_ACTION_FUNCTION(APlayerPawn, CheckWeaponSwitch) +{ + PARAM_SELF_PROLOGUE(APlayerPawn); + PARAM_OBJECT(ammotype, PClassInventory); + self->CheckWeaponSwitch(ammotype); + return 0; +} //=========================================================================== // // APlayerPawn :: GiveDeathmatchInventory diff --git a/src/polyrenderer/scene/poly_portal.cpp b/src/polyrenderer/scene/poly_portal.cpp index 1aa43e9bc..9737aa90f 100644 --- a/src/polyrenderer/scene/poly_portal.cpp +++ b/src/polyrenderer/scene/poly_portal.cpp @@ -25,6 +25,7 @@ #include "doomdef.h" #include "p_maputl.h" #include "sbar.h" +#include "g_levellocals.h" #include "r_data/r_translate.h" #include "poly_portal.h" #include "polyrenderer/poly_renderer.h" @@ -96,7 +97,7 @@ void PolyDrawSectorPortal::SaveGlobals() if (Portal->mType == PORTS_SKYVIEWPOINT) { // Don't let gun flashes brighten the sky box - ASkyViewpoint *sky = barrier_cast(Portal->mSkybox); + AActor *sky = Portal->mSkybox; extralight = 0; swrenderer::R_SetVisibility(sky->args[0] * 0.25f); ViewPos = sky->InterpolatedPosition(r_TicFracF); @@ -115,13 +116,13 @@ void PolyDrawSectorPortal::SaveGlobals() R_SetViewAngle(); Portal->mFlags |= PORTSF_INSKYBOX; - if (Portal->mPartner > 0) sectorPortals[Portal->mPartner].mFlags |= PORTSF_INSKYBOX; + if (Portal->mPartner > 0) level.sectorPortals[Portal->mPartner].mFlags |= PORTSF_INSKYBOX; } void PolyDrawSectorPortal::RestoreGlobals() { Portal->mFlags &= ~PORTSF_INSKYBOX; - if (Portal->mPartner > 0) sectorPortals[Portal->mPartner].mFlags &= ~PORTSF_INSKYBOX; + if (Portal->mPartner > 0) level.sectorPortals[Portal->mPartner].mFlags &= ~PORTSF_INSKYBOX; camera = savedcamera; viewsector = savedsector; diff --git a/src/portal.cpp b/src/portal.cpp index abe442554..43b7ef7b6 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -62,7 +62,16 @@ FPortalBlockmap PortalBlockmap; TArray linePortals; TArray linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. -TArray sectorPortals; + +DEFINE_FIELD(FSectorPortal, mType); +DEFINE_FIELD(FSectorPortal, mFlags); +DEFINE_FIELD(FSectorPortal, mPartner); +DEFINE_FIELD(FSectorPortal, mPlane); +DEFINE_FIELD(FSectorPortal, mOrigin); +DEFINE_FIELD(FSectorPortal, mDestination); +DEFINE_FIELD(FSectorPortal, mDisplacement); +DEFINE_FIELD(FSectorPortal, mPlaneZ); +DEFINE_FIELD(FSectorPortal, mSkybox); //============================================================================ // @@ -490,15 +499,15 @@ void P_ClearPortals() Displacements.Create(1); linePortals.Clear(); linkedPortals.Clear(); - sectorPortals.Resize(2); + level.sectorPortals.Resize(2); // The first entry must always be the default skybox. This is what every sector gets by default. - memset(§orPortals[0], 0, sizeof(sectorPortals[0])); - sectorPortals[0].mType = PORTS_SKYVIEWPOINT; - sectorPortals[0].mFlags = PORTSF_SKYFLATONLY; + memset(&level.sectorPortals[0], 0, sizeof(level.sectorPortals[0])); + level.sectorPortals[0].mType = PORTS_SKYVIEWPOINT; + level.sectorPortals[0].mFlags = PORTSF_SKYFLATONLY; // The second entry will be the default sky. This is for forcing a regular sky through the skybox picker - memset(§orPortals[1], 0, sizeof(sectorPortals[0])); - sectorPortals[1].mType = PORTS_SKYVIEWPOINT; - sectorPortals[1].mFlags = PORTSF_SKYFLATONLY; + memset(&level.sectorPortals[1], 0, sizeof(level.sectorPortals[0])); + level.sectorPortals[1].mType = PORTS_SKYVIEWPOINT; + level.sectorPortals[1].mFlags = PORTSF_SKYFLATONLY; } //============================================================================ @@ -651,22 +660,28 @@ void P_TranslatePortalZ(line_t* src, double& z) // //============================================================================ -unsigned P_GetSkyboxPortal(ASkyViewpoint *actor) +unsigned P_GetSkyboxPortal(AActor *actor) { if (actor == NULL) return 1; // this means a regular sky. - for (unsigned i = 0;iGetClass()->IsDescendantOf(RUNTIME_CLASS(ASkyCamCompat)) ? 0 : PORTSF_SKYFLATONLY; - sectorPortals[i].mSkybox = actor; - sectorPortals[i].mDestination = actor->Sector; + unsigned i = level.sectorPortals.Reserve(1); + memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); + level.sectorPortals[i].mType = PORTS_SKYVIEWPOINT; + level.sectorPortals[i].mFlags = actor->GetClass()->IsDescendantOf(PClass::FindActor("SkyCamCompat")) ? 0 : PORTSF_SKYFLATONLY; + level.sectorPortals[i].mSkybox = actor; + level.sectorPortals[i].mDestination = actor->Sector; return i; } +DEFINE_ACTION_FUNCTION(FSectorPortal, GetSkyboxPortal) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(actor, AActor); + ACTION_RETURN_INT(P_GetSkyboxPortal(actor)); +} //============================================================================ // // P_GetPortal @@ -677,14 +692,14 @@ unsigned P_GetSkyboxPortal(ASkyViewpoint *actor) unsigned P_GetPortal(int type, int plane, sector_t *from, sector_t *to, const DVector2 &displacement) { - unsigned i = sectorPortals.Reserve(1); - memset(§orPortals[i], 0, sizeof(sectorPortals[i])); - sectorPortals[i].mType = type; - sectorPortals[i].mPlane = plane; - sectorPortals[i].mOrigin = from; - sectorPortals[i].mDestination = to; - sectorPortals[i].mDisplacement = displacement; - sectorPortals[i].mPlaneZ = type == PORTS_LINKEDPORTAL? from->GetPlaneTexZ(plane) : FLT_MAX; + unsigned i = level.sectorPortals.Reserve(1); + memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); + level.sectorPortals[i].mType = type; + level.sectorPortals[i].mPlane = plane; + level.sectorPortals[i].mOrigin = from; + level.sectorPortals[i].mDestination = to; + level.sectorPortals[i].mDisplacement = displacement; + level.sectorPortals[i].mPlaneZ = type == PORTS_LINKEDPORTAL? from->GetPlaneTexZ(plane) : FLT_MAX; return i; } @@ -698,14 +713,14 @@ unsigned P_GetPortal(int type, int plane, sector_t *from, sector_t *to, const DV unsigned P_GetStackPortal(AActor *point, int plane) { - unsigned i = sectorPortals.Reserve(1); - memset(§orPortals[i], 0, sizeof(sectorPortals[i])); - sectorPortals[i].mType = PORTS_STACKEDSECTORTHING; - sectorPortals[i].mPlane = plane; - sectorPortals[i].mOrigin = point->target->Sector; - sectorPortals[i].mDestination = point->Sector; - sectorPortals[i].mPlaneZ = FLT_MAX; - sectorPortals[i].mSkybox = point; + unsigned i = level.sectorPortals.Reserve(1); + memset(&level.sectorPortals[i], 0, sizeof(level.sectorPortals[i])); + level.sectorPortals[i].mType = PORTS_STACKEDSECTORTHING; + level.sectorPortals[i].mPlane = plane; + level.sectorPortals[i].mOrigin = point->target->Sector; + level.sectorPortals[i].mDestination = point->Sector; + level.sectorPortals[i].mPlaneZ = FLT_MAX; + level.sectorPortals[i].mSkybox = point; return i; } @@ -971,7 +986,7 @@ void P_CreateLinkedPortals() int id = 1; bool bogus = false; - for(auto &s : sectorPortals) + for(auto &s : level.sectorPortals) { if (s.mType == PORTS_LINKEDPORTAL) { diff --git a/src/portal.h b/src/portal.h index f5c8f8c88..0f2e47068 100644 --- a/src/portal.h +++ b/src/portal.h @@ -6,7 +6,6 @@ #include "m_bbox.h" struct FPortalGroupArray; -class ASkyViewpoint; struct portnode_t; //============================================================================ // @@ -237,8 +236,6 @@ struct FSectorPortal } }; -extern TArray sectorPortals; - //============================================================================ // // Functions @@ -256,7 +253,7 @@ inline int P_NumPortalGroups() { return Displacements.size; } -unsigned P_GetSkyboxPortal(ASkyViewpoint *actor); +unsigned P_GetSkyboxPortal(AActor *actor); unsigned P_GetPortal(int type, int plane, sector_t *orgsec, sector_t *destsec, const DVector2 &displacement); unsigned P_GetStackPortal(AActor *point, int plane); diff --git a/src/r_defs.h b/src/r_defs.h index 0fa63382e..7f4026d41 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -291,8 +291,6 @@ protected: bool CheckTrigger(AActor *triggerer) const; }; -class ASkyViewpoint; - struct secplane_t { // the plane is defined as a*x + b*y + c*z + d = 0 @@ -924,32 +922,13 @@ public: portals[plane] = nullptr; } - FSectorPortal *GetPortal(int plane) - { - return §orPortals[Portals[plane]]; - } + FSectorPortal *GetPortal(int plane); + double GetPortalPlaneZ(int plane); + DVector2 GetPortalDisplacement(int plane); + int GetPortalType(int plane); + int GetOppositePortalGroup(int plane); - double GetPortalPlaneZ(int plane) - { - return sectorPortals[Portals[plane]].mPlaneZ; - } - - DVector2 GetPortalDisplacement(int plane) - { - return sectorPortals[Portals[plane]].mDisplacement; - } - - int GetPortalType(int plane) - { - return sectorPortals[Portals[plane]].mType; - } - - int GetOppositePortalGroup(int plane) - { - return sectorPortals[Portals[plane]].mDestination->PortalGroup; - } - - void SetVerticesDirty() + void SetVerticesDirty() { for (unsigned i = 0; i < e->vertices.Size(); i++) e->vertices[i]->dirty = true; } @@ -1311,10 +1290,7 @@ struct line_t alpha = a; } - FSectorPortal *GetTransferredPortal() - { - return portaltransferred >= sectorPortals.Size() ? (FSectorPortal*)NULL : §orPortals[portaltransferred]; - } + FSectorPortal *GetTransferredPortal(); FLinePortal *getPortal() const { diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 025b94804..7a21713a1 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -57,6 +57,7 @@ #include "r_utility.h" #include "d_player.h" #include "p_local.h" +#include "g_levellocals.h" #include "p_maputl.h" #include "math/cmath.h" diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index a8d2dc7d7..6506f303b 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -425,11 +425,27 @@ void DSeqNode::AddChoice (int seqnum, seqtype_t type) } } +DEFINE_ACTION_FUNCTION(DSeqNode, AddChoice) +{ + PARAM_SELF_PROLOGUE(DSeqNode); + PARAM_NAME(seq); + PARAM_INT(mode); + self->AddChoice(seq, seqtype_t(mode)); + return 0; +} + + FName DSeqNode::GetSequenceName () const { return Sequences[m_Sequence]->SeqName; } +DEFINE_ACTION_FUNCTION(DSeqNode, GetSequenceName) +{ + PARAM_SELF_PROLOGUE(DSeqNode); + ACTION_RETURN_INT(self->GetSequenceName().GetIndex()); +} + IMPLEMENT_CLASS(DSeqActorNode, false, true) IMPLEMENT_POINTERS_START(DSeqActorNode) @@ -869,6 +885,16 @@ DSeqNode *SN_StartSequence (AActor *actor, int sequence, seqtype_t type, int mod return NULL; } +DEFINE_ACTION_FUNCTION(AActor, StartSoundSequenceID) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_INT(seq); + PARAM_INT(type); + PARAM_INT(modenum); + PARAM_BOOL_DEF(nostop); + ACTION_RETURN_POINTER(SN_StartSequence(self, seq, seqtype_t(type), modenum, nostop)); +} + DSeqNode *SN_StartSequence (sector_t *sector, int chan, int sequence, seqtype_t type, int modenum, bool nostop) { if (!nostop) @@ -882,6 +908,17 @@ DSeqNode *SN_StartSequence (sector_t *sector, int chan, int sequence, seqtype_t return NULL; } +DEFINE_ACTION_FUNCTION(_Sector, StartSoundSequenceID) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(chan); + PARAM_INT(seq); + PARAM_INT(type); + PARAM_INT(modenum); + PARAM_BOOL_DEF(nostop); + ACTION_RETURN_POINTER(SN_StartSequence(self, chan, seq, seqtype_t(type), modenum, nostop)); +} + DSeqNode *SN_StartSequence (FPolyObj *poly, int sequence, seqtype_t type, int modenum, bool nostop) { if (!nostop) @@ -921,6 +958,15 @@ DSeqNode *SN_StartSequence (AActor *actor, FName seqname, int modenum) return NULL; } +DEFINE_ACTION_FUNCTION(AActor, StartSoundSequence) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_NAME(seq); + PARAM_INT(modenum); + ACTION_RETURN_POINTER(SN_StartSequence(self, seq, modenum)); +} + + DSeqNode *SN_StartSequence (sector_t *sec, int chan, const char *seqname, int modenum) { int seqnum = FindSequence(seqname); @@ -941,6 +987,15 @@ DSeqNode *SN_StartSequence (sector_t *sec, int chan, FName seqname, int modenum) return NULL; } +DEFINE_ACTION_FUNCTION(_Sector, StartSoundSequence) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(chan); + PARAM_NAME(seq); + PARAM_INT(modenum); + ACTION_RETURN_POINTER(SN_StartSequence(self, chan, seq, modenum)); +} + DSeqNode *SN_StartSequence (FPolyObj *poly, const char *seqname, int modenum) { int seqnum = FindSequence(seqname); @@ -1001,6 +1056,13 @@ DSeqNode *SN_CheckSequence(sector_t *sector, int chan) return NULL; } +DEFINE_ACTION_FUNCTION(_Sector, CheckSoundSequence) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(chan); + ACTION_RETURN_POINTER(SN_CheckSequence(self, chan)); +} + //========================================================================== // // SN_StopSequence @@ -1012,6 +1074,13 @@ void SN_StopSequence (AActor *actor) SN_DoStop (actor); } +DEFINE_ACTION_FUNCTION(AActor, StopSoundSequence) +{ + PARAM_SELF_PROLOGUE(AActor); + SN_StopSequence(self); + return 0; +} + void SN_StopSequence (sector_t *sector, int chan) { DSeqNode *node = SN_CheckSequence(sector, chan); @@ -1021,6 +1090,15 @@ void SN_StopSequence (sector_t *sector, int chan) } } +DEFINE_ACTION_FUNCTION(_Sector, StopSoundSequence) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + PARAM_INT(chan); + SN_StopSequence(self, chan); + return 0; +} + + void SN_StopSequence (FPolyObj *poly) { SN_DoStop (poly); @@ -1090,6 +1168,13 @@ bool SN_IsMakingLoopingSound (sector_t *sector) return false; } +DEFINE_ACTION_FUNCTION(_Sector, IsMakingLoopingSound) +{ + PARAM_SELF_STRUCT_PROLOGUE(sector_t); + ACTION_RETURN_BOOL(SN_IsMakingLoopingSound(self)); +} + + //========================================================================== // // SN_UpdateActiveSequences @@ -1325,6 +1410,15 @@ FName SN_GetSequenceSlot (int sequence, seqtype_t type) return NAME_None; } +DEFINE_ACTION_FUNCTION(DSeqNode, GetSequenceSlot) +{ + PARAM_PROLOGUE; + PARAM_INT(seq); + PARAM_INT(type); + ACTION_RETURN_INT(SN_GetSequenceSlot(seq, seqtype_t(type)).GetIndex()); +} + + //========================================================================== // // SN_MarkPrecacheSounds @@ -1351,6 +1445,16 @@ void SN_MarkPrecacheSounds(int sequence, seqtype_t type) } } +DEFINE_ACTION_FUNCTION(DSeqNode, MarkPrecacheSounds) +{ + PARAM_PROLOGUE; + PARAM_INT(seq); + PARAM_INT(type); + SN_MarkPrecacheSounds(seq, seqtype_t(type)); + return 0; +} + + //========================================================================== // // SN_ChangeNodeData @@ -1462,7 +1566,16 @@ bool SN_AreModesSame(int seqnum, seqtype_t type, int mode1, int mode2) return true; } -bool SN_AreModesSame(const char *name, int mode1, int mode2) +DEFINE_ACTION_FUNCTION(DSeqNode, AreModesSameID) +{ + PARAM_SELF_PROLOGUE(DSeqNode); + PARAM_INT(seqnum); + PARAM_INT(type); + PARAM_INT(mode); + ACTION_RETURN_BOOL(SN_AreModesSame(seqnum, seqtype_t(type), mode, self->GetModeNum())); +} + +bool SN_AreModesSame(FName name, int mode1, int mode2) { int seqnum = FindSequence(name); if (seqnum >= 0) @@ -1473,6 +1586,14 @@ bool SN_AreModesSame(const char *name, int mode1, int mode2) return true; } +DEFINE_ACTION_FUNCTION(DSeqNode, AreModesSame) +{ + PARAM_SELF_PROLOGUE(DSeqNode); + PARAM_NAME(seq); + PARAM_INT(mode); + ACTION_RETURN_BOOL(SN_AreModesSame(seq, mode, self->GetModeNum())); +} + //========================================================================== // // CCMD playsequence diff --git a/src/s_sndseq.h b/src/s_sndseq.h index 57e21caa1..a35fab026 100644 --- a/src/s_sndseq.h +++ b/src/s_sndseq.h @@ -20,7 +20,7 @@ class DSeqNode : public DObject DECLARE_CLASS (DSeqNode, DObject) HAS_OBJECT_POINTERS public: - void Serialize(FSerializer &arc); + void Serialize(FSerializer &arc) override; void StopAndDestroy (); void OnDestroy() override; void Tick (); @@ -91,7 +91,7 @@ void SN_StopSequence (AActor *mobj); void SN_StopSequence (sector_t *sector, int chan); void SN_StopSequence (FPolyObj *poly); bool SN_AreModesSame(int sequence, seqtype_t type, int mode1, int mode2); -bool SN_AreModesSame(const char *name, int mode1, int mode2); +bool SN_AreModesSame(FName name, int mode1, int mode2); void SN_UpdateActiveSequences (void); ptrdiff_t SN_GetSequenceOffset (int sequence, SDWORD *sequencePtr); void SN_DoStop (void *); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 3a9ae5ea1..856156322 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -54,6 +54,7 @@ #include "d_player.h" #include "r_state.h" #include "g_levellocals.h" +#include "virtual.h" // MACROS ------------------------------------------------------------------ @@ -479,7 +480,16 @@ void S_PrecacheLevel () // Precache all sounds known to be used by the currently spawned actors. while ( (actor = iterator.Next()) != NULL ) { - actor->MarkPrecacheSounds(); + IFVIRTUALPTR(actor, AActor, MarkPrecacheSounds) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { actor }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } + else + { + actor->MarkPrecacheSounds(); + } } for (auto i : gameinfo.PrecachedSounds) { diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 8e4b42f69..31a9c022f 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -146,7 +146,7 @@ std2: 'instanceof' { RET(TK_InstanceOf); } 'auto' { RET(TK_Auto); } 'exec' { RET(TK_Exec); } - 'defaultproperties' { RET(TK_DefaultProperties); } + 'property' { RET(TK_Property); } 'native' { RET(TK_Native); } 'var' { RET(TK_Var); } 'out' { RET(TK_Out); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index efa479cf3..fb8f1c5ae 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -67,6 +67,7 @@ xx(TK_Long, "'long'") xx(TK_ULong, "'ulong'") xx(TK_Void, "'void'") xx(TK_Struct, "'struct'") +xx(TK_Property, "'property'") xx(TK_Class, "'class'") xx(TK_Enum, "'enum'") xx(TK_Name, "'name'") diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index fd86299dc..1eefba216 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -208,10 +208,6 @@ ExpEmit::ExpEmit(VMFunctionBuilder *build, int type, int count) void ExpEmit::Free(VMFunctionBuilder *build) { - if (RegType == REGT_INT && RegNum == 0) - { - int a = 0; - } if (!Fixed && !Konst && RegType <= REGT_TYPE) { build->Registers[RegType].Return(RegNum, RegCount); @@ -1620,6 +1616,17 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx) if (fromtype->IsDescendantOf(totype)) goto basereturn; } } + else if (basex->ValueType->IsA(RUNTIME_CLASS(PNativeStruct)) && ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(ValueType)->PointedType == basex->ValueType) + { + bool writable; + basex->RequestAddress(ctx, &writable); + basex->ValueType = ValueType; + auto x = basex; + basex = nullptr; + delete this; + return x; + } + else if (AreCompatiblePointerTypes(ValueType, basex->ValueType)) { goto basereturn; @@ -2669,7 +2676,11 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) return nullptr; } - if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant()) + if (left->ValueType == TypeTextureID && right->IsInteger()) + { + ValueType = TypeTextureID; + } + else if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant()) { // This is the only special case of pointer addition that will be accepted - because it is used quite often in the existing game code. ValueType = TypeState; @@ -2748,6 +2759,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) assert(Operator == '+' || Operator == '-'); ExpEmit op1 = left->Emit(build); ExpEmit op2 = right->Emit(build); + ExpEmit to; if (Operator == '+') { if (op1.RegType == REGT_POINTER) @@ -2768,7 +2780,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) assert(!op1.Konst); op1.Free(build); op2.Free(build); - ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + to = ExpEmit(build, ValueType->GetRegType(), ValueType->GetRegCount()); if (IsVector()) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); @@ -2791,6 +2803,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) assert(ValueType->GetRegType() == REGT_INT); assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum); + if (ValueType == TypeTextureID) goto texcheck; return to; } } @@ -2800,7 +2813,7 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) assert(!op1.Konst || !op2.Konst); op1.Free(build); op2.Free(build); - ExpEmit to(build, ValueType->GetRegType(), ValueType->GetRegCount()); + to = ExpEmit(build, ValueType->GetRegType(), ValueType->GetRegCount()); if (IsVector()) { assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT); @@ -2818,9 +2831,23 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) assert(ValueType->GetRegType() == REGT_INT); assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT); build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR, to.RegNum, op1.RegNum, op2.RegNum); + if (ValueType == TypeTextureID) goto texcheck; return to; } } + +texcheck: + // Do a bounds check for the texture index. Note that count can change at run time so this needs to read the value from the texture manager. + auto * ptr = (FArray*)&TexMan.Textures; + auto * countptr = &ptr->Count; + ExpEmit bndp(build, REGT_POINTER); + ExpEmit bndc(build, REGT_INT); + build->Emit(OP_LKP, bndp.RegNum, build->GetConstantAddress(countptr, ATAG_GENERIC)); + build->Emit(OP_LW, bndc.RegNum, bndp.RegNum, build->GetConstantInt(0)); + build->Emit(OP_BOUND_R, to.RegNum, bndc.RegNum); + bndp.Free(build); + bndc.Free(build); + return to; } //========================================================================== @@ -4436,10 +4463,6 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); SAFE_RESOLVE(expr, ctx); - if (expr->ExprType == EFX_GetDefaultByType) - { - int a = 0; - } bool constflag = expr->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast(expr->ValueType)->IsConst; if (constflag) { @@ -6461,7 +6484,7 @@ FxStructMember::~FxStructMember() bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable) { // Cannot take the address of metadata variables. - if (membervar->Flags & VARF_Static) + if (membervar->Flags & VARF_Meta) { return false; } @@ -6604,7 +6627,7 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) obj = newobj; } - if (membervar->Flags & VARF_Static) + if (membervar->Flags & VARF_Meta) { obj.Free(build); ExpEmit meta(build, REGT_POINTER); @@ -6747,12 +6770,12 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) { auto parentfield = static_cast(Array)->membervar; - SizeAddr = unsigned(parentfield->Offset + parentfield->Type->Align); + SizeAddr = parentfield->Offset + parentfield->Type->Align; } else if (Array->ExprType == EFX_GlobalVariable) { auto parentfield = static_cast(Array)->membervar; - SizeAddr = unsigned(parentfield->Offset + parentfield->Type->Align); + SizeAddr = parentfield->Offset + parentfield->Type->Align; } else { @@ -6836,12 +6859,16 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { arraytype = static_cast(Array->ValueType); } - ExpEmit start = Array->Emit(build); + ExpEmit arrayvar = Array->Emit(build); + ExpEmit start; ExpEmit bound; - // For resizable arrays we even need to check the bounds if if the index is constant. if (SizeAddr != ~0u) { + arrayvar.Free(build); + start = ExpEmit(build, REGT_POINTER); + build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0)); + auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr); if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember) { @@ -6857,12 +6884,14 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) Array->ValueType = TypeUInt32; bound = Array->Emit(build); } + else start = arrayvar; if (index->isConstant()) { unsigned indexval = static_cast(index)->GetValue().GetInt(); assert(SizeAddr != ~0u || (indexval < arraytype->ElementCount && "Array index out of bounds")); + // For resizable arrays we even need to check the bounds if if the index is constant because they are not known at compile time. if (SizeAddr != ~0u) { ExpEmit indexreg(build, REGT_INT); @@ -6948,19 +6977,11 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) if (AddressRequested) { - if (!start.Fixed) - { - build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); - } - else - { - start.Free(build); - // do not clobber local variables. - ExpEmit temp(build, start.RegType); - build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); - start = temp; - } - return start; + start.Free(build); + // do not clobber local variables. + ExpEmit temp(build, start.RegType); + build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); + return temp; } else { @@ -7256,6 +7277,13 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) } break; + case NAME_GetParentClass: + if (CheckArgSize(NAME_GetParentClass, ArgList, 0, 0, ScriptPosition)) + { + func = new FxGetParentClass(new FxSelf(ScriptPosition)); + } + break; + case NAME_GetDefaultByType: if (CheckArgSize(NAME_GetDefaultByType, ArgList, 1, 1, ScriptPosition)) { @@ -7422,7 +7450,28 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) { cls = ccls; staticonly = true; - goto isresolved; + if (ccls->IsKindOf(RUNTIME_CLASS(PClass))) + { + auto clstype = dyn_cast(ctx.Function->Variants[0].SelfClass); + if (clstype != nullptr) + { + novirtual = clstype->IsDescendantOf(static_cast(ccls)); + if (novirtual) + { + bool error; + PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error); + if ((afd->Variants[0].Flags & VARF_Method) && (afd->Variants[0].Flags & VARF_Virtual)) + { + staticonly = false; + novirtual = true; + delete Self; + Self = new FxSelf(ScriptPosition); + Self->ValueType = NewPointer(cls); + } + } + } + } + if (!novirtual) goto isresolved; } } } @@ -7510,6 +7559,13 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) else if (Self->ValueType == TypeString) { + if (MethodName == NAME_Length) // This is an intrinsic because a dedicated opcode exists for it. + { + auto x = new FxStrLen(Self); + Self = nullptr; + delete this; + return x->Resolve(ctx); + } // same for String methods. It also uses a hidden struct type to define them. Self->ValueType = TypeStringStruct; } @@ -7566,6 +7622,20 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } } + + if (MethodName == NAME_GetParentClass && + (Self->IsObject() || Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))) + { + if (ArgList.Size() > 0) + { + ScriptPosition.Message(MSG_ERROR, "too many parameters in call to %s", MethodName.GetChars()); + delete this; + return nullptr; + } + auto x = new FxGetParentClass(Self); + return x->Resolve(ctx); + } + if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) { auto ptype = static_cast(Self->ValueType)->PointedType; @@ -7582,6 +7652,8 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) auto x = new FxGetClass(Self); return x->Resolve(ctx); } + + cls = static_cast(ptype); } else @@ -7634,20 +7706,23 @@ isresolved: if (staticonly && (afd->Variants[0].Flags & VARF_Method)) { - auto clstype = dyn_cast(ctx.Class); - auto ccls = dyn_cast(cls); - if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls)) + if (!novirtual || !(afd->Variants[0].Flags & VARF_Virtual)) { - ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here\n", cls->TypeName.GetChars(), MethodName.GetChars()); - delete this; - return nullptr; - } - else - { - // Todo: If this is a qualified call to a parent class function, let it through (but this needs to disable virtual calls later.) - ScriptPosition.Message(MSG_ERROR, "Qualified member call to parent class %s::%s is not yet implemented\n", cls->TypeName.GetChars(), MethodName.GetChars()); - delete this; - return nullptr; + auto clstype = dyn_cast(ctx.Class); + auto ccls = dyn_cast(cls); + if (clstype == nullptr || ccls == nullptr || !clstype->IsDescendantOf(ccls)) + { + ScriptPosition.Message(MSG_ERROR, "Cannot call non-static function %s::%s from here\n", cls->TypeName.GetChars(), MethodName.GetChars()); + delete this; + return nullptr; + } + else + { + // Todo: If this is a qualified call to a parent class function, let it through (but this needs to disable virtual calls later.) + ScriptPosition.Message(MSG_ERROR, "Qualified member call to parent class %s::%s is not yet implemented\n", cls->TypeName.GetChars(), MethodName.GetChars()); + delete this; + return nullptr; + } } } @@ -8485,7 +8560,7 @@ static int BuiltinFormat(VMValue *args, TArray &defaultparam, int numpa // various type flags are not supported. not like stuff like 'hh' modifier is to be used in the VM. // the only combination that is parsed locally is %n$... bool haveargnums = false; - for (int i = 0; i < fmtstring.Len(); i++) + for (size_t i = 0; i < fmtstring.Len(); i++) { char c = fmtstring[i]; if (in_fmt) @@ -8703,6 +8778,39 @@ ExpEmit FxVectorBuiltin::Emit(VMFunctionBuilder *build) // //========================================================================== +FxStrLen::FxStrLen(FxExpression *self) + :FxExpression(EFX_StrLen, self->ScriptPosition) +{ + Self = self; +} + +FxStrLen::~FxStrLen() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxStrLen::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + assert(Self->ValueType == TypeString); + ValueType = TypeUInt32; + return this; +} + +ExpEmit FxStrLen::Emit(VMFunctionBuilder *build) +{ + ExpEmit to(build, REGT_INT); + ExpEmit op = Self->Emit(build); + build->Emit(OP_LENS, to.RegNum, op.RegNum); + op.Free(build); + return to; +} + +//========================================================================== +// +// +//========================================================================== + FxGetClass::FxGetClass(FxExpression *self) :FxExpression(EFX_GetClass, self->ScriptPosition) { @@ -8741,6 +8849,52 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build) // //========================================================================== +FxGetParentClass::FxGetParentClass(FxExpression *self) + :FxExpression(EFX_GetParentClass, self->ScriptPosition) +{ + Self = self; +} + +FxGetParentClass::~FxGetParentClass() +{ + SAFE_DELETE(Self); +} + +FxExpression *FxGetParentClass::Resolve(FCompileContext &ctx) +{ + SAFE_RESOLVE(Self, ctx); + + if (!Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && !Self->IsObject()) + { + ScriptPosition.Message(MSG_ERROR, "GetClass() requires an object"); + delete this; + return nullptr; + } + ValueType = NewClassPointer(RUNTIME_CLASS(DObject)); // + return this; +} + +ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build) +{ + ExpEmit op = Self->Emit(build); + op.Free(build); + if (Self->IsObject()) + { + ExpEmit to(build, REGT_POINTER); + build->Emit(OP_META, to.RegNum, op.RegNum); + op = to; + op.Free(build); + } + ExpEmit to(build, REGT_POINTER); + build->Emit(OP_LO, to.RegNum, op.RegNum, build->GetConstantInt(myoffsetof(PClass, ParentClass))); + return to; +} + +//========================================================================== +// +// +//========================================================================== + FxGetDefaultByType::FxGetDefaultByType(FxExpression *self) :FxExpression(EFX_GetDefaultByType, self->ScriptPosition) { diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 7e72176e7..e7cfab662 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -289,6 +289,8 @@ enum EFxType EFX_CVar, EFX_NamedNode, EFX_GetClass, + EFX_GetParentClass, + EFX_StrLen, EFX_ColorLiteral, EFX_GetDefaultByType, EFX_COUNT @@ -1438,7 +1440,7 @@ class FxArrayElement : public FxExpression public: FxExpression *Array; FxExpression *index; - unsigned SizeAddr; + size_t SizeAddr; bool AddressRequested; bool AddressWritable; bool arrayispointer = false; @@ -1571,6 +1573,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxVectorBuiltin +// +//========================================================================== + +class FxStrLen : public FxExpression +{ + FxExpression *Self; + +public: + + FxStrLen(FxExpression *self); + ~FxStrLen(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxGetClass @@ -1589,6 +1609,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxGetClass +// +//========================================================================== + +class FxGetParentClass : public FxExpression +{ + FxExpression *Self; + +public: + + FxGetParentClass(FxExpression *self); + ~FxGetParentClass(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxGetDefaultByType diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 9c9659356..a3f5c144c 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -472,7 +472,7 @@ static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 }, - { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs), 3 }, + { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs), 1 }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -738,6 +738,9 @@ void InitThingdef() vertstruct->Size = sizeof(vertex_t); vertstruct->Align = alignof(vertex_t); + auto sectorportalstruct = NewNativeStruct("SectorPortal", nullptr); + sectorportalstruct->Size = sizeof(FSectorPortal); + sectorportalstruct->Align = alignof(FSectorPortal); // set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well... // As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up. @@ -762,11 +765,17 @@ void InitThingdef() PField *levelf = new PField("level", lstruct, VARF_Native | VARF_Static, (intptr_t)&level); GlobalSymbols.AddSymbol(levelf); - // Add the sector array to LevelLocals. + // Add the game data arrays to LevelLocals. lstruct->AddNativeField("sectors", NewPointer(NewResizableArray(sectorstruct), false), myoffsetof(FLevelLocals, sectors), VARF_Native); lstruct->AddNativeField("lines", NewPointer(NewResizableArray(linestruct), false), myoffsetof(FLevelLocals, lines), VARF_Native); lstruct->AddNativeField("sides", NewPointer(NewResizableArray(sidestruct), false), myoffsetof(FLevelLocals, sides), VARF_Native); lstruct->AddNativeField("vertexes", NewPointer(NewResizableArray(vertstruct), false), myoffsetof(FLevelLocals, vertexes), VARF_Native|VARF_ReadOnly); + lstruct->AddNativeField("sectorportals", NewPointer(NewResizableArray(sectorportalstruct), false), myoffsetof(FLevelLocals, sectorPortals), VARF_Native); + + + auto aact = NewPointer(NewResizableArray(NewClassPointer(RUNTIME_CLASS(AActor))), true); + PField *aacf = new PField("AllActorClasses", aact, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&PClassActor::AllActorClasses); + GlobalSymbols.AddSymbol(aacf); // set up a variable for the DEH data PStruct *dstruct = NewNativeStruct("DehInfo", nullptr); @@ -905,7 +914,10 @@ DEFINE_ACTION_FUNCTION(FStringTable, Localize) { PARAM_PROLOGUE; PARAM_STRING(label); - ACTION_RETURN_STRING(GStrings(label)); + PARAM_BOOL_DEF(prefixed); + if (!prefixed) ACTION_RETURN_STRING(GStrings(label)); + if (label[0] != '$') ACTION_RETURN_STRING(label); + ACTION_RETURN_STRING(GStrings(&label[1])); } DEFINE_ACTION_FUNCTION(FString, Replace) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 32f7dd622..db24349cb 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -71,7 +71,6 @@ #include "a_weaponpiece.h" #include "vmbuilder.h" #include "a_ammo.h" -#include "a_health.h" #include "a_keys.h" #include "g_levellocals.h" @@ -1969,46 +1968,6 @@ DEFINE_CLASS_PROPERTY(givequest, I, Inventory) static_cast(info)->GiveQuest = i; } -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY(lowmessage, IT, Health) -{ - PROP_INT_PARM(i, 0); - PROP_STRING_PARM(str, 1); - assert(info->IsKindOf(RUNTIME_CLASS(PClassHealth))); - static_cast(info)->LowHealth = i; - static_cast(info)->LowHealthMessage = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY(autouse, I, HealthPickup) -{ - PROP_INT_PARM(i, 0); - defaults->autousemode = i; -} - -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY(number, I, PuzzleItem) -{ - PROP_INT_PARM(i, 0); - defaults->PuzzleItemNumber = i; -} - -//========================================================================== -// -//========================================================================== -DEFINE_CLASS_PROPERTY(failmessage, T, PuzzleItem) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassPuzzleItem))); - static_cast(info)->PuzzFailMessage = str; -} - //========================================================================== // //========================================================================== diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 1d685c69c..51c224649 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -399,21 +399,30 @@ begin: reg.s[a] = reg.s[B]; NEXTOP; OP(MOVEA): + { ASSERTA(a); ASSERTA(B); - reg.a[a] = reg.a[B]; - reg.atag[a] = reg.atag[B]; + int b = B; + reg.a[a] = reg.a[b]; + reg.atag[a] = reg.atag[b]; NEXTOP; + } OP(MOVEV2): + { ASSERTF(a); ASSERTF(B); - reg.f[a] = reg.f[B]; - reg.f[a+1] = reg.f[B+1]; + int b = B; + reg.f[a] = reg.f[b]; + reg.f[a + 1] = reg.f[b + 1]; NEXTOP; + } OP(MOVEV3): + { ASSERTF(a); ASSERTF(B); - reg.f[a] = reg.f[B]; - reg.f[a+1] = reg.f[B+1]; - reg.f[a+2] = reg.f[B+2]; + int b = B; + reg.f[a] = reg.f[b]; + reg.f[a + 1] = reg.f[b + 1]; + reg.f[a + 2] = reg.f[b + 2]; NEXTOP; + } OP(DYNCAST_R) : ASSERTA(a); ASSERTA(B); ASSERTA(C); b = B; diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index 3bdc2e244..b29e1eeb2 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -336,6 +336,16 @@ static void PrintStruct(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintProperty(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_Property *snode = (ZCC_Property *)node; + out.Break(); + out.Open("property"); + out.AddName(snode->NodeName); + PrintNodes(out, snode->Body, false, true); + out.Close(); +} + static void PrintEnum(FLispString &out, ZCC_TreeNode *node) { ZCC_Enum *enode = (ZCC_Enum *)node; @@ -934,6 +944,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintVectorInitializer, PrintDeclFlags, PrintExprClassCast, + PrintProperty, }; FString ZCC_PrintAST(ZCC_TreeNode *root) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 9305b9f71..d0ff03625 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -209,7 +209,6 @@ class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ } class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; } class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; } class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; } -class_flags(X) ::= class_flags(A) ACTION. { X.Flags = A.Flags | ZCC_Action; X.Replaces = A.Replaces; } class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; } /*----- Dottable Identifier -----*/ @@ -265,6 +264,7 @@ class_body(X) ::= LBRACE class_innards(A) RBRACE. { X = A; /*X-overwrites-A*/ } class_innards(X) ::= . { X = NULL; } class_innards(X) ::= class_innards(X) class_member(B). { SAFE_APPEND(X,B); } +%type property_def{ZCC_Property *} %type struct_def{ZCC_Struct *} %type enum_def {ZCC_Enum *} %type states_def {ZCC_States *} @@ -276,6 +276,7 @@ class_member(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ } class_member(X) ::= states_def(A). { X = A; /*X-overwrites-A*/ } class_member(X) ::= default_def(A). { X = A; /*X-overwrites-A*/ } class_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } +class_member(X) ::= property_def(A). { X = A; /*X-overwrites-A*/ } /*----- Struct Definition -----*/ /* Structs can define variables and enums. */ @@ -283,6 +284,30 @@ class_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ } %type opt_struct_body{ZCC_TreeNode *} %type struct_body{ZCC_TreeNode *} %type struct_member{ZCC_TreeNode *} +%type identifier_list{ZCC_Identifier *} + +property_def(X) ::= PROPERTY(T) IDENTIFIER(A) COLON identifier_list(B) SEMICOLON. +{ + NEW_AST_NODE(Property,def,T); + def->NodeName = A.Name(); + def->Body = B; + X = def; +} + +identifier_list(X) ::= IDENTIFIER(A). +{ + NEW_AST_NODE(Identifier,id,A); + id->Id = A.Name(); + X = id; +} + +identifier_list(X) ::= states_opt(A) COMMA IDENTIFIER(B). +{ + NEW_AST_NODE(Identifier,id,B); + id->Id = B.Name(); + X = A; /*X-overwrites-A*/ + AppendTreeNodeSibling(X, id); +} struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body(B) RBRACE opt_semicolon. { @@ -747,7 +772,7 @@ type_name(X) ::= DOT dottable_id(A). /* Type names can also be used as identifiers in contexts where type names * are not normally allowed. */ %fallback IDENTIFIER - SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16. + SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16 PROPERTY. /* Aggregate types */ %type aggregate_type {ZCC_Type *} @@ -964,6 +989,7 @@ decl_flag(X) ::= PROTECTED(T). { X.Int = ZCC_Protected; X.SourceLoc = T.SourceL decl_flag(X) ::= LATENT(T). { X.Int = ZCC_Latent; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; } +decl_flag(X) ::= TRANSIENT(T). { X.Int = ZCC_Transient; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; } decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; } diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 13a21eb88..281f707d2 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -120,6 +120,10 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode) } break; + case AST_Property: + cls->Properties.Push(static_cast(node)); + break; + case AST_VarDeclarator: cls->Fields.Push(static_cast(node)); break; @@ -396,6 +400,7 @@ int ZCCCompiler::Compile() CreateStructTypes(); CompileAllConstants(); CompileAllFields(); + CompileAllProperties(); InitDefaults(); InitFunctions(); CompileStates(); @@ -1269,6 +1274,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (field->Flags & ZCC_Protected) varflags |= VARF_Protected; if (field->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated; if (field->Flags & ZCC_ReadOnly) varflags |= VARF_ReadOnly; + if (field->Flags & ZCC_Transient) varflags |= VARF_Transient; if (field->Flags & ZCC_Native) { @@ -1277,7 +1283,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (field->Flags & ZCC_Meta) { - varflags |= VARF_Static|VARF_ReadOnly; // metadata implies readonly + varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly if (!(field->Flags & ZCC_Native)) { // Non-native meta data is not implemented yet and requires some groundwork in the class copy code. @@ -1303,7 +1309,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (varflags & VARF_Native) { - auto querytype = (varflags & VARF_Static) ? type->GetClass() : type; + auto querytype = (varflags & VARF_Meta) ? type->GetClass() : type; fd = FindField(querytype, FName(name->Name).GetChars()); if (fd == nullptr) { @@ -1337,6 +1343,68 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel return Fields.Size() == 0; } +//========================================================================== +// +// ZCCCompiler :: CompileAllProperties +// +// builds the property lists of all actor classes +// +//========================================================================== + +void ZCCCompiler::CompileAllProperties() +{ + for (auto c : Classes) + { + if (c->Properties.Size() > 0) + CompileProperties(c->Type(), c->Properties, c->Type()->TypeName); + } +} + +//========================================================================== +// +// ZCCCompiler :: CompileProperties +// +// builds the internal structure of a single class or struct +// +//========================================================================== + +bool ZCCCompiler::CompileProperties(PClass *type, TArray &Properties, FName prefix) +{ + if (!type->IsKindOf(RUNTIME_CLASS(PClassActor))) + { + Error(Properties[0], "Properties can only be defined for actors"); + return false; + } + for(auto p : Properties) + { + TArray fields; + ZCC_Identifier *id = (ZCC_Identifier *)p->Body; + + do + { + auto f = dyn_cast(type->Symbols.FindSymbol(id->Id, true)); + if (f == nullptr) + { + Error(id, "Variable %s not found in %s", FName(id->Id).GetChars(), type->TypeName.GetChars()); + } + fields.Push(f); + id = (ZCC_Identifier*)id->SiblingNext; + } while (id != p->Body); + + FString qualifiedname; + // Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen. + // All these will be removed from the symbol table after the compiler finishes to free up the allocated space. + if (prefix == NAME_None) qualifiedname.Format("@property@%s", FName(p->NodeName).GetChars()); + else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), FName(p->NodeName).GetChars()); + fields.ShrinkToFit(); + if (!type->Symbols.AddSymbol(new PProperty(qualifiedname, fields))) + { + Error(id, "Unable to add property %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars()); + } + } + return true; +} + //========================================================================== // // ZCCCompiler :: FieldFlagsToString @@ -1841,6 +1909,73 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper } } + +//========================================================================== +// +// Parses an actor property's parameters and calls the handler +// +//========================================================================== + +void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag) +{ + unsigned parmcount = 1; + ZCC_TreeNode *x = property->Values; + while (x->SiblingNext != property->Values) + { + x = x->SiblingNext; + parmcount++; + } + if (parmcount != prop->Variables.Size()) + { + Error(x, "Argument count mismatch: Got %u, expected %u", parmcount, prop->Variables.Size()); + return; + } + + auto values = Simplify(property->Values, &bag.Info->Symbols, true); // need to do this before the loop so that we can find the head node again. + auto exp = values; + for (auto f : prop->Variables) + { + void *addr; + + if (f->Flags & VARF_Meta) + { + addr = ((char*)bag.Info) + f->Offset; + } + else + { + addr = ((char*)defaults) + f->Offset; + } + + if (f->Type->IsKindOf(RUNTIME_CLASS(PInt))) + { + static_cast(f->Type)->SetValue(addr, GetInt(exp)); + } + else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat))) + { + static_cast(f->Type)->SetValue(addr, GetDouble(exp)); + } + else if (f->Type->IsKindOf(RUNTIME_CLASS(PString))) + { + *(FString*)addr = GetString(exp); + } + else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer))) + { + auto cls = PClass::FindClass(GetString(exp)); + *(PClass**)addr = cls; + if (!cls->IsDescendantOf(static_cast(f->Type)->ClassRestriction)) + { + Error(property, "class %s is not compatible with property type %s", cls->TypeName.GetChars(), static_cast(f->Type)->ClassRestriction->TypeName.GetChars()); + } + } + else + { + Error(property, "unhandled property type %s", f->Type->DescriptiveName()); + } + exp->ToErrorNode(); // invalidate after processing. + exp = static_cast(exp->SiblingNext); + } +} + //========================================================================== // // Parses an actor property @@ -1893,6 +2028,17 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro } else { + propname.Insert(0, "@property@"); + FName name(propname, true); + if (name != NAME_None) + { + auto propp = dyn_cast(cls->Symbols.FindSymbol(name, true)); + if (propp != nullptr) + { + DispatchScriptProperty(propp, prop, (AActor *)bag.Info->Defaults, bag); + return; + } + } Error(prop, "'%s' is an unknown actor property\n", propname.GetChars()); } } @@ -2306,19 +2452,6 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool unsigned vindex = ~0u; if (virtsym != nullptr) vindex = virtsym->Variants[0].Implementation->VirtualIndex; - if (vindex != ~0u || (varflags & VARF_Virtual)) - { - // Todo: Check if the declaration is legal. - - // First step: compare prototypes - if they do not match the virtual base method does not apply. - - // Second step: Check flags. Possible cases: - // 1. Base method is final: Error. - // 2. This method is override: Base virtual method must exist - // 3. This method is virtual but not override: Base may not have a virtual method with the same prototype. - } - - if (!(f->Flags & ZCC_Native)) { if (f->Body == nullptr) diff --git a/src/scripting/zscript/zcc_compile.h b/src/scripting/zscript/zcc_compile.h index f9ebc62d4..8675b1af7 100644 --- a/src/scripting/zscript/zcc_compile.h +++ b/src/scripting/zscript/zcc_compile.h @@ -51,6 +51,7 @@ struct ZCC_ClassWork : public ZCC_StructWork ZCC_Class *cls; TArray Defaults; TArray States; + TArray Properties; ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n) { @@ -67,6 +68,12 @@ struct ZCC_ClassWork : public ZCC_StructWork } }; +struct ZCC_PropertyWork +{ + ZCC_Property *prop; + PSymbolTable *outputtable; +}; + struct ZCC_ConstantWork { ZCC_ConstantDef *node; @@ -92,6 +99,8 @@ private: void CompileAllFields(); bool CompileFields(PStruct *type, TArray &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false); + void CompileAllProperties(); + bool CompileProperties(PClass *type, TArray &Properties, FName prefix); FString FlagsToString(uint32_t flags); PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember); PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym); @@ -101,6 +110,7 @@ private: void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg); void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag); void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); + void DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag); int GetInt(ZCC_Expression *expr); double GetDouble(ZCC_Expression *expr); const char *GetString(ZCC_Expression *expr, bool silent = false); @@ -114,6 +124,7 @@ private: TArray Constants; TArray Structs; TArray Classes; + TArray Properties; PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false); diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 07cc695d8..a0ecbe06c 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -144,6 +144,8 @@ static void InitTokenMap() TOKENDEF ('{', ZCC_LBRACE); TOKENDEF ('}', ZCC_RBRACE); TOKENDEF (TK_Struct, ZCC_STRUCT); + TOKENDEF (TK_Property, ZCC_PROPERTY); + TOKENDEF (TK_Transient, ZCC_TRANSIENT); TOKENDEF (TK_Enum, ZCC_ENUM); TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sByte); TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte); diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index d02b1a12f..19c327fc9 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -35,6 +35,7 @@ enum ZCC_Extension = 1 << 12, ZCC_Virtual = 1 << 13, ZCC_Override = 1 << 14, + ZCC_Transient = 1 << 15, }; // Function parameter modifiers @@ -104,6 +105,7 @@ enum EZCCTreeNodeType AST_DeclFlags, AST_ClassCast, AST_StaticArrayStatement, + AST_Property, NUM_AST_NODE_TYPES }; @@ -189,6 +191,11 @@ struct ZCC_Struct : ZCC_NamedNode PStruct *Type; }; +struct ZCC_Property : ZCC_NamedNode +{ + ZCC_TreeNode *Body; +}; + struct ZCC_Class : ZCC_Struct { ZCC_Identifier *ParentName; diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp index af25166bc..51eeb76ff 100644 --- a/src/swrenderer/line/r_line.cpp +++ b/src/swrenderer/line/r_line.cpp @@ -28,6 +28,7 @@ #include "a_sharedglobal.h" #include "d_net.h" #include "g_level.h" +#include "g_levellocals.h" #include "r_wallsetup.h" #include "v_palette.h" #include "r_utility.h" diff --git a/src/swrenderer/plane/r_visibleplane.h b/src/swrenderer/plane/r_visibleplane.h index 262d9c4c1..f905a4758 100644 --- a/src/swrenderer/plane/r_visibleplane.h +++ b/src/swrenderer/plane/r_visibleplane.h @@ -16,7 +16,6 @@ #include #include "r_defs.h" -class ASkyViewpoint; class ADynamicLight; struct FLightNode; struct FDynamicColormap; diff --git a/src/swrenderer/scene/r_portal.cpp b/src/swrenderer/scene/r_portal.cpp index e799f377c..2ab01b0bb 100644 --- a/src/swrenderer/scene/r_portal.cpp +++ b/src/swrenderer/scene/r_portal.cpp @@ -44,6 +44,7 @@ #include "version.h" #include "r_utility.h" #include "r_3dfloors.h" +#include "g_levellocals.h" #include "swrenderer/drawers/r_draw_rgba.h" #include "swrenderer/segments/r_clipsegment.h" #include "swrenderer/segments/r_drawsegment.h" @@ -135,7 +136,7 @@ namespace swrenderer case PORTS_SKYVIEWPOINT: { // Don't let gun flashes brighten the sky box - ASkyViewpoint *sky = barrier_cast(port->mSkybox); + AActor *sky = port->mSkybox; extralight = 0; R_SetVisibility(sky->args[0] * 0.25f); @@ -170,7 +171,7 @@ namespace swrenderer } port->mFlags |= PORTSF_INSKYBOX; - if (port->mPartner > 0) sectorPortals[port->mPartner].mFlags |= PORTSF_INSKYBOX; + if (port->mPartner > 0) level.sectorPortals[port->mPartner].mFlags |= PORTSF_INSKYBOX; camera = nullptr; viewsector = port->mDestination; assert(viewsector != nullptr); @@ -234,7 +235,7 @@ namespace swrenderer planes->Render(); port->mFlags &= ~PORTSF_INSKYBOX; - if (port->mPartner > 0) sectorPortals[port->mPartner].mFlags &= ~PORTSF_INSKYBOX; + if (port->mPartner > 0) level.sectorPortals[port->mPartner].mFlags &= ~PORTSF_INSKYBOX; } // Draw all the masked textures in a second pass, in the reverse order they diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index aa760c221..c94f4f467 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -261,6 +261,15 @@ FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITF return FTextureID(-1); } +DEFINE_ACTION_FUNCTION(_TexMan, CheckForTexture) +{ + PARAM_PROLOGUE; + PARAM_STRING(name); + PARAM_INT(type); + PARAM_INT_DEF(flags); + ACTION_RETURN_INT(TexMan.CheckForTexture(name, type, flags).GetIndex()); +} + //========================================================================== // // FTextureManager :: ListTextures diff --git a/src/textures/textures.h b/src/textures/textures.h index fef23a309..44d0d92bc 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -360,9 +360,11 @@ public: bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch); }; +class FxAddSub; // Texture manager class FTextureManager { + friend class FxAddSub; // needs access to do a bounds check on the texture ID. public: FTextureManager (); ~FTextureManager (); diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 5a2a2485a..1407576c8 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -129,6 +129,16 @@ void DCanvas::DrawTexture (FTexture *img, double x, double y, int tags_first, .. DrawTextureParms(img, parms); } +DEFINE_ACTION_FUNCTION(_Screen, DrawHUDTexture) +{ + PARAM_PROLOGUE; + PARAM_INT(texid); + PARAM_FLOAT(x); + PARAM_FLOAT(y); + screen->DrawTexture(TexMan(FSetTextureID(texid)), x, y, DTA_HUDRules, HUD_Normal, TAG_END); + return 0; +} + void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) { #ifndef NO_SWRENDER diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 199120f75..16f3b6f6c 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -1,14 +1,19 @@ #include "zscript/base.txt" +#include "zscript/sounddata.txt" +#include "zscript/mapdata.txt" #include "zscript/dynarrays.txt" #include "zscript/constants.txt" #include "zscript/actor.txt" #include "zscript/actor_checks.txt" -#include "zscript/shared/inventory.txt" -#include "zscript/shared/inv_misc.txt" -#include "zscript/shared/weapons.txt" -#include "zscript/shared/armor.txt" -#include "zscript/shared/powerups.txt" +#include "zscript/inventory/inventory.txt" +#include "zscript/inventory/inv_misc.txt" +#include "zscript/inventory/weapons.txt" +#include "zscript/inventory/armor.txt" +#include "zscript/inventory/ammo.txt" +#include "zscript/inventory/health.txt" +#include "zscript/inventory/powerups.txt" + #include "zscript/shared/player.txt" #include "zscript/shared/morph.txt" #include "zscript/shared/botstuff.txt" diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 932db33f2..465c7f4e0 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -309,6 +309,7 @@ class Actor : Thinker native virtual native void Die(Actor source, Actor inflictor, int dmgflags = 0); virtual native bool Slam(Actor victim); virtual native void Touch(Actor toucher); + virtual native void MarkPrecacheSounds(); // Called by PIT_CheckThing to check if two actos actually can collide. virtual bool CanCollideWith(Actor other, bool passive) @@ -420,6 +421,10 @@ class Actor : Thinker native native bool HitFriend(); native bool MonsterMove(); + native SeqNode StartSoundSequenceID (int sequence, int type, int modenum, bool nostop = false); + native SeqNode StartSoundSequence (Name seqname, int modenum); + native void StopSoundSequence(); + native void FindFloorCeiling(int flags = 0); native double, double GetFriction(); native bool, Actor TestMobjZ(bool quick = false); @@ -486,7 +491,9 @@ class Actor : Thinker native native Inventory GiveInventoryType(class itemtype); native Inventory DropInventory (Inventory item); native bool UseInventory(Inventory item); + native void ObtainInventory(Actor other); native bool GiveAmmo (Class type, int amount); + native bool UsePuzzleItem(int PuzzleItemType); native float AccuracyFactor(); // DECORATE compatible functions @@ -721,13 +728,6 @@ class Actor : Thinker native native void A_ActiveSound(); native void A_FastChase(); - native void A_FreezeDeath(); - native void A_FreezeDeathChunks(); - void A_GenericFreezeDeath() - { - A_SetTranslation('Ice'); - A_FreezeDeath(); - } native void A_PlayerScream(); native void A_SkullPop(class skulltype = "BloodySkull"); native void A_CheckPlayerDone(); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index f0e280623..e9e0a0673 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -1,3 +1,42 @@ +struct TexMan +{ + enum EUseTypes + { + Type_Any, + Type_Wall, + Type_Flat, + Type_Sprite, + Type_WallPatch, + Type_Build, + Type_SkinSprite, + Type_Decal, + Type_MiscPatch, + Type_FontChar, + Type_Override, // For patches between TX_START/TX_END + Type_Autopage, // Automap background - used to enable the use of FAutomapTexture + Type_SkinGraphic, + Type_Null, + Type_FirstDefined, + }; + + enum EFlags + { + TryAny = 1, + Overridable = 2, + ReturnFirst = 4, + AllowSkins = 8, + ShortNameOnly = 16, + DontCreate = 32 + }; + + native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny); +} + +struct Screen +{ + native static void DrawHUDTexture(TextureID tex, double x, double y); +} + class Object native { native bool bDestroyed; @@ -143,12 +182,13 @@ struct LevelLocals native native bool polygrind; native bool nomonsters; native bool frozen; + native bool infinite_flight; // level_info_t *info cannot be done yet. } struct StringTable native { - native static String Localize(String val); + native static String Localize(String val, bool prefixed = false); } // a few values of this need to be readable by the play code. @@ -187,369 +227,6 @@ struct F3DFloor native { } -struct Vertex native -{ - native readonly Vector2 p; -} - -struct Side -{ - enum ETexpart - { - top=0, - mid=1, - bottom=2 - }; - - enum EWallFlags - { - WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative - WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall - WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel - WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles. - WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side. - WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side. - WALLF_POLYOBJ = 64, // This wall belongs to a polyobject. - WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. - }; - - native Sector sector; // Sector the SideDef is facing. - //DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall - native Line linedef; - native int16 Light; - native uint8 Flags; - - native TextureID GetTexture(int which); - native void SetTexture(int which, TextureID tex); - native void SetTextureXOffset(int which, double offset); - native double GetTextureXOffset(int which); - native void AddTextureXOffset(int which, double delta); - native void SetTextureYOffset(int which, double offset); - native double GetTextureYOffset(int which); - native void AddTextureYOffset(int which, double delta); - native void SetTextureXScale(int which, double scale); - native double GetTextureXScale(int which); - native void MultiplyTextureXScale(int which, double delta); - native void SetTextureYScale(int which, double scale); - native double GetTextureYScale(int which); - native void MultiplyTextureYScale(int which, double delta); - //native DInterpolation *SetInterpolation(int position); - //native void StopInterpolation(int position); - - native Vertex V1(); - native Vertex V2(); - - native int Index(); -}; - -struct Line native -{ - enum ELineFlags - { - ML_BLOCKING =0x00000001, // solid, is an obstacle - ML_BLOCKMONSTERS =0x00000002, // blocks monsters only - ML_TWOSIDED =0x00000004, // backside will not be present at all if not two sided - ML_DONTPEGTOP = 0x00000008, // upper texture unpegged - ML_DONTPEGBOTTOM = 0x00000010, // lower texture unpegged - ML_SECRET = 0x00000020, // don't map as two sided: IT'S A SECRET! - ML_SOUNDBLOCK = 0x00000040, // don't let sound cross two of these - ML_DONTDRAW = 0x00000080, // don't draw on the automap - ML_MAPPED = 0x00000100, // set if already drawn in automap - ML_REPEAT_SPECIAL = 0x00000200, // special is repeatable - ML_ADDTRANS = 0x00000400, // additive translucency (can only be set internally) - - // Extended flags - ML_MONSTERSCANACTIVATE = 0x00002000, // [RH] Monsters (as well as players) can activate the line - ML_BLOCK_PLAYERS = 0x00004000, - ML_BLOCKEVERYTHING = 0x00008000, // [RH] Line blocks everything - ML_ZONEBOUNDARY = 0x00010000, - ML_RAILING = 0x00020000, - ML_BLOCK_FLOATERS = 0x00040000, - ML_CLIP_MIDTEX = 0x00080000, // Automatic for every Strife line - ML_WRAP_MIDTEX = 0x00100000, - ML_3DMIDTEX = 0x00200000, - ML_CHECKSWITCHRANGE = 0x00400000, - ML_FIRSTSIDEONLY = 0x00800000, // activated only when crossed from front side - ML_BLOCKPROJECTILE = 0x01000000, - ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line - ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight - ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks - ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING - }; - - - native readonly vertex v1, v2; // vertices, from v1 to v2 - native readonly Vector2 delta; // precalculated v2 - v1 for side checking - native uint flags; - native uint activation; // activation type - native int special; - native int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) - native double alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) - //native Side sidedef[2]; - native readonly double bbox[4]; // bounding box, for the extent of the LineDef. - native readonly Sector frontsector, backsector; - native int validcount; // if == validcount, already checked - native int locknumber; // [Dusk] lock number for special - native readonly uint portalindex; - native readonly uint portaltransferred; - - native bool isLinePortal(); - native bool isVisualPortal(); - native Line getPortalDestination(); - native int getPortalAlignment(); - native int Index(); -} - -struct SecPlane native -{ - native Vector3 Normal; - native double D; - native double negiC; - - native bool isSlope(); - native int PointOnSide(Vector3 pos); - native double ZatPoint (Vector2 v); - native double ZatPointDist(Vector2 v, double dist); - native bool isEqual(Secplane other); - native void ChangeHeight(double hdiff); - native double GetChangedHeight(double hdiff); - native double HeightDiff(double oldd, double newd = 0.0); - native double PointToDist(Vector2 xy, double z); -} - -// This encapsulates all info Doom's original 'special' field contained - for saving and transferring. -struct SecSpecial -{ - Name damagetype; - int damageamount; - short special; - short damageinterval; - short leakydamage; - int Flags; -} - -struct Sector native -{ - //secplane_t floorplane, ceilingplane; // defined internally - //FDynamicColormap *ColorMap; - - native Actor SoundTarget; - - native int16 special; - native int16 lightlevel; - native int16 seqType; - - native int sky; - native Name SeqName; - - native readonly Vector2 centerspot; - native int validcount; - native Actor thinglist; - - native double friction, movefactor; - native int terrainnum[2]; - - // thinker_t for reversable actions - //SectorEffect floordata; - //SectorEffect ceilingdata; - //SectorEffect lightingdata; - - enum EPlane - { - floor, - ceiling - }; - - enum EInterpolationType - { - CeilingMove, - FloorMove, - CeilingScroll, - FloorScroll - }; - //Interpolation interpolations[4]; - - native uint8 soundtraversed; - native int8 stairlock; - native int prevsec; - native int nextsec; - - //TStaticPointedArray Lines; // this is defined internally to avoid exposing some overly complicated type to the parser - - native readonly Sector heightsec; - - native uint bottommap, midmap, topmap; - - //struct msecnode_t *touching_thinglist; - //struct msecnode_t *sectorportal_thinglist; - - native double gravity; - native Name damagetype; - native int damageamount; - native int16 damageinterval; - native int16 leakydamage; - - native uint16 ZoneNumber; - - enum ESectorMoreFlags - { - SECMF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor - SECMF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes - SECMF_NOFAKELIGHT = 8, // heightsec does not change lighting - SECMF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions - SECMF_UNDERWATER = 32, // sector is underwater - SECMF_FORCEDUNDERWATER= 64, // sector is forced to be underwater - SECMF_UNDERWATERMASK = 32+64, - SECMF_DRAWN = 128, // sector has been drawn at least once - SECMF_HIDDEN = 256, // Do not draw on textured automap - } - native uint16 MoreFlags; - - enum ESectorFlags - { - SECF_SILENT = 1, // actors in sector make no noise - SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector - SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. - SECF_NORESPAWN = 8, // players can not respawn in this sector - SECF_FRICTION = 16, // sector has friction enabled - SECF_PUSH = 32, // pushers enabled - SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) - SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage - SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode - SECF_ENDLEVEL = 512, // ends level when health goes below 10 - SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. - - SECF_WASSECRET = 1 << 30, // a secret that was discovered - SECF_SECRET = 1 << 31, // a secret sector - - SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, - SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags - SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers - } - - enum EMoveResult - { - MOVE_OK, - MOVE_CRUSHED, - MOVE_PASTDEST - }; - - native uint Flags; - - native SectorAction SecActTarget; - - native readonly uint Portals[2]; - native readonly int PortalGroup; - - native readonly int sectornum; - - native int Index(); - - native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); - native double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0); - - native void RemoveForceField(); - native static Sector PointInSector(Vector2 pt); - native void SetColor(color c, int desat = 0); - native void SetFade(color c); - - native bool PlaneMoving(int pos); - native int GetFloorLight(); - native int GetCeilingLight(); - native Sector GetHeightSec(); - native void TransferSpecial(Sector model); - native void GetSpecial(out SecSpecial spec); - native void SetSpecial( SecSpecial spec); - native int GetTerrain(int pos); - native void CheckPortalPlane(int plane); - native double, Sector HighestCeilingAt(Vector2 a); - native double, Sector LowestFloorAt(Vector2 a); - native double, double GetFriction(int plane); - - native void SetXOffset(int pos, double o); - native void AddXOffset(int pos, double o); - native double GetXOffset(int pos); - native void SetYOffset(int pos, double o); - native void AddYOffset(int pos, double o); - native double GetYOffset(int pos, bool addbase = true); - native void SetXScale(int pos, double o); - native double GetXScale(int pos); - native void SetYScale(int pos, double o); - native double GetYScale(int pos); - native void SetAngle(int pos, double o); - native double GetAngle(int pos, bool addbase = true); - native void SetBase(int pos, double y, double o); - native void SetAlpha(int pos, double o); - native double GetAlpha(int pos); - native int GetFlags(int pos); - native int GetVisFlags(int pos); - native void ChangeFlags(int pos, int And, int Or); - native int GetPlaneLight(int pos); - native void SetPlaneLight(int pos, int level); - native TextureID GetTexture(int pos); - native void SetTexture(int pos, TextureID tex, bool floorclip = true); - native double GetPlaneTexZ(int pos); - native void SetPlaneTexZ(int pos, double val, bool dirtify = false); // This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code. - native void ChangeLightLevel(int newval); - native void SetLightLevel(int newval); - native int GetLightLevel(); - native void AdjustFloorClip(); - native bool IsLinked(Sector other, bool ceiling); - - native bool PortalBlocksView(int plane); - native bool PortalBlocksSight(int plane); - native bool PortalBlocksMovement(int plane); - native bool PortalBlocksSound(int plane); - native bool PortalIsLinked(int plane); - native void ClearPortal(int plane); - native double GetPortalPlaneZ(int plane); - native Vector2 GetPortalDisplacement(int plane); - native int GetPortalType(int plane); - native int GetOppositePortalGroup(int plane); - native double CenterFloor(); - native double CenterCeiling(); - native bool TriggerSectorActions(Actor thing, int activation); - - native int MoveFloor(double speed, double dest, int crush, int direction, bool hexencrush, bool instant = false); - native int MoveCeiling(double speed, double dest, int crush, int direction, bool hexencrush); - - native Sector NextSpecialSector(int type, Sector prev); - native double, Vertex FindLowestFloorSurrounding(); - native double, Vertex FindHighestFloorSurrounding(); - native double, Vertex FindNextHighestFloor(); - native double, Vertex FindNextLowestFloor(); - native double, Vertex FindLowestCeilingSurrounding(); - native double, Vertex FindHighestCeilingSurrounding(); - native double, Vertex FindNextLowestCeiling(); - native double, Vertex FindNextHighestCeiling(); - - native double FindShortestTextureAround(); - native double FindShortestUpperAround(); - native Sector FindModelFloorSector(double floordestheight); - native Sector FindModelCeilingSector(double floordestheight); - native int FindMinSurroundingLight(int max); - native double, Vertex FindLowestCeilingPoint(); - native double, Vertex FindHighestFloorPoint(); - - - bool isSecret() - { - return !!(Flags & SECF_SECRET); - } - - bool wasSecret() - { - return !!(Flags & SECF_WASSECRET); - } - - void ClearSecret() - { - Flags &= ~SECF_SECRET; - } - - -} - struct Wads { enum WadNamespace diff --git a/wadsrc/static/zscript/inventory/ammo.txt b/wadsrc/static/zscript/inventory/ammo.txt new file mode 100644 index 000000000..be9933a70 --- /dev/null +++ b/wadsrc/static/zscript/inventory/ammo.txt @@ -0,0 +1,311 @@ +/* +** a_ammo.cpp +** Implements ammo and backpack items. +** +**--------------------------------------------------------------------------- +** Copyright 2000-2016 Randy Heit +** Copyright 2006-2017 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +class Ammo : Inventory native +{ + native int BackpackAmount; + native int BackpackMaxAmount; + + Default + { + +INVENTORY.KEEPDEPLETED + Inventory.PickupSound "misc/ammo_pkup"; + } + + native Class GetParentAmmo (); + + //=========================================================================== + // + // AAmmo :: HandlePickup + // + //=========================================================================== + + override bool HandlePickup (Inventory item) + { + let ammoitem = Ammo(item); + if (ammoitem != null && ammoitem.GetParentAmmo() == GetClass()) + { + if (Amount < MaxAmount || sv_unlimited_pickup) + { + int receiving = item.Amount; + + if (!item.bIgnoreSkill) + { // extra ammo in baby mode and nightmare mode + receiving = int(receiving * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + } + int oldamount = Amount; + + if (Amount > 0 && Amount + receiving < 0) + { + Amount = 0x7fffffff; + } + else + { + Amount += receiving; + } + if (Amount > MaxAmount && !sv_unlimited_pickup) + { + Amount = MaxAmount; + } + item.bPickupGood = true; + + // If the player previously had this ammo but ran out, possibly switch + // to a weapon that uses it, but only if the player doesn't already + // have a weapon pending. + + if (oldamount == 0 && Owner != null && Owner.player != null) + { + PlayerPawn(Owner).CheckWeaponSwitch(GetClass()); + } + } + return true; + } + return false; + } + + //=========================================================================== + // + // AAmmo :: CreateCopy + // + //=========================================================================== + + override Inventory CreateCopy (Actor other) + { + Inventory copy; + int amount = Amount; + + // extra ammo in baby mode and nightmare mode + if (!bIgnoreSkill) + { + amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + } + + let type = GetParentAmmo(); + if (GetClass() == type) + { + if (!GoAway ()) + { + Destroy (); + } + + copy = Inventory(Spawn (type)); + copy.Amount = amount; + copy.BecomeItem (); + } + else + { + copy = Super.CreateCopy (other); + copy.Amount = amount; + } + if (copy.Amount > copy.MaxAmount) + { // Don't pick up more ammo than you're supposed to be able to carry. + copy.Amount = copy.MaxAmount; + } + return copy; + } + + //=========================================================================== + // + // AAmmo :: CreateTossable + // + //=========================================================================== + + override Inventory CreateTossable() + { + Inventory copy = Super.CreateTossable(); + if (copy != null) + { // Do not increase ammo by dropping it and picking it back up at + // certain skill levels. + copy.bIgnoreSkill = true; + } + return copy; + } + + +} + +class BackpackItem : Inventory +{ + bool bDepleted; + + //=========================================================================== + // + // ABackpackItem :: CreateCopy + // + // A backpack is being added to a player who doesn't yet have one. Give them + // every kind of ammo, and increase their max amounts. + // + //=========================================================================== + + override Inventory CreateCopy (Actor other) + { + // Find every unique type of ammoitem. Give it to the player if + // he doesn't have it already, and double its maximum capacity. + uint end = AllActorClasses.Size(); + for (uint i = 0; i < end; ++i) + { + let type = AllActorClasses[i]; + + if (type.GetParentClass() == 'Ammo') + { + let ammotype = (class)(type); + let ammoitem = Ammo(other.FindInventory(ammotype)); + int amount = GetDefaultByType(ammotype).BackpackAmount; + // extra ammo in baby mode and nightmare mode + if (!bIgnoreSkill) + { + amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + } + if (amount < 0) amount = 0; + if (ammoitem == NULL) + { // The player did not have the ammoitem. Add it. + ammoitem = Ammo(Spawn(ammotype)); + ammoitem.Amount = bDepleted ? 0 : amount; + if (ammoitem.BackpackMaxAmount > ammoitem.MaxAmount) + { + ammoitem.MaxAmount = ammoitem.BackpackMaxAmount; + } + if (ammoitem.Amount > ammoitem.MaxAmount) + { + ammoitem.Amount = ammoitem.MaxAmount; + } + ammoitem.AttachToOwner (other); + } + else + { // The player had the ammoitem. Give some more. + if (ammoitem.MaxAmount < ammoitem.BackpackMaxAmount) + { + ammoitem.MaxAmount = ammoitem.BackpackMaxAmount; + } + if (!bDepleted && ammoitem.Amount < ammoitem.MaxAmount) + { + ammoitem.Amount += amount; + if (ammoitem.Amount > ammoitem.MaxAmount) + { + ammoitem.Amount = ammoitem.MaxAmount; + } + } + } + } + } + return Super.CreateCopy (other); + } + + //=========================================================================== + // + // ABackpackItem :: HandlePickup + // + // When the player picks up another backpack, just give them more ammoitem. + // + //=========================================================================== + + override bool HandlePickup (Inventory item) + { + // Since you already have a backpack, that means you already have every + // kind of ammo in your inventory, so we don't need to look at the + // entire PClass list to discover what kinds of ammo exist, and we don't + // have to alter the MaxAmount either. + if (item is 'BackpackItem') + { + for (let probe = Owner.Inv; probe != NULL; probe = probe.Inv) + { + if (probe.GetParentClass() == 'Ammo') + { + if (probe.Amount < probe.MaxAmount || sv_unlimited_pickup) + { + int amount = Ammo(probe).Default.BackpackAmount; + // extra ammo in baby mode and nightmare mode + if (!bIgnoreSkill) + { + amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor)); + } + probe.Amount += amount; + if (probe.Amount > probe.MaxAmount && !sv_unlimited_pickup) + { + probe.Amount = probe.MaxAmount; + } + } + } + } + // The pickup always succeeds, even if you didn't get anything + item.bPickupGood = true; + return true; + } + return false; + } + + //=========================================================================== + // + // ABackpackItem :: CreateTossable + // + // The tossed backpack must not give out any more ammo, otherwise a player + // could cheat by dropping their backpack and picking it up for more ammoitem. + // + //=========================================================================== + + override Inventory CreateTossable () + { + let pack = BackpackItem(Super.CreateTossable()); + if (pack != NULL) + { + pack.bDepleted = true; + } + return pack; + } + + //=========================================================================== + // + // ABackpackItem :: DetachFromOwner + // + //=========================================================================== + + override void DetachFromOwner () + { + // When removing a backpack, drop the player's ammo maximums to normal + + for (let item = Owner.Inv; item != NULL; item = item.Inv) + { + if (item is 'Ammo' && item.MaxAmount == Ammo(item).BackpackMaxAmount) + { + item.MaxAmount = item.Default.MaxAmount; + if (item.Amount > item.MaxAmount) + { + item.Amount = item.MaxAmount; + } + } + } + } +} + diff --git a/wadsrc/static/zscript/shared/armor.txt b/wadsrc/static/zscript/inventory/armor.txt similarity index 100% rename from wadsrc/static/zscript/shared/armor.txt rename to wadsrc/static/zscript/inventory/armor.txt diff --git a/wadsrc/static/zscript/inventory/health.txt b/wadsrc/static/zscript/inventory/health.txt new file mode 100644 index 000000000..88bf6b133 --- /dev/null +++ b/wadsrc/static/zscript/inventory/health.txt @@ -0,0 +1,162 @@ +/* +** a_health.cpp +** All health items +** +**--------------------------------------------------------------------------- +** Copyright 2000-2016 Randy Heit +** Copyright 2006-2017 Cheistoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +class Health : Inventory +{ + transient int PrevHealth; + /*meta*/ int LowHealth; + /*meta*/ String LowHealthMessage; + + property LowMessage: LowHealth, LowHealthMessage; + + Default + { + Inventory.Amount 1; + Inventory.MaxAmount 0; + Inventory.PickupSound "misc/health_pkup"; + } + + //=========================================================================== + // + // AHealth :: PickupMessage + // + //=========================================================================== + override String PickupMessage () + { + if (PrevHealth < LowHealth) + { + String message = LowHealthMessage; + if (message.Length() != 0) + { + return message; + } + } + return Super.PickupMessage(); + } + + //=========================================================================== + // + // TryPickup + // + //=========================================================================== + + override bool TryPickup (in out Actor other) + { + PrevHealth = other.player != NULL ? other.player.health : other.health; + + // P_GiveBody adds one new feature, applied only if it is possible to pick up negative health: + // Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount. + if (other.GiveBody(Amount, MaxAmount)) + { + GoAwayAndDie(); + return true; + } + return false; + } + + +} + +class HealthPickup : Inventory +{ + int autousemode; + + property AutoUse: autousemode; + + Default + { + Inventory.DefMaxAmount; + +INVENTORY.INVBAR + } + + //=========================================================================== + // + // CreateCopy + // + //=========================================================================== + + override Inventory CreateCopy (Actor other) + { + Inventory copy = Super.CreateCopy (other); + copy.health = health; + return copy; + } + + //=========================================================================== + // + // CreateTossable + // + //=========================================================================== + + override Inventory CreateTossable () + { + Inventory copy = Super.CreateTossable (); + if (copy != NULL) + { + copy.health = health; + } + return copy; + } + + //=========================================================================== + // + // HandlePickup + // + //=========================================================================== + + override bool HandlePickup (Inventory item) + { + // HealthPickups that are the same type but have different health amounts + // do not count as the same item. + if (item.health == health) + { + return Super.HandlePickup (item); + } + return false; + } + + //=========================================================================== + // + // Use + // + //=========================================================================== + + override bool Use (bool pickup) + { + return Owner.GiveBody (health, 0); + } + + +} diff --git a/wadsrc/static/zscript/inventory/inv_misc.txt b/wadsrc/static/zscript/inventory/inv_misc.txt new file mode 100644 index 000000000..9bea4c7bf --- /dev/null +++ b/wadsrc/static/zscript/inventory/inv_misc.txt @@ -0,0 +1,141 @@ +//=========================================================================== +// +// +// +//=========================================================================== + +class ScoreItem : Inventory +{ + Default + { + Height 10; + +COUNTITEM + Inventory.Amount 1; + +Inventory.ALWAYSPICKUP + } + + override bool TryPickup (in out Actor toucher) + { + toucher.Score += Amount; + GoAwayAndDie(); + return true; + } +} + +//=========================================================================== +// +// +// +//=========================================================================== + +class Key : Inventory native +{ + native uint8 KeyNumber; + + Default + { + +DONTGIB; // Don't disappear due to a crusher + Inventory.InterHubAmount 0; + Inventory.PickupSound "misc/k_pkup"; + } + + override bool HandlePickup (Inventory item) + { + // In single player, you can pick up an infinite number of keys + // even though you can only hold one of each. + if (multiplayer) + { + return Super.HandlePickup (item); + } + if (GetClass() == item.GetClass()) + { + item.bPickupGood = true; + return true; + } + return false; + } + + override bool ShouldStay () + { + return !!multiplayer; + } +} + +//=========================================================================== +// +// AMapRevealer +// +// A MapRevealer reveals the whole map for the player who picks it up. +// The MapRevealer doesn't actually go in your inventory. Instead, it sets +// a flag on the level. +// +//=========================================================================== + +class MapRevealer : Inventory +{ + override bool TryPickup (in out Actor toucher) + { + level.allmap = true; + GoAwayAndDie (); + return true; + } +} + +//=========================================================================== +// +// +// +//=========================================================================== + +class PuzzleItem : Inventory +{ + /*meta*/ int PuzzleItemNumber; + /*meta*/ String PuzzFailMessage; + + property Number: PuzzleItemNumber; + property FailMessage: PuzzFailMessage; + + Default + { + +NOGRAVITY + +INVENTORY.INVBAR + Inventory.DefMaxAmount; + Inventory.UseSound "PuzzleSuccess"; + Inventory.PickupSound "misc/i_pkup"; + PuzzleItem.FailMessage("$TXT_USEPUZZLEFAILED"); + } + + override bool HandlePickup (Inventory item) + { + // Can't carry more than 1 of each puzzle item in coop netplay + if (multiplayer && !deathmatch && item.GetClass() == GetClass()) + { + return true; + } + return Super.HandlePickup (item); + } + + override bool Use (bool pickup) + { + if (Owner == NULL) return false; + if (Owner.UsePuzzleItem (PuzzleItemNumber)) + { + return true; + } + // [RH] Always play the sound if the use fails. + Owner.A_PlaySound ("*puzzfail", CHAN_VOICE); + if (Owner.CheckLocalView (consoleplayer)) + { + C_MidPrint ("SmallFont", PuzzFailMessage, true); + } + return false; + } + + + override bool ShouldStay () + { + return !!multiplayer; + } + +} + diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt similarity index 90% rename from wadsrc/static/zscript/shared/inventory.txt rename to wadsrc/static/zscript/inventory/inventory.txt index d33b5e112..d3f6bfef5 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -1,5 +1,6 @@ class Inventory : Actor native { + const BLINKTHRESHOLD = (4*32); native Actor Owner; // Who owns this item? NULL if it's still a pickup. native int Amount; // Amount of item this instance has @@ -37,11 +38,25 @@ class Inventory : Actor native virtual native void PlayPickupSound(Actor user); virtual native void AttachToOwner(Actor user); virtual native void DetachFromOwner(); + virtual native bool DrawPowerup(int x, int y); + //=========================================================================== + // + // AInventory :: Travelled + // + // Called when an item in somebody's inventory is carried over to another + // map, in case it needs to do special reinitialization. + // + //=========================================================================== + + virtual void Travelled() + {} + virtual double GetSpeedFactor() { return 1; } virtual bool GetNoTeleportFreeze() { return false; } virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {} + native bool GoAway(); native void GoAwayAndDie(); native void BecomeItem(); native void BecomePickup(); diff --git a/wadsrc/static/zscript/shared/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt similarity index 60% rename from wadsrc/static/zscript/shared/powerups.txt rename to wadsrc/static/zscript/inventory/powerups.txt index 2842989f0..db838b904 100644 --- a/wadsrc/static/zscript/shared/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -104,26 +104,253 @@ class PowerMask : PowerIronFeet native } } -class PowerLightAmp : Powerup native +//=========================================================================== +// +// LightAmp +// +//=========================================================================== + +class PowerLightAmp : Powerup { Default { Powerup.Duration -120; } + + //=========================================================================== + // + // APowerLightAmp :: DoEffect + // + //=========================================================================== + + override void DoEffect () + { + Super.DoEffect (); + + let player = Owner.player; + if (player != NULL && player.fixedcolormap < PlayerInfo.NUMCOLORMAPS) + { + if (!isBlinking()) + { + player.fixedlightlevel = 1; + } + else + { + player.fixedlightlevel = -1; + } + } + } + + //=========================================================================== + // + // APowerLightAmp :: EndEffect + // + //=========================================================================== + + override void EndEffect () + { + Super.EndEffect(); + if (Owner != NULL && Owner.player != NULL && Owner.player.fixedcolormap < PlayerInfo.NUMCOLORMAPS) + { + Owner.player.fixedlightlevel = -1; + } + } + } -class PowerTorch : PowerLightAmp native {} +//=========================================================================== +// +// Torch +// +//=========================================================================== -class PowerFlight : Powerup native +class PowerTorch : PowerLightAmp +{ + int NewTorch, NewTorchDelta; + + override void DoEffect () + { + if (Owner == NULL || Owner.player == NULL) + { + return; + } + + let player = Owner.player; + if (EffectTics <= BLINKTHRESHOLD || player.fixedcolormap >= PlayerInfo.NUMCOLORMAPS) + { + Super.DoEffect (); + } + else + { + Powerup.DoEffect (); + + if (!(level.time & 16) && Owner.player != NULL) + { + if (NewTorch != 0) + { + if (player.fixedlightlevel + NewTorchDelta > 7 + || player.fixedlightlevel + NewTorchDelta < 0 + || NewTorch == player.fixedlightlevel) + { + NewTorch = 0; + } + else + { + player.fixedlightlevel += NewTorchDelta; + } + } + else + { + NewTorch = (random[torch]() & 7) + 1; + NewTorchDelta = (NewTorch == Owner.player.fixedlightlevel) ? + 0 : ((NewTorch > player.fixedlightlevel) ? 1 : -1); + } + } + } + } + +} + +//=========================================================================== +// +// Flight +// +//=========================================================================== + +class PowerFlight : Powerup { Default { Powerup.Duration -60; +INVENTORY.HUBPOWER } + + bool HitCenterFrame; + + //=========================================================================== + // + // APowerFlight :: InitEffect + // + //=========================================================================== + + override void InitEffect () + { + Super.InitEffect(); + Owner.bFly = true; + Owner.bNoGravity = true; + if (Owner.pos.Z <= Owner.floorz) + { + Owner.Vel.Z = 4;; // thrust the player in the air a bit + } + if (Owner.Vel.Z <= -35) + { // stop falling scream + Owner.A_StopSound (CHAN_VOICE); + } + } + + //=========================================================================== + // + // APowerFlight :: DoEffect + // + //=========================================================================== + + override void Tick () + { + // The Wings of Wrath only expire in multiplayer and non-hub games + if (!multiplayer && level.infinite_flight) + { + EffectTics++; + } + Super.Tick (); + } + + //=========================================================================== + // + // APowerFlight :: EndEffect + // + //=========================================================================== + + override void EndEffect () + { + Super.EndEffect(); + if (Owner == NULL || Owner.player == NULL) + { + return; + } + + if (!(Owner.bFlyCheat)) + { + if (Owner.pos.Z != Owner.floorz) + { + Owner.player.centering = true; + } + Owner.bFly = false; + Owner.bNoGravity = false; + } + } + + //=========================================================================== + // + // APowerFlight :: DrawPowerup + // + //=========================================================================== + + override bool DrawPowerup (int x, int y) + { + // If this item got a valid icon use that instead of the default spinning wings. + if (Icon.isValid()) + { + return Super.DrawPowerup(x, y); + } + + if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16)) + { + TextureID picnum = TexMan.CheckForTexture ("SPFLY0", TexMan.Type_MiscPatch); + int frame = (level.time/3) & 15; + + if (!picnum.isValid()) + { + return false; + } + if (Owner.bNoGravity) + { + if (HitCenterFrame && (frame != 15 && frame != 0)) + { + screen.DrawHUDTexture (picnum + 15, x, y); + } + else + { + screen.DrawHUDTexture (picnum + frame, x, y); + HitCenterFrame = false; + } + } + else + { + if (!HitCenterFrame && (frame != 15 && frame != 0)) + { + screen.DrawHUDTexture (picnum + frame, x, y); + HitCenterFrame = false; + } + else + { + screen.DrawHUDTexture (picnum+15, x, y); + HitCenterFrame = true; + } + } + } + return true; + } + + } -class PowerWeaponLevel2 : Powerup native +//=========================================================================== +// +// WeaponLevel2 +// +//=========================================================================== + +class PowerWeaponLevel2 : Powerup { Default { @@ -131,11 +358,100 @@ class PowerWeaponLevel2 : Powerup native Inventory.Icon "SPINBK0"; +INVENTORY.NOTELEPORTFREEZE } + + //=========================================================================== + // + // APowerWeaponLevel2 :: InitEffect + // + //=========================================================================== + + override void InitEffect () + { + + Super.InitEffect(); + + let player = Owner.player; + + if (player == null) + return; + + let weap = player.ReadyWeapon; + + if (weap == null) + return; + + let sister = weap.SisterWeapon; + + if (sister == null) + return; + + if (!sister.bPowered_Up) + return; + + let ready = sister.GetReadyState(); + if (weap.GetReadyState() != ready) + { + player.ReadyWeapon = sister; + player.SetPsprite(PSP_WEAPON, ready); + } + else + { + PSprite psp = player.FindPSprite(PSprite.WEAPON); + if (psp != null && psp.Caller == player.ReadyWeapon) + { + // If the weapon changes but the state does not, we have to manually change the PSprite's caller here. + psp.Caller = sister; + player.ReadyWeapon = sister; + } + else + { + // Something went wrong. Initiate a regular weapon change. + player.PendingWeapon = sister; + } + } + } + + //=========================================================================== + // + // APowerWeaponLevel2 :: EndEffect + // + //=========================================================================== + + override void EndEffect () + { + Super.EndEffect(); + if (Owner == null) return; + let player = Owner.player; + if (player != NULL) + { + if (player.ReadyWeapon != NULL && player.ReadyWeapon.bPowered_Up) + { + player.ReadyWeapon.EndPowerup (); + } + if (player.PendingWeapon != NULL && player.PendingWeapon != WP_NOCHANGE && + player.PendingWeapon.bPowered_Up && + player.PendingWeapon.SisterWeapon != NULL) + { + player.PendingWeapon = player.PendingWeapon.SisterWeapon; + } + } + } + + } +//=========================================================================== +// +// Speed +// +//=========================================================================== + class PowerSpeed : Powerup native { native int SpeedFlags; + + const PSF_NOTRAIL = 1; + Default { @@ -145,7 +461,67 @@ class PowerSpeed : Powerup native +INVENTORY.NOTELEPORTFREEZE } - override double GetSpeedFactor() { return Speed; } + override double GetSpeedFactor() + { + return Speed; + } + + //=========================================================================== + // + // APowerSpeed :: DoEffect + // + //=========================================================================== + + override void DoEffect () + { + Super.DoEffect (); + + if (Owner == NULL || Owner.player == NULL) + return; + + if (Owner.player.cheats & CF_PREDICTING) + return; + + if (SpeedFlags & PSF_NOTRAIL) + return; + + if (level.time & 1) + return; + + // Check if another speed item is present to avoid multiple drawing of the speed trail. + // Only the last PowerSpeed without PSF_NOTRAIL set will actually draw the trail. + for (Inventory item = Inv; item != NULL; item = item.Inv) + { + let sitem = PowerSpeed(item); + if (sitem != null && !(sitem.SpeedFlags & PSF_NOTRAIL)) + { + return; + } + } + + if (Owner.Vel.Length() <= 12) + return; + + Actor speedMo = Spawn("PlayerSpeedTrail", Owner.Pos, NO_REPLACE); + if (speedMo) + { + speedMo.Angle = Owner.Angle; + speedMo.Translation = Owner.Translation; + speedMo.target = Owner; + speedMo.sprite = Owner.sprite; + speedMo.frame = Owner.frame; + speedMo.Floorclip = Owner.Floorclip; + + // [BC] Also get the scale from the owner. + speedMo.Scale = Owner.Scale; + + if (Owner == players[consoleplayer].camera && + !(Owner.player.cheats & CF_CHASECAM)) + { + speedMo.bInvisible = true; + } + } + } } // Player Speed Trail (used by the Speed Powerup) ---------------------------- @@ -170,6 +546,12 @@ class PlayerSpeedTrail : Actor } } +//=========================================================================== +// +// Minotaur +// +//=========================================================================== + class PowerMinotaur : Powerup { Default @@ -179,7 +561,13 @@ class PowerMinotaur : Powerup } } -class PowerTargeter : Powerup native +//=========================================================================== +// +// Targeter +// +//=========================================================================== + +class PowerTargeter : Powerup { Default { @@ -196,6 +584,119 @@ class PowerTargeter : Powerup native TRGT C -1; Stop; } + + override void Travelled () + { + InitEffect (); + } + + override void InitEffect () + { + // Why is this called when the inventory isn't even attached yet + // in APowerup.CreateCopy? + if (!Owner.FindInventory(GetClass(), true)) + return; + + let player = Owner.player; + + Super.InitEffect(); + + if (player == null) + return; + + let stat = FindState("Targeter"); + + if (stat != null) + { + player.SetPsprite(PSprite.TARGETCENTER, stat); + player.SetPsprite(PSprite.TARGETLEFT, stat + 1); + player.SetPsprite(PSprite.TARGETRIGHT, stat + 2); + } + + player.GetPSprite(PSprite.TARGETCENTER).x = (160-3); + player.GetPSprite(PSprite.TARGETCENTER).y = + player.GetPSprite(PSprite.TARGETLEFT).y = + player.GetPSprite(PSprite.TARGETRIGHT).y = (100-3); + PositionAccuracy (); + } + + override void AttachToOwner(Actor other) + { + Super.AttachToOwner(other); + + // Let's actually properly call this for the targeters. + InitEffect(); + } + + override bool HandlePickup(Inventory item) + { + if (Super.HandlePickup(item)) + { + InitEffect(); // reset the HUD sprites + return true; + } + return false; + } + + override void DoEffect () + { + Super.DoEffect (); + + if (Owner != null && Owner.player != null) + { + let player = Owner.player; + + PositionAccuracy (); + if (EffectTics < 5*TICRATE) + { + let stat = FindState("Targeter"); + + if (stat != null) + { + if (EffectTics & 32) + { + player.SetPsprite(PSprite.TARGETRIGHT, null); + player.SetPsprite(PSprite.TARGETLEFT, stat + 1); + } + else if (EffectTics & 16) + { + player.SetPsprite(PSprite.TARGETRIGHT, stat + 2); + player.SetPsprite(PSprite.TARGETLEFT, null); + } + } + } + } + } + + override void EndEffect () + { + Super.EndEffect(); + if (Owner != null && Owner.player != null) + { + // Calling GetPSprite here could crash if we're creating a new game. + // This is because P_SetupLevel nulls the player's mo before destroying + // every DThinker which in turn ends up calling this. + // However P_SetupLevel is only called after G_NewInit which calls + // every player's dtor which destroys all their psprites. + let player = Owner.player; + PSprite pspr; + if ((pspr = player.FindPSprite(PSprite.TARGETCENTER)) != null) pspr.SetState(null); + if ((pspr = player.FindPSprite(PSprite.TARGETLEFT)) != null) pspr.SetState(null); + if ((pspr = player.FindPSprite(PSprite.TARGETRIGHT)) != null) pspr.SetState(null); + } + } + + private void PositionAccuracy () + { + let player = Owner.player; + + if (player != null) + { + player.GetPSprite(PSprite.TARGETLEFT).x = (160-3) - ((100 - player.mo.accuracy)); + player.GetPSprite(PSprite.TARGETRIGHT).x = (160-3)+ ((100 - player.mo.accuracy)); + } + } + } //=========================================================================== diff --git a/wadsrc/static/zscript/shared/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt similarity index 93% rename from wadsrc/static/zscript/shared/weapons.txt rename to wadsrc/static/zscript/inventory/weapons.txt index c3ebf299d..f1d75d5dd 100644 --- a/wadsrc/static/zscript/shared/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -125,20 +125,3 @@ class WeaponPiece : Inventory native } } -class Ammo : Inventory native -{ - native int BackpackAmount; - native int BackpackMaxAmount; - - Default - { - +INVENTORY.KEEPDEPLETED - Inventory.PickupSound "misc/ammo_pkup"; - } -} - -class BackpackItem : Inventory native -{ - native bool bDepleted; -} - diff --git a/wadsrc/static/zscript/mapdata.txt b/wadsrc/static/zscript/mapdata.txt new file mode 100644 index 000000000..b7589f8d4 --- /dev/null +++ b/wadsrc/static/zscript/mapdata.txt @@ -0,0 +1,401 @@ + +struct SectorPortal native +{ + enum EType + { + TYPE_SKYVIEWPOINT = 0, // a regular skybox + TYPE_STACKEDSECTORTHING, // stacked sectors with the thing method + TYPE_PORTAL, // stacked sectors with Sector_SetPortal + TYPE_LINKEDPORTAL, // linked portal (interactive) + TYPE_PLANE, // EE-style plane portal (not implemented in SW renderer) + TYPE_HORIZON, // EE-style horizon portal (not implemented in SW renderer) + }; + + enum EFlags + { + FLAG_SKYFLATONLY = 1, // portal is only active on skyflatnum + FLAG_INSKYBOX = 2, // to avoid recursion + }; + + native int mType; + native int mFlags; + native uint mPartner; + native int mPlane; + native Sector mOrigin; + native Sector mDestination; + native Vector2 mDisplacement; + native double mPlaneZ; + native Actor mSkybox; + + native static uint GetSkyboxPortal(Actor actor); +}; + + +struct Vertex native +{ + native readonly Vector2 p; +} + +struct Side native +{ + enum ETexpart + { + top=0, + mid=1, + bottom=2 + }; + + enum EWallFlags + { + WALLF_ABSLIGHTING = 1, // Light is absolute instead of relative + WALLF_NOAUTODECALS = 2, // Do not attach impact decals to this wall + WALLF_NOFAKECONTRAST = 4, // Don't do fake contrast for this wall in side_t::GetLightLevel + WALLF_SMOOTHLIGHTING = 8, // Similar to autocontrast but applies to all angles. + WALLF_CLIP_MIDTEX = 16, // Like the line counterpart, but only for this side. + WALLF_WRAP_MIDTEX = 32, // Like the line counterpart, but only for this side. + WALLF_POLYOBJ = 64, // This wall belongs to a polyobject. + WALLF_LIGHT_FOG = 128, // This wall's Light is used even in fog. + }; + + native Sector sector; // Sector the SideDef is facing. + //DBaseDecal* AttachedDecals; // [RH] Decals bound to the wall + native Line linedef; + native int16 Light; + native uint8 Flags; + + native TextureID GetTexture(int which); + native void SetTexture(int which, TextureID tex); + native void SetTextureXOffset(int which, double offset); + native double GetTextureXOffset(int which); + native void AddTextureXOffset(int which, double delta); + native void SetTextureYOffset(int which, double offset); + native double GetTextureYOffset(int which); + native void AddTextureYOffset(int which, double delta); + native void SetTextureXScale(int which, double scale); + native double GetTextureXScale(int which); + native void MultiplyTextureXScale(int which, double delta); + native void SetTextureYScale(int which, double scale); + native double GetTextureYScale(int which); + native void MultiplyTextureYScale(int which, double delta); + //native DInterpolation *SetInterpolation(int position); + //native void StopInterpolation(int position); + + native Vertex V1(); + native Vertex V2(); + + native int Index(); +}; + +struct Line native +{ + enum ELineFlags + { + ML_BLOCKING =0x00000001, // solid, is an obstacle + ML_BLOCKMONSTERS =0x00000002, // blocks monsters only + ML_TWOSIDED =0x00000004, // backside will not be present at all if not two sided + ML_DONTPEGTOP = 0x00000008, // upper texture unpegged + ML_DONTPEGBOTTOM = 0x00000010, // lower texture unpegged + ML_SECRET = 0x00000020, // don't map as two sided: IT'S A SECRET! + ML_SOUNDBLOCK = 0x00000040, // don't let sound cross two of these + ML_DONTDRAW = 0x00000080, // don't draw on the automap + ML_MAPPED = 0x00000100, // set if already drawn in automap + ML_REPEAT_SPECIAL = 0x00000200, // special is repeatable + ML_ADDTRANS = 0x00000400, // additive translucency (can only be set internally) + + // Extended flags + ML_MONSTERSCANACTIVATE = 0x00002000, // [RH] Monsters (as well as players) can activate the line + ML_BLOCK_PLAYERS = 0x00004000, + ML_BLOCKEVERYTHING = 0x00008000, // [RH] Line blocks everything + ML_ZONEBOUNDARY = 0x00010000, + ML_RAILING = 0x00020000, + ML_BLOCK_FLOATERS = 0x00040000, + ML_CLIP_MIDTEX = 0x00080000, // Automatic for every Strife line + ML_WRAP_MIDTEX = 0x00100000, + ML_3DMIDTEX = 0x00200000, + ML_CHECKSWITCHRANGE = 0x00400000, + ML_FIRSTSIDEONLY = 0x00800000, // activated only when crossed from front side + ML_BLOCKPROJECTILE = 0x01000000, + ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line + ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight + ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks + ML_3DMIDTEX_IMPASS = 0x10000000, // [TP] if 3D midtex, behaves like a height-restricted ML_BLOCKING + }; + + + native readonly vertex v1, v2; // vertices, from v1 to v2 + native readonly Vector2 delta; // precalculated v2 - v1 for side checking + native uint flags; + native uint activation; // activation type + native int special; + native int args[5]; // <--- hexen-style arguments (expanded to ZDoom's full width) + native double alpha; // <--- translucency (0=invisibile, FRACUNIT=opaque) + native Side sidedef[2]; + native readonly double bbox[4]; // bounding box, for the extent of the LineDef. + native readonly Sector frontsector, backsector; + native int validcount; // if == validcount, already checked + native int locknumber; // [Dusk] lock number for special + native readonly uint portalindex; + native readonly uint portaltransferred; + + native bool isLinePortal(); + native bool isVisualPortal(); + native Line getPortalDestination(); + native int getPortalAlignment(); + native int Index(); +} + +struct SecPlane native +{ + native Vector3 Normal; + native double D; + native double negiC; + + native bool isSlope(); + native int PointOnSide(Vector3 pos); + native double ZatPoint (Vector2 v); + native double ZatPointDist(Vector2 v, double dist); + native bool isEqual(Secplane other); + native void ChangeHeight(double hdiff); + native double GetChangedHeight(double hdiff); + native double HeightDiff(double oldd, double newd = 0.0); + native double PointToDist(Vector2 xy, double z); +} + +// This encapsulates all info Doom's original 'special' field contained - for saving and transferring. +struct SecSpecial +{ + Name damagetype; + int damageamount; + short special; + short damageinterval; + short leakydamage; + int Flags; +} + +struct Sector native +{ + //secplane_t floorplane, ceilingplane; // defined internally + //FDynamicColormap *ColorMap; + + native Actor SoundTarget; + + native int16 special; + native int16 lightlevel; + native int16 seqType; + + native int sky; + native Name SeqName; + + native readonly Vector2 centerspot; + native int validcount; + native Actor thinglist; + + native double friction, movefactor; + native int terrainnum[2]; + + // thinker_t for reversable actions + //SectorEffect floordata; + //SectorEffect ceilingdata; + //SectorEffect lightingdata; + + enum EPlane + { + floor, + ceiling + }; + + enum EInterpolationType + { + CeilingMove, + FloorMove, + CeilingScroll, + FloorScroll + }; + //Interpolation interpolations[4]; + + native uint8 soundtraversed; + native int8 stairlock; + native int prevsec; + native int nextsec; + + //TStaticPointedArray Lines; // this is defined internally to avoid exposing some overly complicated type to the parser + + native readonly Sector heightsec; + + native uint bottommap, midmap, topmap; + + //struct msecnode_t *touching_thinglist; + //struct msecnode_t *sectorportal_thinglist; + + native double gravity; + native Name damagetype; + native int damageamount; + native int16 damageinterval; + native int16 leakydamage; + + native readonly uint16 ZoneNumber; + + enum ESectorMoreFlags + { + SECMF_FAKEFLOORONLY = 2, // when used as heightsec in R_FakeFlat, only copies floor + SECMF_CLIPFAKEPLANES = 4, // as a heightsec, clip planes to target sector's planes + SECMF_NOFAKELIGHT = 8, // heightsec does not change lighting + SECMF_IGNOREHEIGHTSEC= 16, // heightsec is only for triggering sector actions + SECMF_UNDERWATER = 32, // sector is underwater + SECMF_FORCEDUNDERWATER= 64, // sector is forced to be underwater + SECMF_UNDERWATERMASK = 32+64, + SECMF_DRAWN = 128, // sector has been drawn at least once + SECMF_HIDDEN = 256, // Do not draw on textured automap + } + native uint16 MoreFlags; + + enum ESectorFlags + { + SECF_SILENT = 1, // actors in sector make no noise + SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector + SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast. + SECF_NORESPAWN = 8, // players can not respawn in this sector + SECF_FRICTION = 16, // sector has friction enabled + SECF_PUSH = 32, // pushers enabled + SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.) + SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage + SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode + SECF_ENDLEVEL = 512, // ends level when health goes below 10 + SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. + + SECF_WASSECRET = 1 << 30, // a secret that was discovered + SECF_SECRET = 1 << 31, // a secret sector + + SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, + SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags + SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers + } + + enum EMoveResult + { + MOVE_OK, + MOVE_CRUSHED, + MOVE_PASTDEST + }; + + native uint Flags; + + native SectorAction SecActTarget; + + native uint Portals[2]; + native readonly int PortalGroup; + + native readonly int sectornum; + + native int Index(); + + native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); + native double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0); + + native void RemoveForceField(); + native static Sector PointInSector(Vector2 pt); + native void SetColor(color c, int desat = 0); + native void SetFade(color c); + + native bool PlaneMoving(int pos); + native int GetFloorLight(); + native int GetCeilingLight(); + native Sector GetHeightSec(); + native void TransferSpecial(Sector model); + native void GetSpecial(out SecSpecial spec); + native void SetSpecial( SecSpecial spec); + native int GetTerrain(int pos); + native void CheckPortalPlane(int plane); + native double, Sector HighestCeilingAt(Vector2 a); + native double, Sector LowestFloorAt(Vector2 a); + native double, double GetFriction(int plane); + + native void SetXOffset(int pos, double o); + native void AddXOffset(int pos, double o); + native double GetXOffset(int pos); + native void SetYOffset(int pos, double o); + native void AddYOffset(int pos, double o); + native double GetYOffset(int pos, bool addbase = true); + native void SetXScale(int pos, double o); + native double GetXScale(int pos); + native void SetYScale(int pos, double o); + native double GetYScale(int pos); + native void SetAngle(int pos, double o); + native double GetAngle(int pos, bool addbase = true); + native void SetBase(int pos, double y, double o); + native void SetAlpha(int pos, double o); + native double GetAlpha(int pos); + native int GetFlags(int pos); + native int GetVisFlags(int pos); + native void ChangeFlags(int pos, int And, int Or); + native int GetPlaneLight(int pos); + native void SetPlaneLight(int pos, int level); + native TextureID GetTexture(int pos); + native void SetTexture(int pos, TextureID tex, bool floorclip = true); + native double GetPlaneTexZ(int pos); + native void SetPlaneTexZ(int pos, double val, bool dirtify = false); // This mainly gets used by init code. The only place where it must set the vertex to dirty is the interpolation code. + native void ChangeLightLevel(int newval); + native void SetLightLevel(int newval); + native int GetLightLevel(); + native void AdjustFloorClip(); + native bool IsLinked(Sector other, bool ceiling); + + native bool PortalBlocksView(int plane); + native bool PortalBlocksSight(int plane); + native bool PortalBlocksMovement(int plane); + native bool PortalBlocksSound(int plane); + native bool PortalIsLinked(int plane); + native void ClearPortal(int plane); + native double GetPortalPlaneZ(int plane); + native Vector2 GetPortalDisplacement(int plane); + native int GetPortalType(int plane); + native int GetOppositePortalGroup(int plane); + native double CenterFloor(); + native double CenterCeiling(); + native bool TriggerSectorActions(Actor thing, int activation); + + native int MoveFloor(double speed, double dest, int crush, int direction, bool hexencrush, bool instant = false); + native int MoveCeiling(double speed, double dest, int crush, int direction, bool hexencrush); + + native Sector NextSpecialSector(int type, Sector prev); + native double, Vertex FindLowestFloorSurrounding(); + native double, Vertex FindHighestFloorSurrounding(); + native double, Vertex FindNextHighestFloor(); + native double, Vertex FindNextLowestFloor(); + native double, Vertex FindLowestCeilingSurrounding(); + native double, Vertex FindHighestCeilingSurrounding(); + native double, Vertex FindNextLowestCeiling(); + native double, Vertex FindNextHighestCeiling(); + + native double FindShortestTextureAround(); + native double FindShortestUpperAround(); + native Sector FindModelFloorSector(double floordestheight); + native Sector FindModelCeilingSector(double floordestheight); + native int FindMinSurroundingLight(int max); + native double, Vertex FindLowestCeilingPoint(); + native double, Vertex FindHighestFloorPoint(); + + native void SetEnvironment(String env); + native void SetEnvironmentID(int envnum); + + native SeqNode StartSoundSequenceID (int chan, int sequence, int type, int modenum, bool nostop = false); + native SeqNode StartSoundSequence (int chan, Name seqname, int modenum); + native SeqNode CheckSoundSequence (int chan); + native void StopSoundSequence(int chan); + native bool IsMakingLoopingSound (); + + bool isSecret() + { + return !!(Flags & SECF_SECRET); + } + + bool wasSecret() + { + return !!(Flags & SECF_WASSECRET); + } + + void ClearSecret() + { + Flags &= ~SECF_SECRET; + } +} diff --git a/wadsrc/static/zscript/shared/ice.txt b/wadsrc/static/zscript/shared/ice.txt index 9b72e2455..d26131eb0 100644 --- a/wadsrc/static/zscript/shared/ice.txt +++ b/wadsrc/static/zscript/shared/ice.txt @@ -71,3 +71,126 @@ class IceChunkHead : PlayerChunk } } + +extend class Actor +{ + + //============================================================================ + // + // A_FreezeDeath + // + //============================================================================ + + void A_FreezeDeath() + { + + int t = random[freezedeath](); + tics = 75+t+random[freezedeath](); + bSolid = bShootable = bNoBlood = bIceCorpse = bPushable = bTelestomp = bCanPass = bSlidesOnWalls = bCrashed = true; + Height = Default.Height; + A_SetRenderStyle(1, STYLE_Normal); + + A_PlaySound ("misc/freeze", CHAN_BODY); + + // [RH] Andy Baker's stealth monsters + if (bStealth) + { + Alpha = 1; + visdir = 0; + } + + if (player) + { + player.damagecount = 0; + player.poisoncount = 0; + player.bonuscount = 0; + } + else if (bIsMonster && special) + { // Initiate monster death actions + A_CallSpecial(special, args[0], args[1], args[2], args[3], args[4]); + special = 0; + } + } + + //============================================================================ + // + // A_FreezeDeathChunks + // + //============================================================================ + + void A_FreezeDeathChunks() + { + if (Vel != (0,0,0) && !bShattering) + { + tics = 3*TICRATE; + return; + } + Vel = (0,0,0); + A_PlaySound ("misc/icebreak", CHAN_BODY); + + // [RH] In Hexen, this creates a random number of shards (range [24,56]) + // with no relation to the size of the self shattering. I think it should + // base the number of shards on the size of the dead thing, so bigger + // things break up into more shards than smaller things. + // An actor with radius 20 and height 64 creates ~40 chunks. + int numChunks = max(4, int(radius * Height)/32); + int i = Random[FreezeDeathChunks]() % (numChunks/4); + for (i = max(24, numChunks + i); i >= 0; i--) + { + double xo = (random[FreezeDeathChunks]() - 128)*radius / 128; + double yo = (random[FreezeDeathChunks]() - 128)*radius / 128; + double zo = (random[FreezeDeathChunks]() * Height / 255); + + Actor mo = Spawn("IceChunk", Vec3Offset(xo, yo, zo), ALLOW_REPLACE); + if (mo) + { + mo.SetState (mo.SpawnState + (random[FreezeDeathChunks]()%3)); + mo.Vel.X = random2[FreezeDeathChunks]() / 128.; + mo.Vel.Y = random2[FreezeDeathChunks]() / 128.; + mo.Vel.Z = (mo.pos.Z - pos.Z) / Height * 4; + } + } + if (player) + { // attach the player's view to a chunk of ice + Actor head = Spawn("IceChunkHead", pos + (0, 0, player.mo.ViewHeight), ALLOW_REPLACE); + if (head != null) + { + head.Vel.X = random2[FreezeDeathChunks]() / 128.; + head.Vel.Y = random2[FreezeDeathChunks]() / 128.; + head.Vel.Z = (head.pos.Z - pos.Z) / Height * 4; + + head.health = health; + head.Angle = Angle; + if (head is "PlayerPawn") + { + head.player = player; + head.player.mo = PlayerPawn(head); + player = null; + head.ObtainInventory (self); + } + head.Pitch = 0.; + if (head.player.camera == self) + { + head.player.camera = head; + } + } + } + + // [RH] Do some stuff to make this more useful outside Hexen + if (bBossDeath) + { + A_BossDeath(); + } + A_NoBlocking(); + + SetStateLabel('null'); + } + + void A_GenericFreezeDeath() + { + A_SetTranslation('Ice'); + A_FreezeDeath(); + } + + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/inv_misc.txt b/wadsrc/static/zscript/shared/inv_misc.txt deleted file mode 100644 index 032c9e826..000000000 --- a/wadsrc/static/zscript/shared/inv_misc.txt +++ /dev/null @@ -1,87 +0,0 @@ -class ScoreItem : Inventory -{ - Default - { - Height 10; - +COUNTITEM - Inventory.Amount 1; - +Inventory.ALWAYSPICKUP - } - - override bool TryPickup (in out Actor toucher) - { - toucher.Score += Amount; - GoAwayAndDie(); - return true; - } -} - -class Health : Inventory native -{ - native int PrevHealth; - - Default - { - Inventory.Amount 1; - Inventory.MaxAmount 0; - Inventory.PickupSound "misc/health_pkup"; - } -} - -class HealthPickup : Inventory native -{ - native int autousemode; - - Default - { - Inventory.DefMaxAmount; - +INVENTORY.INVBAR - } -} - -class Key : Inventory native -{ - native uint8 KeyNumber; - - Default - { - +DONTGIB; // Don't disappear due to a crusher - Inventory.InterHubAmount 0; - Inventory.PickupSound "misc/k_pkup"; - } -} - -class MapRevealer : Inventory -{ - //=========================================================================== - // - // AMapRevealer :: TryPickup - // - // A MapRevealer reveals the whole map for the player who picks it up. - // The MapRevealer doesn't actually go in your inventory. Instead, it sets - // a flag on the level. - // - //=========================================================================== - - override bool TryPickup (in out Actor toucher) - { - level.allmap = true; - GoAwayAndDie (); - return true; - } -} - -class PuzzleItem : Inventory native -{ - native int PuzzleItemNumber; - - Default - { - +NOGRAVITY - +INVENTORY.INVBAR - Inventory.DefMaxAmount; - Inventory.UseSound "PuzzleSuccess"; - Inventory.PickupSound "misc/i_pkup"; - } -} - diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 3ab022827..1d10d5895 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -105,6 +105,7 @@ class PlayerPawn : Actor native native int GetMaxHealth(); native bool ResetAirSupply (bool playgasp = false); + native void CheckWeaponSwitch(class item); } class PlayerChunk : PlayerPawn native @@ -127,8 +128,18 @@ class PlayerChunk : PlayerPawn native class PSprite : Object native { + enum PSPLayers + { + STRIFEHANDS = -1, + WEAPON = 1, + FLASH = 1000, + TARGETCENTER = 0x7fffffff - 2, + TARGETLEFT, + TARGETRIGHT, + }; + native readonly State CurState; - native readonly Actor Caller; + native Actor Caller; native readonly PSprite Next; native readonly PlayerInfo Owner; native SpriteID Sprite; @@ -164,7 +175,11 @@ enum EPlayerState struct PlayerInfo native // this is what internally is known as player_t { - native readonly PlayerPawn mo; + // technically engine constants but the only part of the playsim using them is the player. + const NOFIXEDCOLORMAP = -1; + const NUMCOLORMAPS = 32; + + native PlayerPawn mo; native uint8 playerstate; native uint original_oldbuttons; native readonly Class cls; diff --git a/wadsrc/static/zscript/shared/skies.txt b/wadsrc/static/zscript/shared/skies.txt index 72b86b14f..c817a3994 100644 --- a/wadsrc/static/zscript/shared/skies.txt +++ b/wadsrc/static/zscript/shared/skies.txt @@ -1,4 +1,40 @@ -class SkyViewpoint : Actor native + +/* +** a_skies.cpp +** Skybox-related actors +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2006-2017 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, self list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, self list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from self software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +class SkyViewpoint : Actor { default { @@ -7,9 +43,52 @@ class SkyViewpoint : Actor native +NOGRAVITY +DONTSPLASH } + + // arg0 = Visibility*4 for self skybox + + // If self actor has no TID, make it the default sky box + override void BeginPlay () + { + Super.BeginPlay (); + + if (tid == 0 && level.sectorPortals[0].mSkybox == null) + { + level.sectorPortals[0].mSkybox = self; + level.sectorPortals[0].mDestination = CurSector; + } + } + + override void OnDestroy () + { + // remove all sector references to ourselves. + for (int i = 0; i < level.sectorPortals.Size(); i++) + { + SectorPortal s = level.sectorPortals[i]; + if (s.mSkybox == self) + { + s.mSkybox = null; + // This is necessary to entirely disable EE-style skyboxes + // if their viewpoint gets deleted. + s.mFlags |= SectorPortal.FLAG_SKYFLATONLY; + } + } + + Super.OnDestroy(); + } + } -class SkyPicker : Actor native +//--------------------------------------------------------------------------- + +// arg0 = tid of matching SkyViewpoint +// A value of 0 means to use a regular stretched texture, in case +// there is a default SkyViewpoint in the level. +// +// arg1 = 0: set both floor and ceiling skybox +// = 1: set only ceiling skybox +// = 2: set only floor skybox + +class SkyPicker : Actor { default { @@ -18,14 +97,61 @@ class SkyPicker : Actor native +NOGRAVITY +DONTSPLASH } + + override void PostBeginPlay () + { + Actor box; + Super.PostBeginPlay (); + + if (args[0] == 0) + { + box = null; + } + else + { + let it = ActorIterator.Create(args[0], "SkyViewpoint"); + box = it.Next (); + } + + if (box == null && args[0] != 0) + { + A_Log(format("Can't find SkyViewpoint %d for sector %d\n", args[0], CurSector.Index())); + } + else + { + int boxindex = SectorPortal.GetSkyboxPortal(box); + // Do not override special portal types, only regular skies. + if (0 == (args[1] & 2)) + { + if (CurSector.GetPortalType(sector.ceiling) == SectorPortal.TYPE_SKYVIEWPOINT) + CurSector.Portals[sector.ceiling] = boxindex; + } + if (0 == (args[1] & 1)) + { + if (CurSector.GetPortalType(sector.floor) == SectorPortal.TYPE_SKYVIEWPOINT) + CurSector.Portals[sector.floor] = boxindex; + } + } + Destroy (); + } + } -class SkyCamCompat : SkyViewpoint native +class SkyCamCompat : SkyViewpoint { + override void BeginPlay () + { + // Skip SkyViewpoint's initialization, Actor's is not needed here. + } } -class StackPoint : SkyViewpoint native +class StackPoint : SkyViewpoint { + override void BeginPlay () + { + // Skip SkyViewpoint's initialization, Actor's is not needed here. + } + } class UpperStackLookOnly : StackPoint diff --git a/wadsrc/static/zscript/shared/soundenvironment.txt b/wadsrc/static/zscript/shared/soundenvironment.txt index 2a4d66adb..d7317bcbf 100644 --- a/wadsrc/static/zscript/shared/soundenvironment.txt +++ b/wadsrc/static/zscript/shared/soundenvironment.txt @@ -1,5 +1,5 @@ -class SoundEnvironment : Actor native +class SoundEnvironment : Actor { default { @@ -8,5 +8,28 @@ class SoundEnvironment : Actor native +NOGRAVITY +DONTSPLASH } -} + + override void PostBeginPlay () + { + Super.PostBeginPlay (); + if (!bDormant) + { + Activate (self); + } + } + override void Activate (Actor activator) + { + CurSector.SetEnvironmentID((args[0]<<8) | (args[1])); + } + + // Deactivate just exists so that you can flag the thing as dormant in an editor + // and not have it take effect. This is so you can use multiple environments in + // a single zone, with only one set not-dormant, so you know which one will take + // effect at the start. + override void Deactivate (Actor deactivator) + { + bDormant = true; + } + +} diff --git a/wadsrc/static/zscript/shared/soundsequence.txt b/wadsrc/static/zscript/shared/soundsequence.txt index 97ff8e9aa..c5e2b2604 100644 --- a/wadsrc/static/zscript/shared/soundsequence.txt +++ b/wadsrc/static/zscript/shared/soundsequence.txt @@ -1,3 +1,62 @@ +/* +** a_soundsequence.cpp +** Actors for independantly playing sound sequences in a map. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** A SoundSequence actor has two modes of operation: +** +** 1. If the sound sequence assigned to it has a slot, then a separate +** SoundSequenceSlot actor is spawned (if not already present), and +** this actor's sound sequence is added to its list of choices. This +** actor is then destroyed, never to be heard from again. The sound +** sequence for the slot is automatically played on the new +** SoundSequenceSlot actor, and it should at some point execute the +** randomsequence command so that it can pick one of the other +** sequences to play. The slot sequence should also end with restart +** so that more than one sequence will have a chance to play. +** +** In this mode, it is very much like world $ambient sounds defined +** in SNDINFO but more flexible. +** +** 2. If the sound sequence assigned to it has no slot, then it will play +** the sequence when activated and cease playing the sequence when +** deactivated. +** +** In this mode, it is very much like point $ambient sounds defined +** in SNDINFO but more flexible. +** +** To assign a sound sequence, set the SoundSequence's first argument to +** the ID of the corresponding environment sequence you want to use. If +** that sequence is a multiple-choice sequence, then the second argument +** selects which choice it picks. +*/ class AmbientSound : Actor native { @@ -17,7 +76,7 @@ class AmbientSoundNoGravity : AmbientSound } } -class SoundSequenceSlot : Actor native +class SoundSequenceSlot : Actor { default { @@ -25,9 +84,11 @@ class SoundSequenceSlot : Actor native +NOBLOCKMAP +DONTSPLASH } + + SeqNode sequence; } -class SoundSequence : Actor native +class SoundSequence : Actor { default { @@ -35,6 +96,86 @@ class SoundSequence : Actor native +NOBLOCKMAP +DONTSPLASH } + + //========================================================================== + // + // ASoundSequence :: Destroy + // + //========================================================================== + + override void OnDestroy () + { + StopSoundSequence (); + Super.OnDestroy(); + } + + //========================================================================== + // + // ASoundSequence :: PostBeginPlay + // + //========================================================================== + + override void PostBeginPlay () + { + Name slot = SeqNode.GetSequenceSlot (args[0], SeqNode.ENVIRONMENT); + + if (slot != 'none') + { // This is a slotted sound, so add it to the master for that slot + SoundSequenceSlot master; + let locator = ThinkerIterator.Create("SoundSequenceSlot"); + + while ((master = SoundSequenceSlot(locator.Next ()))) + { + if (master.Sequence.GetSequenceName() == slot) + { + break; + } + } + if (master == NULL) + { + master = SoundSequenceSlot(Spawn("SoundSequenceSlot")); + master.Sequence = master.StartSoundSequence (slot, 0); + } + master.Sequence.AddChoice (args[0], SeqNode.ENVIRONMENT); + Destroy (); + } + } + + //========================================================================== + // + // ASoundSequence :: MarkPrecacheSounds + // + //========================================================================== + + override void MarkPrecacheSounds() + { + Super.MarkPrecacheSounds(); + SeqNode.MarkPrecacheSounds(args[0], SeqNode.ENVIRONMENT); + } + + //========================================================================== + // + // ASoundSequence :: Activate + // + //========================================================================== + + override void Activate (Actor activator) + { + StartSoundSequenceID (args[0], SeqNode.ENVIRONMENT, args[1]); + } + + //========================================================================== + // + // ASoundSequence :: Deactivate + // + //========================================================================== + + override void Deactivate (Actor activator) + { + StopSoundSequence (); + } + + } // Heretic Sound sequences ----------------------------------------------------------- diff --git a/wadsrc/static/zscript/sounddata.txt b/wadsrc/static/zscript/sounddata.txt new file mode 100644 index 000000000..2496b8f8d --- /dev/null +++ b/wadsrc/static/zscript/sounddata.txt @@ -0,0 +1,20 @@ + +class SeqNode native +{ + enum ESeqType + { + PLATFORM, + DOOR, + ENVIRONMENT, + NUMSEQTYPES, + NOTRANS + }; + + native bool AreModesSameID(int sequence, int type, int mode1); + native bool AreModesSame(Name name, int mode1); + native Name GetSequenceName(); + native void AddChoice (int seqnum, int type); + native static Name GetSequenceSlot (int sequence, int type); + native static void MarkPrecacheSounds(int sequence, int type); +} + diff --git a/wadsrc_lights/static/filter/doom.doom1/gldefs.txt b/wadsrc_lights/static/filter/doom.doom1/gldefs.txt index 1d5e3aba0..d79ba5296 100644 --- a/wadsrc_lights/static/filter/doom.doom1/gldefs.txt +++ b/wadsrc_lights/static/filter/doom.doom1/gldefs.txt @@ -317,9 +317,9 @@ object BFGExtra // Barrel pulselight BARREL { - color 0.0 0.5 0.0 - size 30 - secondarySize 31 + color 0.0 0.3 0.0 + size 20 + secondarySize 21 interval 0.5 offset 0 36 0 dontlightself 1 @@ -629,9 +629,9 @@ object BlurSphere // Health Potion pulselight HEALTHPOTION { - color 0.0 0.0 0.6 - size 24 - secondarySize 27 + color 0.0 0.0 0.3 + size 16 + secondarySize 20 interval 2.0 attenuate 1 offset 0 10 0 @@ -645,9 +645,9 @@ object HealthBonus // Armour Helmet pulselight ARMORBONUS { - color 0.2 0.6 0.2 - size 24 - secondarySize 21 + color 0.1 0.3 0.1 + size 16 + secondarySize 20 interval 1.0 dontlightself 1 attenuate 1 @@ -715,16 +715,16 @@ object RedSkull // Green armour pointlight GREENARMOR1 { - color 0.0 0.6 0.0 - size 72 + color 0.0 0.3 0.0 + size 40 attenuate 1 offset 0 10 0 } pointlight GREENARMOR2 { - color 0.0 0.6 0.0 - size 48 + color 0.0 0.3 0.0 + size 30 attenuate 1 offset 0 10 0 } @@ -738,16 +738,16 @@ object GreenArmor // Blue armour pointlight BLUEARMOR1 { - color 0.0 0.0 0.6 - size 72 + color 0.0 0.0 0.3 + size 40 attenuate 1 offset 0 10 0 } pointlight BLUEARMOR2 { - color 0.0 0.0 0.6 - size 48 + color 0.0 0.0 0.3 + size 30 attenuate 1 offset 0 10 0 } diff --git a/wadsrc_lights/static/filter/doom.doom2/gldefs.txt b/wadsrc_lights/static/filter/doom.doom2/gldefs.txt index 1d5e3aba0..d79ba5296 100644 --- a/wadsrc_lights/static/filter/doom.doom2/gldefs.txt +++ b/wadsrc_lights/static/filter/doom.doom2/gldefs.txt @@ -317,9 +317,9 @@ object BFGExtra // Barrel pulselight BARREL { - color 0.0 0.5 0.0 - size 30 - secondarySize 31 + color 0.0 0.3 0.0 + size 20 + secondarySize 21 interval 0.5 offset 0 36 0 dontlightself 1 @@ -629,9 +629,9 @@ object BlurSphere // Health Potion pulselight HEALTHPOTION { - color 0.0 0.0 0.6 - size 24 - secondarySize 27 + color 0.0 0.0 0.3 + size 16 + secondarySize 20 interval 2.0 attenuate 1 offset 0 10 0 @@ -645,9 +645,9 @@ object HealthBonus // Armour Helmet pulselight ARMORBONUS { - color 0.2 0.6 0.2 - size 24 - secondarySize 21 + color 0.1 0.3 0.1 + size 16 + secondarySize 20 interval 1.0 dontlightself 1 attenuate 1 @@ -715,16 +715,16 @@ object RedSkull // Green armour pointlight GREENARMOR1 { - color 0.0 0.6 0.0 - size 72 + color 0.0 0.3 0.0 + size 40 attenuate 1 offset 0 10 0 } pointlight GREENARMOR2 { - color 0.0 0.6 0.0 - size 48 + color 0.0 0.3 0.0 + size 30 attenuate 1 offset 0 10 0 } @@ -738,16 +738,16 @@ object GreenArmor // Blue armour pointlight BLUEARMOR1 { - color 0.0 0.0 0.6 - size 72 + color 0.0 0.0 0.3 + size 40 attenuate 1 offset 0 10 0 } pointlight BLUEARMOR2 { - color 0.0 0.0 0.6 - size 48 + color 0.0 0.0 0.3 + size 30 attenuate 1 offset 0 10 0 } diff --git a/wadsrc_lights/static/filter/doom.freedoom/gldefs.txt b/wadsrc_lights/static/filter/doom.freedoom/gldefs.txt index 19aa9d0fd..1bb7c2b84 100644 --- a/wadsrc_lights/static/filter/doom.freedoom/gldefs.txt +++ b/wadsrc_lights/static/filter/doom.freedoom/gldefs.txt @@ -316,9 +316,9 @@ object BFGExtra // Barrel pulselight BARREL { - color 0.0 0.5 0.0 - size 30 - secondarySize 31 + color 0.0 0.3 0.0 + size 20 + secondarySize 21 interval 0.5 offset 0 36 0 dontlightself 1 @@ -628,9 +628,9 @@ object BlurSphere // Armour Helmet pulselight ARMORBONUS { - color 0.6 0.2 0.2 - size 24 - secondarySize 21 + color 0.3 0.1 0.1 + size 16 + secondarySize 20 interval 1.0 dontlightself 1 attenuate 1 @@ -657,7 +657,7 @@ object BlueSkull pulselight YELLOWKEY { color 0.6 0.6 0.0 - size 24 + size 15 secondarySize 27 interval 2.0 attenuate 1 @@ -698,7 +698,7 @@ object RedSkull pointlight GREENARMOR2 { color 0.4 0.0 0.0 - size 48 + size 40 attenuate 1 offset 0 10 0 }