# Conflicts:
#	src/r_things.cpp
#	src/r_things.h
This commit is contained in:
nashmuhandes 2016-07-05 21:52:38 +08:00
commit 4292311f53
86 changed files with 1893 additions and 908 deletions

View file

@ -284,7 +284,7 @@ enum ActorFlag4
enum ActorFlag5
{
MF5_DONTDRAIN = 0x00000001, // cannot be drained health from.
MF5_INSTATECALL = 0x00000002, // This actor is being run through CallStateChain
/* FREE SLOT 0x00000002*/
MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances.
MF5_NOFORWARDFALL = 0x00000008, // Does not make any actor fall forward by being damaged by this
MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret
@ -408,9 +408,11 @@ enum ActorRenderFlag
RF_SPRITETYPEMASK = 0x7000, // ---Different sprite types, not all implemented
RF_FACESPRITE = 0x0000, // Face sprite
RF_WALLSPRITE = 0x1000, // Wall sprite
RF_FLOORSPRITE = 0x2000, // Floor sprite
RF_FLATSPRITE = 0x2000, // Flat sprite
RF_VOXELSPRITE = 0x3000, // Voxel object
RF_INVISIBLE = 0x8000, // Don't bother drawing this actor
RF_ROLLSPRITE = 0x40000, //[marrub]roll the sprite billboard
RF_DONTFLIP = 0x80000, // Don't flip it when viewed from behind.
RF_FORCEYBILLBOARD = 0x10000, // [BB] OpenGL only: draw with y axis billboard, i.e. anchored to the floor (overrides gl_billboard_mode setting)
RF_FORCEXYBILLBOARD = 0x20000, // [BB] OpenGL only: draw with xy axis billboard, i.e. unanchored (overrides gl_billboard_mode setting)

View file

@ -1488,6 +1488,44 @@ FBaseCVar *FindCVarSub (const char *var_name, int namelen)
return var;
}
FBaseCVar *GetCVar(AActor *activator, const char *cvarname)
{
FBaseCVar *cvar = FindCVar(cvarname, nullptr);
// Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return nullptr.
if (cvar == nullptr || (cvar->GetFlags() & CVAR_IGNORE))
{
return nullptr;
}
else
{
// For userinfo cvars, redirect to GetUserCVar
if (cvar->GetFlags() & CVAR_USERINFO)
{
if (activator == nullptr || activator->player == nullptr)
{
return nullptr;
}
return GetUserCVar(int(activator->player - players), cvarname);
}
return cvar;
}
}
FBaseCVar *GetUserCVar(int playernum, const char *cvarname)
{
if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum])
{
return nullptr;
}
FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true));
FBaseCVar *cvar;
if (cvar_p == nullptr || (cvar = *cvar_p) == nullptr || (cvar->GetFlags() & CVAR_IGNORE))
{
return nullptr;
}
return cvar;
}
//===========================================================================
//
// C_CreateCVar

View file

@ -186,6 +186,10 @@ void C_BackupCVars (void);
FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev);
FBaseCVar *FindCVarSub (const char *var_name, int namelen);
// Used for ACS and DECORATE.
FBaseCVar *GetCVar(AActor *activator, const char *cvarname);
FBaseCVar *GetUserCVar(int playernum, const char *cvarname);
// Create a new cvar with the specified name and type
FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags);

View file

@ -16,7 +16,7 @@
#include <stdarg.h>
// the dec offsetof macro doesnt work very well...
#define myoffsetof(type,identifier) ((size_t)&((type *)1)->identifier - 1)
#define myoffsetof(type,identifier) ((size_t)&((type *)alignof(type))->identifier - alignof(type))
int Q_filelength (FILE *f);
bool FileExists (const char *filename);

View file

@ -807,11 +807,12 @@ void SetDehParams(FState *state, int codepointer)
VMFunctionBuilder buildit;
// Allocate registers used to pass parameters in.
// self, stateowner, state (all are pointers)
buildit.Registers[REGT_POINTER].Get(3);
buildit.Registers[REGT_POINTER].Get(NAP);
// Emit code to pass the standard action function parameters.
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 0);
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 1);
buildit.Emit(OP_PARAM, 0, REGT_POINTER, 2);
for (int i = 0; i < NAP; i++)
{
buildit.Emit(OP_PARAM, 0, REGT_POINTER, i);
}
// Emit code for action parameters.
int argcount = MBFCodePointerFactories[codepointer](buildit, value1, value2);
buildit.Emit(OP_TAIL_K, buildit.GetConstantAddress(sym->Variants[0].Implementation, ATAG_OBJECT), NAP + argcount, 0);
@ -2114,7 +2115,7 @@ static int PatchCodePtrs (int dummy)
else
{
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
if ((sym->Flags & (VARF_Method | VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > 3 && !(args[3] & VARF_Optional)))
if ((sym->Flags & (VARF_Method | VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
{
Printf("Frame %d: Incompatible code pointer '%s'\n", frame, Line2);
sym = NULL;
@ -2726,7 +2727,7 @@ static bool LoadDehSupp ()
else
{
TArray<DWORD> &args = sym->Variants[0].ArgFlags;
if ((sym->Flags & (VARF_Method|VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > 3 && !(args[3] & VARF_Optional)))
if ((sym->Flags & (VARF_Method|VARF_Action)) != (VARF_Method | VARF_Action) || (args.Size() > NAP && !(args[NAP] & VARF_Optional)))
{
sc.ScriptMessage("Incompatible code pointer '%s'", sc.String);
}
@ -3123,22 +3124,29 @@ bool ADehackedPickup::TryPickup (AActor *&toucher)
const char *ADehackedPickup::PickupMessage ()
{
return RealPickup->PickupMessage ();
if (RealPickup != nullptr)
return RealPickup->PickupMessage ();
else return "";
}
bool ADehackedPickup::ShouldStay ()
{
return RealPickup->ShouldStay ();
if (RealPickup != nullptr)
return RealPickup->ShouldStay ();
else return true;
}
bool ADehackedPickup::ShouldRespawn ()
{
return RealPickup->ShouldRespawn ();
if (RealPickup != nullptr)
return RealPickup->ShouldRespawn ();
else return false;
}
void ADehackedPickup::PlayPickupSound (AActor *toucher)
{
RealPickup->PlayPickupSound (toucher);
if (RealPickup != nullptr)
RealPickup->PlayPickupSound (toucher);
}
void ADehackedPickup::DoPickupSpecial (AActor *toucher)
@ -3146,19 +3154,19 @@ void ADehackedPickup::DoPickupSpecial (AActor *toucher)
Super::DoPickupSpecial (toucher);
// If the real pickup hasn't joined the toucher's inventory, make sure it
// doesn't stick around.
if (RealPickup->Owner != toucher)
if (RealPickup != nullptr && RealPickup->Owner != toucher)
{
RealPickup->Destroy ();
}
RealPickup = NULL;
RealPickup = nullptr;
}
void ADehackedPickup::Destroy ()
{
if (RealPickup != NULL)
if (RealPickup != nullptr)
{
RealPickup->Destroy ();
RealPickup = NULL;
RealPickup = nullptr;
}
Super::Destroy ();
}

View file

@ -557,7 +557,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
case 1: // Doom2.exe compatible with a few relaxed settings
v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|COMPATF_SPRITESORT|
COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_DEHHEALTH|COMPATF_CROSSDROPOFF|
COMPATF_LIGHT;
COMPATF_LIGHT|COMPATF_MASKEDMIDTEX;
w= COMPATF2_FLOORMOVE;
break;
@ -570,7 +570,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
break;
case 3: // Boom compat mode
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP;
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_MASKEDMIDTEX;
break;
case 4: // Old ZDoom compat mode
@ -580,12 +580,12 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_NOINITCALL)
case 5: // MBF compat mode
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_MUSHROOM|
COMPATF_MBFMONSTERMOVE|COMPATF_NOBLOCKFRIENDS;
COMPATF_MBFMONSTERMOVE|COMPATF_NOBLOCKFRIENDS|COMPATF_MASKEDMIDTEX;
break;
case 6: // Boom with some added settings to reenable some 'broken' behavior
v = COMPATF_TRACE|COMPATF_SOUNDTARGET|COMPATF_BOOMSCROLL|COMPATF_MISSILECLIP|COMPATF_NO_PASSMOBJ|
COMPATF_INVISIBILITY|COMPATF_CORPSEGIBS|COMPATF_HITSCAN|COMPATF_WALLRUN|COMPATF_NOTOSSDROPS;
COMPATF_INVISIBILITY|COMPATF_CORPSEGIBS|COMPATF_HITSCAN|COMPATF_WALLRUN|COMPATF_NOTOSSDROPS|COMPATF_MASKEDMIDTEX;
w = COMPATF2_POINTONLINE;
break;

View file

@ -381,6 +381,7 @@ class player_t
{
public:
player_t();
~player_t();
player_t &operator= (const player_t &p);
void Serialize (FArchive &arc);
@ -436,6 +437,7 @@ public:
AWeapon *ReadyWeapon;
AWeapon *PendingWeapon; // WP_NOCHANGE if not changing
TObjPtr<DPSprite> psprites; // view sprites (gun, etc)
int cheats; // bit flags
int timefreezer; // Player has an active time freezer
@ -455,7 +457,6 @@ public:
int extralight; // so gun flashes light up areas
short fixedcolormap; // can be set to REDCOLORMAP, etc.
short fixedlightlevel;
pspdef_t psprites[NUMPSPRITES]; // view sprites (gun, etc)
int morphTics; // player is a chicken/pig if > 0
PClassPlayerPawn *MorphedPlayerClass; // [MH] (for SBARINFO) class # for this player instance when morphed
int MorphStyle; // which effects to apply for this player instance when morphed
@ -527,6 +528,12 @@ public:
}
int GetSpawnClass();
// PSprite layers
void TickPSprites();
void DestroyPSprites();
DPSprite *FindPSprite(int layer);
DPSprite *GetPSprite(PSPLayers layer); // Used ONLY for compatibility with the old hardcoded layers.
};
// Bookkeeping on players - state.

View file

@ -60,6 +60,7 @@
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
EXTERN_CVAR(Bool, strictdecorate);
// PUBLIC DATA DEFINITIONS -------------------------------------------------
@ -3067,7 +3068,8 @@ void PClass::InsertIntoHash ()
if (found != NULL)
{ // This type has already been inserted
// ... but there is no need whatsoever to make it a fatal error!
Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars());
if (!strictdecorate) Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars());
else I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars());
TypeTable.ReplaceType(this, found, bucket);
}
else

View file

@ -127,11 +127,11 @@ DMovingCeiling::DMovingCeiling ()
{
}
DMovingCeiling::DMovingCeiling (sector_t *sector)
DMovingCeiling::DMovingCeiling (sector_t *sector, bool interpolate)
: DMover (sector)
{
sector->ceilingdata = this;
interpolation = sector->SetInterpolation(sector_t::CeilingMove, true);
if (interpolate) interpolation = sector->SetInterpolation(sector_t::CeilingMove, true);
}
bool sector_t::MoveAttached(int crush, double move, int floorOrCeiling, bool resetfailed)

View file

@ -49,7 +49,7 @@ class DMovingCeiling : public DMover
{
DECLARE_CLASS (DMovingCeiling, DMover)
public:
DMovingCeiling (sector_t *sector);
DMovingCeiling (sector_t *sector, bool interpolate = true);
protected:
DMovingCeiling ();
};

View file

@ -1573,7 +1573,7 @@ void FParser::SF_FloorHeight(void)
sectors[i].floorplane.PointToDist (sectors[i].centerspot, dest),
crush? 10:-1,
(dest > sectors[i].CenterFloor()) ? 1 : -1,
false) != EMoveResult::crushed)
false) == EMoveResult::crushed)
{
returnval = 0;
}
@ -1662,7 +1662,7 @@ void FParser::SF_CeilingHeight(void)
sectors[i].ceilingplane.PointToDist (sectors[i].centerspot, dest),
crush? 10:-1,
(dest > sectors[i].CenterCeiling()) ? 1 : -1,
false) != EMoveResult::crushed)
false) == EMoveResult::crushed)
{
returnval = 0;
}
@ -3473,12 +3473,7 @@ void FParser::SF_Resurrect()
mo->SetState(state);
mo->Height = mo->GetDefault()->Height;
mo->radius = mo->GetDefault()->radius;
mo->flags = mo->GetDefault()->flags;
mo->flags2 = mo->GetDefault()->flags2;
mo->flags3 = mo->GetDefault()->flags3;
mo->flags4 = mo->GetDefault()->flags4;
mo->flags5 = mo->GetDefault()->flags5;
mo->health = mo->GetDefault()->health;
mo->Revive();
mo->target = NULL;
}
}
@ -3766,30 +3761,6 @@ void FParser::SF_SetCorona(void)
t_return.value.i = 0;
}
//==========================================================================
//
// new for GZDoom: Call a Hexen line special (deprecated, superseded by direct use)
//
//==========================================================================
void FParser::SF_Ls()
{
int args[5]={0,0,0,0,0};
int spc;
if (CheckArgs(1))
{
spc=intvalue(t_argv[0]);
for(int i=0;i<5;i++)
{
if (t_argc>=i+2) args[i]=intvalue(t_argv[i+1]);
}
if (spc>=0 && spc<256)
P_ExecuteSpecial(spc, NULL,Script->trigger,false, args[0],args[1],args[2],args[3],args[4]);
}
}
//==========================================================================
//
// new for GZDoom: Gets the levelnum
@ -4024,17 +3995,6 @@ void FParser::SF_KillInSector()
}
}
//==========================================================================
//
// new for GZDoom: Sets a sector's type
//
//==========================================================================
void FParser::SF_SectorType(void)
{
// I don't think this was ever used publicly so I'm not going to bother fixing it.
}
//==========================================================================
//
// new for GZDoom: Sets a new line trigger type (Doom format!)
@ -4069,30 +4029,6 @@ void FParser::SF_SetLineTrigger()
}
//==========================================================================
//
//
//
//==========================================================================
void FParser::SF_ChangeTag()
{
// Development garbage!
}
//==========================================================================
//
//
//
//==========================================================================
void FParser::SF_WallGlow()
{
// Development garbage!
}
//==========================================================================
//
// new for GZDoom: Call a Hexen line special
@ -4510,13 +4446,10 @@ void init_functions(void)
// new for GZDoom
gscr->NewFunction("spawnshot2", &FParser::SF_SpawnShot2);
gscr->NewFunction("setcolor", &FParser::SF_SetColor);
gscr->NewFunction("sectortype", &FParser::SF_SectorType);
gscr->NewFunction("wallglow", &FParser::SF_WallGlow);
gscr->NewFunction("objradius", &FParser::SF_MobjRadius);
gscr->NewFunction("objheight", &FParser::SF_MobjHeight);
gscr->NewFunction("thingcount", &FParser::SF_ThingCount);
gscr->NewFunction("killinsector", &FParser::SF_KillInSector);
gscr->NewFunction("changetag", &FParser::SF_ChangeTag);
gscr->NewFunction("levelnum", &FParser::SF_LevelNum);
// new inventory
@ -4525,8 +4458,6 @@ void init_functions(void)
gscr->NewFunction("checkinventory", &FParser::SF_CheckInventory);
gscr->NewFunction("setweapon", &FParser::SF_SetWeapon);
gscr->NewFunction("ls", &FParser::SF_Ls); // execute Hexen type line special
// Dummies - shut up warnings
gscr->NewFunction("setcorona", &FParser::SF_SetCorona);
}

View file

@ -38,7 +38,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch)
if (self->player != NULL)
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON())
if (weapon != NULL && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
@ -73,16 +73,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol)
bool accurate;
if (self->player != NULL)
if (self->player != nullptr)
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
P_SetPsprite (self->player, ps_flash, weapon->FindState(NAME_Flash));
self->player->psprites[ps_flash].processPending = true;
P_SetPsprite(self->player, PSP_FLASH, weapon->FindState(NAME_Flash), true);
}
self->player->mo->PlayAttacking2 ();
@ -161,7 +160,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw)
slope = P_AimLineAttack (self, angle, range, &t) + spread_z * (pr_saw.Random2() / 255.);
AWeapon *weapon = self->player->ReadyWeapon;
if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!t.linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_WEAPON())
if ((weapon != NULL) && !(flags & SF_NOUSEAMMO) && !(!t.linetarget && (flags & SF_NOUSEAMMOMISS)) && !(weapon->WeaponFlags & WIF_DEHAMMO) && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
@ -263,19 +262,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun)
int i;
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM);
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
self->player->psprites[ps_flash].processPending = true;
P_SetPsprite(player, PSP_FLASH, weapon->FindState(NAME_Flash), true);
}
player->mo->PlayAttacking2 ();
@ -300,19 +298,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2)
int damage;
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
S_Sound (self, CHAN_WEAPON, "weapons/sshotf", 1, ATTN_NORM);
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2))
return 0;
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
self->player->psprites[ps_flash].processPending = true;
P_SetPsprite(player, PSP_FLASH, weapon->FindState(NAME_Flash), true);
}
player->mo->PlayAttacking2 ();
@ -384,15 +381,13 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i
if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates)
{
// we're ok so set the state
P_SetPsprite (player, ps_flash, flashstate + index);
player->psprites[ps_flash].processPending = true;
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
return;
}
else
{
// oh, no! The state is beyond the end of the state table so use the original flash state.
P_SetPsprite (player, ps_flash, flashstate);
player->psprites[ps_flash].processPending = true;
P_SetPsprite(player, PSP_FLASH, flashstate, true);
return;
}
}
@ -408,8 +403,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i
{ // Invalid state. With no index offset, it should at least be valid.
index = 0;
}
P_SetPsprite (player, ps_flash, flashstate + index);
player->psprites[ps_flash].processPending = true;
P_SetPsprite(player, PSP_FLASH, flashstate + index, true);
}
//
@ -421,13 +415,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun)
player_t *player;
if (self == NULL || NULL == (player = self->player))
if (self == nullptr || nullptr == (player = self->player))
{
return 0;
}
AWeapon *weapon = player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
@ -435,12 +429,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireCGun)
S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM);
FState *flash = weapon->FindState(NAME_Flash);
if (flash != NULL)
if (flash != nullptr)
{
// [RH] Fix for Sparky's messed-up Dehacked patch! Blargh!
FState * atk = weapon->FindState(NAME_Fire);
int theflash = clamp (int(player->psprites[ps_weapon].state - atk), 0, 1);
int theflash = clamp (int(player->GetPSprite(PSP_WEAPON)->GetState() - atk), 0, 1);
if (flash[theflash].sprite != flash->sprite)
{
@ -471,7 +465,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMissile)
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
@ -498,7 +492,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireSTGrenade)
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
@ -526,7 +520,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePlasma)
return 0;
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0;
@ -581,21 +575,21 @@ static void FireRailgun(AActor *self, int offset_xy, bool fromweapon)
DEFINE_ACTION_FUNCTION(AActor, A_FireRailgun)
{
PARAM_ACTION_PROLOGUE;
FireRailgun(self, 0, ACTION_CALL_FROM_WEAPON());
FireRailgun(self, 0, ACTION_CALL_FROM_PSPRITE());
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunRight)
{
PARAM_ACTION_PROLOGUE;
FireRailgun(self, 10, ACTION_CALL_FROM_WEAPON());
FireRailgun(self, 10, ACTION_CALL_FROM_PSPRITE());
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_FireRailgunLeft)
{
PARAM_ACTION_PROLOGUE;
FireRailgun(self, -10, ACTION_CALL_FROM_WEAPON());
FireRailgun(self, -10, ACTION_CALL_FROM_PSPRITE());
return 0;
}
@ -621,7 +615,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG)
}
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, deh.BFGCells))
return 0;
@ -636,6 +630,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireBFG)
// A_BFGSpray
// Spawn a BFG explosion on every monster in view
//
enum BFG_Flags
{
BFGF_HURTSOURCE = 1,
BFGF_MISSILEORIGIN = 2,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
{
PARAM_ACTION_PROLOGUE;
@ -646,12 +646,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
PARAM_FLOAT_OPT (distance) { distance = 0; }
PARAM_ANGLE_OPT (vrange) { vrange = 0.; }
PARAM_INT_OPT (defdamage) { defdamage = 0; }
PARAM_INT_OPT (flags) { flags = 0; }
int i;
int j;
int damage;
DAngle an;
FTranslatedLineTarget t;
AActor *originator;
if (spraytype == NULL) spraytype = PClass::FindActor("BFGExtra");
if (numrays <= 0) numrays = 40;
@ -664,13 +666,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
if (!self->target)
return 0;
// [XA] Set the originator of the rays to the projectile (self) if
// the new flag is set, else set it to the player (self->target)
originator = (flags & BFGF_MISSILEORIGIN) ? self : (AActor *)(self->target);
// offset angles from its attack angle
for (i = 0; i < numrays; i++)
{
an = self->Angles.Yaw - angle / 2 + angle / numrays*i;
// self->target is the originator (player) of the missile
P_AimLineAttack(self->target, an, distance, &t, vrange);
P_AimLineAttack(originator, an, distance, &t, vrange);
if (t.linetarget != NULL)
{
@ -681,7 +686,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
if (spray != NULL)
{
if (spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == t.linetarget->GetSpecies())
if ((spray->flags6 & MF6_MTHRUSPECIES && self->target->GetSpecies() == t.linetarget->GetSpecies()) ||
(!(flags & BFGF_HURTSOURCE) && self->target == t.linetarget)) // [XA] Don't hit oneself unless we say so.
{
spray->Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them.
continue;
@ -704,7 +710,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
damage = defdamage;
}
int newdam = P_DamageMobj(t.linetarget, self->target, self->target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource.Degrees);
int newdam = P_DamageMobj(t.linetarget, originator, self->target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource.Degrees);
P_TraceBleed(newdam > 0 ? newdam : damage, &t, self);
}
}
@ -745,7 +751,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireOldBFG)
}
AWeapon *weapon = self->player->ReadyWeapon;
if (!ACTION_CALL_FROM_WEAPON()) weapon = NULL;
if (!ACTION_CALL_FROM_PSPRITE()) weapon = NULL;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))

View file

@ -1751,6 +1751,8 @@ void G_DoPlayerPop(int playernum)
players[playernum].mo = NULL;
players[playernum].camera = NULL;
}
players[playernum].DestroyPSprites();
}
void G_ScreenShot (char *filename)

View file

@ -123,9 +123,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Feathers)
void P_UpdateBeak (AActor *self)
{
if (self->player != NULL)
if (self->player != nullptr)
{
self->player->psprites[ps_weapon].sy = WEAPONTOP + self->player->chickenPeck / 2;
self->player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + self->player->chickenPeck / 2;
}
}
@ -141,12 +141,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakRaise)
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
player->psprites[ps_weapon].sy = WEAPONTOP;
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState());
player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP;
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetReadyState());
return 0;
}
@ -192,7 +192,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1)
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
player->psprites[ps_weapon].tics -= pr_beakatkpl1() & 7;
player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl1() & 7;
return 0;
}
@ -227,6 +227,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2)
}
P_PlayPeck (player->mo);
player->chickenPeck = 12;
player->psprites[ps_weapon].tics -= pr_beakatkpl2()&3;
player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl2()&3;
return 0;
}

View file

@ -287,8 +287,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_GenWizard)
self->SetState (self->FindState(NAME_Death));
self->flags &= ~MF_MISSILE;
mo->master = self->target;
// Heretic did not offset it by TELEFOGHEIGHT, so I won't either.
Spawn<ATeleportFog> (self->Pos(), ALLOW_REPLACE);
P_SpawnTeleportFog(self, self->Pos(), false, true);
}
}
return 0;

View file

@ -17,6 +17,7 @@
#include "farchive.h"
#include "d_player.h"
#include "a_morph.h"
#include "p_spec.h"
// Include all the other Heretic stuff here to reduce compile time
#include "a_chicken.cpp"

View file

@ -259,7 +259,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack)
FTranslatedLineTarget t;
int actualdamage = 0;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
@ -267,13 +267,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GauntletAttack)
PARAM_INT(power);
AWeapon *weapon = player->ReadyWeapon;
if (weapon != NULL)
if (weapon != nullptr)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
player->GetPSprite(PSP_WEAPON)->x = ((pr_gatk() & 3) - 2);
player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + (pr_gatk() & 3);
}
player->psprites[ps_weapon].sx = ((pr_gatk()&3)-2);
player->psprites[ps_weapon].sy = WEAPONTOP + (pr_gatk()&3);
Angle = self->Angles.Yaw;
if (power)
{
@ -425,7 +426,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1)
AActor *ball;
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
@ -436,13 +437,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMacePL1)
return 0;
}
AWeapon *weapon = player->ReadyWeapon;
if (weapon != NULL)
if (weapon != nullptr)
{
if (!weapon->DepleteAmmo(weapon->bAltFire))
return 0;
player->GetPSprite(PSP_WEAPON)->x = ((pr_maceatk() & 3) - 2);
player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP + (pr_maceatk() & 3);
}
player->psprites[ps_weapon].sx = ((pr_maceatk() & 3) - 2);
player->psprites[ps_weapon].sy = WEAPONTOP + (pr_maceatk() & 3);
ball = P_SpawnPlayerMissile(self, PClass::FindActor("MaceFX1"), self->Angles.Yaw + (((pr_maceatk() & 7) - 4) * (360. / 256)));
if (ball)
{
@ -1158,11 +1160,11 @@ IMPLEMENT_CLASS (APhoenixRodPowered)
void APhoenixRodPowered::EndPowerup ()
{
P_SetPsprite (Owner->player, ps_weapon, SisterWeapon->GetReadyState());
DepleteAmmo (bAltFire);
Owner->player->refire = 0;
S_StopSound (Owner, CHAN_WEAPON);
Owner->player->ReadyWeapon = SisterWeapon;
P_SetPsprite(Owner->player, PSP_WEAPON, SisterWeapon->GetReadyState());
}
class APhoenixFX1 : public AActor
@ -1298,7 +1300,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2)
player_t *player;
APhoenixRod *flamethrower;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
@ -1306,9 +1308,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2)
soundid = "weapons/phoenixpowshoot";
flamethrower = static_cast<APhoenixRod *> (player->ReadyWeapon);
if (flamethrower == NULL || --flamethrower->FlameCount == 0)
if (flamethrower == nullptr || --flamethrower->FlameCount == 0)
{ // Out of flame
P_SetPsprite (player, ps_weapon, flamethrower->FindState("Powerdown"));
P_SetPsprite(player, PSP_WEAPON, flamethrower->FindState("Powerdown"));
player->refire = 0;
S_StopSound (self, CHAN_WEAPON);
return 0;

View file

@ -106,7 +106,7 @@ DEFINE_ACTION_FUNCTION_PARAMS (AActor, A_Blast)
AActor *mo;
TThinkerIterator<AActor> iterator;
if (self->player && (blastflags & BF_USEAMMO) && ACTION_CALL_FROM_WEAPON())
if (self->player && (blastflags & BF_USEAMMO) && ACTION_CALL_FROM_PSPRITE())
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL && !weapon->DepleteAmmo(weapon->bAltFire))

View file

@ -58,7 +58,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
FTranslatedLineTarget t;
PClassActor *puff;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
@ -77,7 +77,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
if (t.linetarget)
{
P_LineAttack(pmo, angle, 1.5 * MELEERANGE, slope, damage, NAME_Melee, puff, false, &t);
if (t.linetarget != NULL)
if (t.linetarget != nullptr)
{
pmo->Angles.Yaw = t.angleFromSource;
if (((t.linetarget->player && (!t.linetarget->IsTeammate(pmo) || level.teamdamage != 0)) || t.linetarget->flags3&MF3_ISMONSTER)
@ -89,13 +89,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck)
{
pmo->health = player->health = newLife;
}
if (weapon != NULL)
if (weapon != nullptr)
{
FState * newstate = weapon->FindState("Drain");
if (newstate != NULL) P_SetPsprite(player, ps_weapon, newstate);
if (newstate != nullptr) P_SetPsprite(player, PSP_WEAPON, newstate);
}
}
if (weapon != NULL)
if (weapon != nullptr)
{
weapon->DepleteAmmo(weapon->bAltFire, false);
}
@ -187,7 +187,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheckBlink)
{
if (!--self->weaponspecial)
{
P_SetPsprite (self->player, ps_weapon, self->player->ReadyWeapon->FindState ("Blink"));
P_SetPsprite(self->player, PSP_WEAPON, self->player->ReadyWeapon->FindState ("Blink"));
self->weaponspecial = (pr_blink()+50)>>2;
}
else

View file

@ -70,13 +70,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReady)
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("ReadyGlow"));
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("ReadyGlow"));
}
else
{
@ -97,13 +97,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckReadyG)
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount <= 0)
{
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("Ready"));
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Ready"));
}
else
{
@ -124,13 +124,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUp)
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("SelectGlow"));
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("SelectGlow"));
}
else
{
@ -151,13 +151,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckUpG)
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount <= 0)
{
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("Select"));
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Select"));
}
else
{
@ -178,13 +178,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeCheckAtk)
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
if (player->ReadyWeapon->Ammo1->Amount)
{
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("FireGlow"));
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("FireGlow"));
}
return 0;
}
@ -210,7 +210,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack)
PClassActor *pufftype;
FTranslatedLineTarget t;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
@ -241,7 +241,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FAxeAttack)
if (t.linetarget)
{
P_LineAttack(pmo, angle, AXERANGE, slope, damage, NAME_Melee, pufftype, true, &t);
if (t.linetarget != NULL)
if (t.linetarget != nullptr)
{
if (t.linetarget->flags3&MF3_ISMONSTER || t.linetarget->player)
{
@ -265,15 +265,15 @@ axedone:
if (useMana == 2)
{
AWeapon *weapon = player->ReadyWeapon;
if (weapon != NULL)
if (weapon != nullptr)
{
weapon->DepleteAmmo (weapon->bAltFire, false);
if ((weapon->Ammo1 == NULL || weapon->Ammo1->Amount == 0) &&
if ((weapon->Ammo1 == nullptr || weapon->Ammo1->Amount == 0) &&
(!(weapon->WeaponFlags & WIF_PRIMARY_USES_BOTH) ||
weapon->Ammo2 == NULL || weapon->Ammo2->Amount == 0))
weapon->Ammo2 == nullptr || weapon->Ammo2->Amount == 0))
{
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState ("Fire") + 5);
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState ("Fire") + 5);
}
}
}

View file

@ -105,7 +105,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack)
int i;
player_t *player;
if (NULL == (player = self->player))
if (nullptr == (player = self->player))
{
return 0;
}
@ -120,7 +120,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FPunchAttack)
if (pmo->weaponspecial >= 3)
{
pmo->weaponspecial = 0;
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->FindState("Fire2"));
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState("Fire2"));
S_Sound (pmo, CHAN_VOICE, "*fistgrunt", 1, ATTN_NORM);
}
return 0;

View file

@ -37,9 +37,9 @@ void APigPlayer::MorphPlayerThink ()
}
if(Vel.X == 0 && Vel.Y == 0 && pr_pigplayerthink() < 64)
{ // Snout sniff
if (player->ReadyWeapon != NULL)
if (player->ReadyWeapon != nullptr)
{
P_SetPsprite(player, ps_weapon, player->ReadyWeapon->FindState("Grunt"));
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState("Grunt"));
}
S_Sound (this, CHAN_VOICE, "PigActive1", 1, ATTN_NORM); // snort
return;

View file

@ -372,9 +372,9 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
bool wantFast;
int i;
G_ClearHubInfo();
if (!savegamerestore)
{
G_ClearHubInfo();
G_ClearSnapshots ();
P_RemoveDefereds ();

View file

@ -1109,17 +1109,17 @@ void APowerWeaponLevel2::InitEffect ()
Super::InitEffect();
if (Owner->player == NULL)
if (Owner->player == nullptr)
return;
weapon = Owner->player->ReadyWeapon;
if (weapon == NULL)
if (weapon == nullptr)
return;
sister = weapon->SisterWeapon;
if (sister == NULL)
if (sister == nullptr)
return;
if (!(sister->WeaponFlags & WIF_POWERED_UP))
@ -1131,7 +1131,7 @@ void APowerWeaponLevel2::InitEffect ()
if (weapon->GetReadyState() != sister->GetReadyState())
{
P_SetPsprite (Owner->player, ps_weapon, sister->GetReadyState());
P_SetPsprite(Owner->player, PSP_WEAPON, sister->GetReadyState());
}
}
@ -1294,29 +1294,42 @@ void APowerTargeter::Travelled ()
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) == NULL)
if ((player = Owner->player) == nullptr)
return;
FState *state = FindState("Targeter");
if (state != NULL)
if (state != nullptr)
{
P_SetPsprite (player, ps_targetcenter, state + 0);
P_SetPsprite (player, ps_targetleft, state + 1);
P_SetPsprite (player, ps_targetright, state + 2);
P_SetPsprite(player, PSP_TARGETCENTER, state + 0);
P_SetPsprite(player, PSP_TARGETLEFT, state + 1);
P_SetPsprite(player, PSP_TARGETRIGHT, state + 2);
}
player->psprites[ps_targetcenter].sx = (160-3);
player->psprites[ps_targetcenter].sy =
player->psprites[ps_targetleft].sy =
player->psprites[ps_targetright].sy = (100-3);
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.
InitEffect();
}
bool APowerTargeter::HandlePickup(AInventory *item)
{
if (Super::HandlePickup(item))
@ -1327,13 +1340,11 @@ bool APowerTargeter::HandlePickup(AInventory *item)
return false;
}
void APowerTargeter::DoEffect ()
{
Super::DoEffect ();
if (Owner != NULL && Owner->player != NULL)
if (Owner != nullptr && Owner->player != nullptr)
{
player_t *player = Owner->player;
@ -1342,17 +1353,17 @@ void APowerTargeter::DoEffect ()
{
FState *state = FindState("Targeter");
if (state != NULL)
if (state != nullptr)
{
if (EffectTics & 32)
{
P_SetPsprite (player, ps_targetright, NULL);
P_SetPsprite (player, ps_targetleft, state+1);
P_SetPsprite(player, PSP_TARGETRIGHT, nullptr);
P_SetPsprite(player, PSP_TARGETLEFT, state + 1);
}
else if (EffectTics & 16)
{
P_SetPsprite (player, ps_targetright, state+2);
P_SetPsprite (player, ps_targetleft, NULL);
P_SetPsprite(player, PSP_TARGETRIGHT, state + 2);
P_SetPsprite(player, PSP_TARGETLEFT, nullptr);
}
}
}
@ -1362,11 +1373,17 @@ void APowerTargeter::DoEffect ()
void APowerTargeter::EndEffect ()
{
Super::EndEffect();
if (Owner != NULL && Owner->player != NULL)
if (Owner != nullptr && Owner->player != nullptr)
{
P_SetPsprite (Owner->player, ps_targetcenter, NULL);
P_SetPsprite (Owner->player, ps_targetleft, NULL);
P_SetPsprite (Owner->player, ps_targetright, 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.
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);
}
}
@ -1374,10 +1391,10 @@ void APowerTargeter::PositionAccuracy ()
{
player_t *player = Owner->player;
if (player != NULL)
if (player != nullptr)
{
player->psprites[ps_targetleft].sx = (160-3) - ((100 - player->mo->accuracy));
player->psprites[ps_targetright].sx = (160-3)+ ((100 - player->mo->accuracy));
player->GetPSprite(PSP_TARGETLEFT)->x = (160-3) - ((100 - player->mo->accuracy));
player->GetPSprite(PSP_TARGETRIGHT)->x = (160-3)+ ((100 - player->mo->accuracy));
}
}

View file

@ -182,6 +182,7 @@ protected:
void EndEffect ();
void PositionAccuracy ();
void Travelled ();
void AttachToOwner(AActor *other);
bool HandlePickup(AInventory *item);
};

View file

@ -608,15 +608,18 @@ bool AWeapon::DepleteAmmo (bool altFire, bool checkEnough, int ammouse)
void AWeapon::PostMorphWeapon ()
{
if (Owner == NULL)
DPSprite *pspr;
if (Owner == nullptr)
{
return;
}
Owner->player->PendingWeapon = WP_NOCHANGE;
Owner->player->ReadyWeapon = this;
Owner->player->psprites[ps_weapon].sy = WEAPONBOTTOM;
Owner->player->refire = 0;
P_SetPsprite (Owner->player, ps_weapon, GetUpState());
pspr = Owner->player->GetPSprite(PSP_WEAPON);
pspr->y = WEAPONBOTTOM;
pspr->SetState(GetUpState());
}
//===========================================================================

View file

@ -2786,7 +2786,7 @@ class CommandDrawBar : public SBarInfoCommand
// [BL] Since we used a percentage (in order to get the most fluid animation)
// we need to establish a cut off point so the last pixel won't hang as the animation slows
if(pixel == -1 && statusBar->Images[foreground])
pixel = MAX(1., 1./statusBar->Images[foreground]->GetWidth());
pixel = MAX(1 / 65536., 1./statusBar->Images[foreground]->GetWidth());
if(fabs(drawValue - value) < pixel)
drawValue = value;

View file

@ -115,7 +115,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Beacon)
rebel->SetState (rebel->SeeState);
rebel->Angles.Yaw = self->Angles.Yaw;
Spawn<ATeleportFog> (rebel->Vec3Angle(20., self->Angles.Yaw, TELEFOGHEIGHT), ALLOW_REPLACE);
P_SpawnTeleportFog(rebel, rebel->Vec3Angle(20., self->Angles.Yaw, 0), false, true);
if (--self->health < 0)
{
self->SetState(self->FindState(NAME_Death));

View file

@ -317,7 +317,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
double speed = (anglespeed % 10) / 16.;
DAngle an = (anglespeed / 10) * (360 / 8.);
self->VelFromAngle(an, speed);
self->Thrust(an, speed);
}
}
return 0;
@ -350,14 +350,24 @@ DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns)
S_Sound (self, CHAN_VOICE, "human/imonfire", 1, ATTN_NORM);
if (self->player != NULL && self->player->mo == self)
if (self->player != nullptr && self->player->mo == self)
{
P_SetPsprite (self->player, ps_weapon, self->FindState("FireHands"));
P_SetPsprite (self->player, ps_flash, NULL);
self->player->ReadyWeapon = NULL;
self->player->PendingWeapon = WP_NOCHANGE;
self->player->playerstate = PST_LIVE;
self->player->extralight = 3;
FState *firehands = self->FindState("FireHands");
if (firehands != NULL)
{
DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS);
if (psp != nullptr)
{
psp->SetState(firehands);
psp->Flags &= PSPF_ADDWEAPON | PSPF_ADDBOB;
psp->y = WEAPONTOP;
}
self->player->ReadyWeapon = nullptr;
self->player->PendingWeapon = WP_NOCHANGE;
self->player->playerstate = PST_LIVE;
self->player->extralight = 3;
}
}
return 0;
}
@ -376,12 +386,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer)
{
PARAM_ACTION_PROLOGUE;
if (self->player != NULL && self->player->mo == self)
if (self->player != nullptr && self->player->mo == self)
{
self->player->playerstate = PST_DEAD;
P_SetPsprite (self->player, ps_weapon,
self->player->psprites[ps_weapon].state +
(self->FindState("FireHandsLower") - self->FindState("FireHands")));
DPSprite *psp;
psp = self->player->GetPSprite(PSP_STRIFEHANDS);
FState *firehandslower = self->FindState("FireHandsLower");
FState *firehands = self->FindState("FireHands");
if (firehandslower != NULL && firehands != NULL && firehands < firehandslower)
psp->SetState(psp->GetState() + (firehandslower - firehands));
}
return 0;
}
@ -390,13 +404,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_HandLower)
{
PARAM_ACTION_PROLOGUE;
if (self->player != NULL)
if (self->player != nullptr)
{
pspdef_t *psp = &self->player->psprites[ps_weapon];
psp->sy += 9;
if (psp->sy > WEAPONBOTTOM*2)
DPSprite *psp = self->player->GetPSprite(PSP_STRIFEHANDS);
psp->y += 9;
if (psp->y > WEAPONBOTTOM*2)
{
P_SetPsprite (self->player, ps_weapon, NULL);
psp->SetState(nullptr);
}
if (self->player->extralight > 0) self->player->extralight--;
}

View file

@ -216,10 +216,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearFlash)
player_t *player = self->player;
if (player == NULL)
if (player == nullptr)
return 0;
P_SetPsprite (player, ps_flash, NULL);
P_SetPsprite (player, PSP_FLASH, nullptr);
return 0;
}
@ -233,9 +233,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_ShowElectricFlash)
{
PARAM_ACTION_PROLOGUE;
if (self->player != NULL)
if (self->player != nullptr)
{
P_SetPsprite (self->player, ps_flash, self->player->ReadyWeapon->FindState(NAME_Flash));
P_SetPsprite (self->player, PSP_FLASH, self->player->ReadyWeapon->FindState(NAME_Flash));
}
return 0;
}
@ -498,10 +498,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireMauler2Pre)
S_Sound (self, CHAN_WEAPON, "weapons/mauler2charge", 1, ATTN_NORM);
if (self->player != NULL)
if (self->player != nullptr)
{
self->player->psprites[ps_weapon].sx += pr_mauler2.Random2() / 64.;
self->player->psprites[ps_weapon].sy += pr_mauler2.Random2() / 64.;
self->player->GetPSprite(PSP_WEAPON)->x += pr_mauler2.Random2() / 64.;
self->player->GetPSprite(PSP_WEAPON)->y += pr_mauler2.Random2() / 64.;
}
return 0;
}
@ -698,24 +698,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade)
DAngle an;
AWeapon *weapon;
if (player == NULL || grenadetype == NULL)
if (player == nullptr || grenadetype == nullptr)
return 0;
if ((weapon = player->ReadyWeapon) == NULL)
if ((weapon = player->ReadyWeapon) == nullptr)
return 0;
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
P_SetPsprite (player, ps_flash, flash);
self->player->psprites[ps_flash].processPending = true;
P_SetPsprite (player, PSP_FLASH, flash, true);
if (grenadetype != NULL)
if (grenadetype != nullptr)
{
self->AddZ(32);
grenade = P_SpawnSubMissile (self, grenadetype, self);
self->AddZ(-32);
if (grenade == NULL)
if (grenade == nullptr)
return 0;
if (grenade->SeeSound != 0)
@ -849,15 +848,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilView)
{
PARAM_ACTION_PROLOGUE;
DPSprite *pspr;
int pieces;
if (self->player == NULL)
if (self->player == nullptr)
{
return 0;
}
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
P_SetPsprite (self->player, ps_weapon,
self->player->psprites[ps_weapon].state + pieces);
pspr = self->player->GetPSprite(PSP_WEAPON);
pspr->SetState(pspr->GetState() + pieces);
return 0;
}
@ -875,9 +875,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown)
{
PARAM_ACTION_PROLOGUE;
DPSprite *pspr;
int pieces;
if (self->player == NULL)
if (self->player == nullptr)
{
return 0;
}
@ -887,8 +888,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown)
{
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
}
P_SetPsprite (self->player, ps_weapon,
self->player->psprites[ps_weapon].state + pieces);
pspr = self->player->GetPSprite(PSP_WEAPON);
pspr->SetState(pspr->GetState() + pieces);
return 0;
}
@ -904,15 +905,16 @@ DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilAttack)
{
PARAM_ACTION_PROLOGUE;
DPSprite *pspr;
int pieces;
if (self->player == NULL)
if (self->player == nullptr)
{
return 0;
}
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
P_SetPsprite (self->player, ps_weapon,
self->player->psprites[ps_weapon].state + 4*pieces - 3);
pspr = self->player->GetPSprite(PSP_WEAPON);
pspr->SetState(pspr->GetState() + 4*pieces - 3);
return 0;
}

View file

@ -456,7 +456,7 @@ bool gl_SetupLightTexture()
{
if (GLRenderer->gllight == nullptr) return false;
FMaterial * pat = FMaterial::ValidateTexture(GLRenderer->gllight, false);
pat->Bind(CLAMP_XY_NOMIP, 0);
gl_RenderState.SetMaterial(pat, CLAMP_XY_NOMIP, 0, -1, false);
return true;
}
@ -484,7 +484,7 @@ bool GLWall::PutWallCompat(int passflag)
}
else if (sub)
{
if (sub->lighthead != nullptr) return false;
if (sub->lighthead == nullptr) return false;
}
bool foggy = !gl_isBlack(Colormap.FadeColor) || (level.flags&LEVEL_HASFADETABLE) || gl_lights_additive;
@ -673,7 +673,7 @@ void GLFlat::DrawLightsCompat(int pass)
while (node)
{
DrawSubsectorLights(sub, pass);
DrawSubsectorLights(node->sub, pass);
node = node->next;
}
}

View file

@ -348,7 +348,7 @@ static void PrepareTransparentDoors(sector_t * sector)
int side = sector->lines[i]->sidedef[0]->sector == sec;
if (sector->GetPlaneTexZ(sector_t::floor)!=sec->GetPlaneTexZ(sector_t::floor)+1.)
if (sector->GetPlaneTexZ(sector_t::floor)!=sec->GetPlaneTexZ(sector_t::floor)+1. || sec->floorplane.isSlope())
{
sector->transdoor=false;
return;

View file

@ -1019,10 +1019,10 @@ void gl_RenderModel(GLSprite * spr)
//
//===========================================================================
void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY)
void gl_RenderHUDModel(DPSprite *psp, float ofsX, float ofsY)
{
AActor * playermo=players[consoleplayer].camera;
FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->state->sprite, psp->state->GetFrame(), false);
FSpriteModelFrame *smf = gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false);
// [BB] No model found for this sprite, so we can't render anything.
if ( smf == nullptr )
@ -1062,7 +1062,7 @@ void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY)
gl_RenderState.mViewMatrix.rotate(-smf->rolloffset, 1, 0, 0);
gl_RenderState.ApplyMatrices();
gl_RenderFrameModels( smf, psp->state, psp->tics, playermo->player->ReadyWeapon->GetClass(), nullptr, 0 );
gl_RenderFrameModels( smf, psp->GetState(), psp->GetTics(), playermo->player->ReadyWeapon->GetClass(), nullptr, 0 );
glDepthFunc(GL_LESS);
if (!( playermo->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
@ -1077,10 +1077,15 @@ void gl_RenderHUDModel(pspdef_t *psp, float ofsX, float ofsY)
bool gl_IsHUDModelForPlayerAvailable (player_t * player)
{
if ( (player == nullptr) || (player->ReadyWeapon == nullptr) || (player->psprites[0].state == nullptr) )
if (player == nullptr || player->ReadyWeapon == nullptr)
return false;
FState* state = player->psprites[0].state;
DPSprite *psp = player->FindPSprite(PSP_WEAPON);
if (psp == nullptr || psp->GetState() == nullptr)
return false;
FState* state = psp->GetState();
FSpriteModelFrame *smf = gl_FindModelFrame(player->ReadyWeapon->GetClass(), state->sprite, state->GetFrame(), false);
return ( smf != nullptr );
}

View file

@ -371,7 +371,7 @@ FSpriteModelFrame * gl_FindModelFrame(const PClass * ti, int sprite, int frame,
void gl_RenderModel(GLSprite * spr);
// [BB] HUD weapon model rendering functions.
void gl_RenderHUDModel(pspdef_t *psp, float ofsx, float ofsy);
void gl_RenderHUDModel(DPSprite *psp, float ofsx, float ofsy);
bool gl_IsHUDModelForPlayerAvailable (player_t * player);

View file

@ -13,11 +13,11 @@ class FFlatVertexBuffer;
class FSkyVertexBuffer;
class OpenGLFrameBuffer;
struct FDrawInfo;
struct pspdef_t;
class FShaderManager;
class GLPortal;
class FLightBuffer;
class FSamplerManager;
class DPSprite;
inline float DEG2RAD(float deg)
{
@ -53,6 +53,12 @@ struct GL_IRECT
}
};
enum
{
DM_MAINVIEW,
DM_OFFSCREEN,
DM_PORTAL
};
class FGLRenderer
{
@ -106,10 +112,10 @@ public:
void RenderMultipassStuff();
void RenderScene(int recursion);
void RenderTranslucent();
void DrawScene(bool toscreen = false);
void DrawScene(int drawmode);
void DrawBlend(sector_t * viewsector);
void DrawPSprite (player_t * player,pspdef_t *psp,float sx, float sy, bool hudModelStep, int OverrideShader, bool alphatexture);
void DrawPSprite (player_t * player,DPSprite *psp,float sx, float sy, bool hudModelStep, int OverrideShader, bool alphatexture);
void DrawPlayerSprites(sector_t * viewsector, bool hudModelStep);
void DrawTargeterSprites();

View file

@ -306,9 +306,10 @@ bool GLPortal::Start(bool usestencil, bool doquery)
savedAngle = ViewAngle;
savedviewactor=GLRenderer->mViewActor;
savedviewarea=in_area;
savedshowviewer = r_showviewer;
savedviewpath[0] = ViewPath[0];
savedviewpath[1] = ViewPath[1];
savedvisibility = camera ? camera->renderflags & RF_INVISIBLE : ActorRenderFlags::FromInt(0);
PrevPortal = GLRenderer->mCurrentPortal;
PrevClipPortal = GLRenderer->mClipPortal;
@ -375,7 +376,7 @@ void GLPortal::End(bool usestencil)
ViewAngle = savedAngle;
GLRenderer->mViewActor=savedviewactor;
in_area=savedviewarea;
r_showviewer = savedshowviewer;
if (camera != nullptr) camera->renderflags = (camera->renderflags & ~RF_INVISIBLE) | savedvisibility;
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag & 1), !!(PlaneMirrorFlag & 1));
{
@ -432,7 +433,7 @@ void GLPortal::End(bool usestencil)
ViewAngle = savedAngle;
GLRenderer->mViewActor=savedviewactor;
in_area=savedviewarea;
r_showviewer = savedshowviewer;
if (camera != nullptr) camera->renderflags |= savedvisibility;
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
// This draws a valid z-buffer into the stencil's contents to ensure it
@ -665,7 +666,7 @@ void GLSkyboxPortal::DrawContents()
SaveMapSection();
currentmapsection[mapsection >> 3] |= 1 << (mapsection & 7);
GLRenderer->DrawScene();
GLRenderer->DrawScene(DM_PORTAL);
portal->mFlags &= ~PORTSF_INSKYBOX;
inskybox = false;
gl_RenderState.SetDepthClamp(oldclamp);
@ -755,7 +756,7 @@ void GLSectorStackPortal::DrawContents()
SaveMapSection();
SetupCoverage();
ClearClipper();
GLRenderer->DrawScene();
GLRenderer->DrawScene(DM_PORTAL);
RestoreMapSection();
if (origin->plane != -1) instack[origin->plane]--;
@ -791,14 +792,13 @@ void GLPlaneMirrorPortal::DrawContents()
ViewPos.Z = 2 * planez - ViewPos.Z;
GLRenderer->mViewActor = NULL;
PlaneMirrorMode = origin->fC() < 0 ? -1 : 1;
r_showviewer = true;
PlaneMirrorFlag++;
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
ClearClipper();
gl_RenderState.SetClipHeight(planez, PlaneMirrorMode < 0? -1.f : 1.f);
GLRenderer->DrawScene();
GLRenderer->DrawScene(DM_PORTAL);
gl_RenderState.SetClipHeight(0.f, 0.f);
PlaneMirrorFlag--;
PlaneMirrorMode=old_pm;
@ -955,7 +955,6 @@ void GLMirrorPortal::DrawContents()
ViewAngle = linedef->Delta().Angle() * 2. - StartAngle;
GLRenderer->mViewActor = NULL;
r_showviewer = true;
MirrorFlag++;
GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1));
@ -971,7 +970,7 @@ void GLMirrorPortal::DrawContents()
gl_RenderState.SetClipLine(linedef);
gl_RenderState.EnableClipLine(true);
GLRenderer->DrawScene();
GLRenderer->DrawScene(DM_PORTAL);
gl_RenderState.EnableClipLine(false);
MirrorFlag--;
@ -1009,7 +1008,7 @@ void GLLineToLinePortal::DrawContents()
P_TranslatePortalZ(origin, ViewPos.Z);
P_TranslatePortalXY(origin, ViewPath[0].X, ViewPath[0].Y);
P_TranslatePortalXY(origin, ViewPath[1].X, ViewPath[1].Y);
if (!r_showviewer)
if (!r_showviewer && camera != nullptr && P_PointOnLineSidePrecise(ViewPath[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(ViewPath[1], glport->lines[0]->mDestination))
{
double distp = (ViewPath[0] - ViewPath[1]).Length();
if (distp > EQUAL_EPSILON)
@ -1017,9 +1016,9 @@ void GLLineToLinePortal::DrawContents()
double dist1 = (ViewPos - ViewPath[0]).Length();
double dist2 = (ViewPos - ViewPath[1]).Length();
if (dist1 + dist2 > distp + 1)
if (dist1 + dist2 < distp + 1)
{
r_showviewer = true;
camera->renderflags |= RF_INVISIBLE;
}
}
}
@ -1044,7 +1043,7 @@ void GLLineToLinePortal::DrawContents()
ClearClipper();
gl_RenderState.SetClipLine(glport->lines[0]->mDestination);
gl_RenderState.EnableClipLine(true);
GLRenderer->DrawScene();
GLRenderer->DrawScene(DM_PORTAL);
gl_RenderState.EnableClipLine(false);
RestoreMapSection();
}

View file

@ -105,7 +105,7 @@ private:
DAngle savedAngle;
AActor * savedviewactor;
area_t savedviewarea;
bool savedshowviewer;
ActorRenderFlags savedvisibility;
DVector3 savedviewpath[2];
GLPortal *PrevPortal;
GLPortal *PrevClipPortal;

View file

@ -98,6 +98,7 @@ EXTERN_CVAR (Bool, r_deathcamera)
extern int viewpitch;
extern bool NoInterpolateView;
extern bool r_showviewer;
DWORD gl_fixedcolormap;
area_t in_area;
@ -501,16 +502,29 @@ void FGLRenderer::RenderTranslucent()
//-----------------------------------------------------------------------------
EXTERN_CVAR(Bool, gl_draw_sync)
void FGLRenderer::DrawScene(bool toscreen)
void FGLRenderer::DrawScene(int drawmode)
{
static int recursion=0;
CreateScene();
if (camera != nullptr)
{
ActorRenderFlags savedflags = camera->renderflags;
if (drawmode != DM_PORTAL && !r_showviewer)
{
camera->renderflags |= RF_INVISIBLE;
}
CreateScene();
camera->renderflags = savedflags;
}
else
{
CreateScene();
}
GLRenderer->mClipPortal = NULL; // this must be reset before any portal recursion takes place.
// Up to this point in the main draw call no rendering is performed so we can wait
// with swapping the render buffer until now.
if (!gl_draw_sync && toscreen)
if (!gl_draw_sync && drawmode == DM_MAINVIEW)
{
All.Unclock();
static_cast<OpenGLFrameBuffer*>(screen)->Swap();
@ -734,7 +748,7 @@ void FGLRenderer::ProcessScene(bool toscreen)
int mapsection = R_PointInSubsector(ViewPos)->mapsection;
memset(&currentmapsection[0], 0, currentmapsection.Size());
currentmapsection[mapsection>>3] |= 1 << (mapsection & 7);
DrawScene(toscreen);
DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN);
FDrawInfo::EndDrawInfo();
}

View file

@ -81,7 +81,6 @@ CUSTOM_CVAR(Int, gl_fuzztype, 0, CVAR_ARCHIVE)
if (self < 0 || self > 7) self = 0;
}
extern bool r_showviewer;
EXTERN_CVAR (Float, transsouls)
extern TArray<spritedef_t> sprites;
@ -239,7 +238,9 @@ void GLSprite::Draw(int pass)
secplane_t *topplane = i == 0 ? &topp : &(*lightlist)[i].plane;
secplane_t *lowplane = i == (*lightlist).Size() - 1 ? &bottomp : &(*lightlist)[i + 1].plane;
int thisll = (*lightlist)[i].caster != NULL ? gl_ClampLight(*(*lightlist)[i].p_lightlevel) : lightlevel;
int thislight = (*lightlist)[i].caster != NULL ? gl_ClampLight(*(*lightlist)[i].p_lightlevel) : lightlevel;
int thisll = actor == nullptr? thislight : (uint8_t)gl_CheckSpriteGlow(actor->Sector, thislight, actor->InterpolatedPosition(r_TicFracF));
FColormap thiscm;
thiscm.FadeColor = Colormap.FadeColor;
thiscm.CopyFrom3DLight(&(*lightlist)[i]);
@ -249,6 +250,10 @@ void GLSprite::Draw(int pass)
}
gl_SetColor(thisll, rel, thiscm, trans);
if (!foglayer)
{
gl_SetFog(thislight, rel, &thiscm, additivefog);
}
gl_RenderState.SetSplitPlanes(*topplane, *lowplane);
}
else if (clipping)
@ -264,7 +269,8 @@ void GLSprite::Draw(int pass)
&& (gl_billboard_mode == 1 || (actor && actor->renderflags & RF_FORCEXYBILLBOARD))));
const bool drawBillboardFacingCamera = gl_billboard_faces_camera;
// [Nash] has +ROLLSPRITE
const bool drawRollSpriteActor = (actor != NULL && actor->renderflags & RF_ROLLSPRITE);
gl_RenderState.Apply();
FVector3 v1;
@ -272,7 +278,16 @@ void GLSprite::Draw(int pass)
FVector3 v3;
FVector3 v4;
if (drawWithXYBillboard || drawBillboardFacingCamera)
// [fgsfds] check sprite type mask
DWORD spritetype = (DWORD)-1;
if (actor != NULL) spritetype = actor->renderflags & RF_SPRITETYPEMASK;
// [Nash] is a flat sprite
const bool isFlatSprite = (actor != NULL) && (spritetype == RF_WALLSPRITE || spritetype == RF_FLATSPRITE);
const bool dontFlip = (actor != nullptr) && (actor->renderflags & RF_DONTFLIP);
// [Nash] check for special sprite drawing modes
if (drawWithXYBillboard || drawBillboardFacingCamera || drawRollSpriteActor || isFlatSprite)
{
// Compute center of sprite
float xcenter = (x1 + x2)*0.5;
@ -284,7 +299,8 @@ void GLSprite::Draw(int pass)
mat.Translate(xcenter, zcenter, ycenter); // move to sprite center
// Order of rotations matters. Perform yaw rotation (Y, face camera) before pitch (X, tilt up/down).
if (drawBillboardFacingCamera) {
if (drawBillboardFacingCamera)
{
// [CMB] Rotate relative to camera XY position, not just camera direction,
// which is nicer in VR
float xrel = xcenter - ViewPos.X;
@ -296,13 +312,62 @@ void GLSprite::Draw(int pass)
mat.Rotate(0, 1, 0, relAngleDeg);
}
if (drawWithXYBillboard)
// [fgsfds] calculate yaw vectors
float yawvecX = 0, yawvecY = 0, rollDegrees = 0;
float angleRad = (270. - GLRenderer->mAngles.Yaw).Radians();
if (actor) rollDegrees = actor->Angles.Roll.Degrees;
if (isFlatSprite)
{
yawvecX = actor->Angles.Yaw.Cos();
yawvecY = actor->Angles.Yaw.Sin();
}
// [MC] This is the only thing that I changed in Nash's submission which
// was constantly applying roll to everything. That was wrong. Flat sprites
// with roll literally look like paper thing space ships trying to swerve.
// However, it does well with wall sprites.
// Also, renamed FLOORSPRITE to FLATSPRITE because that's technically incorrect.
// I plan on adding proper FLOORSPRITEs which can actually curve along sloped
// 3D floors later... if possible.
// Here we need some form of priority in order to work.
if (spritetype == RF_FLATSPRITE)
{
DVector3 diff = actor->Vec3To(GLRenderer->mViewActor);
DAngle angto = diff.Angle();
angto = deltaangle(actor->Angles.Yaw, angto);
float pitchDegrees = actor->Angles.Pitch.Degrees;
bool noFlipSprite = (!dontFlip || (fabs(angto) < 90.));
mat.Rotate(0, 1, 0, (noFlipSprite) ? 0 : 180);
mat.Rotate(-yawvecY, 0, yawvecX, (noFlipSprite) ? -pitchDegrees : pitchDegrees);
if (drawRollSpriteActor)
{
mat.Rotate(yawvecX, 0, yawvecY, (noFlipSprite) ? -rollDegrees : rollDegrees);
}
}
// [fgsfds] Rotate the sprite about the sight vector (roll)
else if (spritetype == RF_WALLSPRITE)
{
mat.Rotate(0, 1, 0, 0);
if (drawRollSpriteActor)
mat.Rotate(yawvecX, 0, yawvecY, rollDegrees);
}
else if (drawRollSpriteActor)
{
if (drawWithXYBillboard)
{
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -GLRenderer->mAngles.Pitch.Degrees);
}
mat.Rotate(cos(angleRad), 0, sin(angleRad), rollDegrees);
}
// apply the transform
else if (drawWithXYBillboard)
{
// Rotate the sprite about the vector starting at the center of the sprite
// triangle strip and with direction orthogonal to where the player is looking
// in the x/y plane.
float angleRad = (270. - GLRenderer->mAngles.Yaw).Radians();
mat.Rotate(-sin(angleRad), 0, cos(angleRad), -GLRenderer->mAngles.Pitch.Degrees);
}
mat.Translate(-xcenter, -zcenter, -ycenter); // retreat from sprite center
@ -546,8 +611,6 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
{
sector_t rs;
sector_t * rendersector;
// don't draw the thing that's used as camera (for viewshifts during quakes!)
if (thing == GLRenderer->mViewActor || (thing == players[consoleplayer].camera && !r_showviewer)) return;
// Don't waste time projecting sprites that are definitely not visible.
if (thing == NULL || thing->sprite == 0 || !thing->IsVisibleToPlayer())
@ -555,6 +618,12 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
return;
}
if (thing->renderflags & RF_INVISIBLE || !thing->RenderStyle.IsVisible(thing->Alpha))
{
if (!(thing->flags & MF_STEALTH) || !gl_fixedcolormap || !gl_enhanced_nightvision || thing == camera)
return;
}
int spritenum = thing->sprite;
DVector2 sprscale = thing->Scale;
if (thing->player != NULL)
@ -562,12 +631,6 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
P_CheckPlayerSprite(thing, spritenum, sprscale);
}
if (thing->renderflags & RF_INVISIBLE || !thing->RenderStyle.IsVisible(thing->Alpha))
{
if (!(thing->flags & MF_STEALTH) || !gl_fixedcolormap || !gl_enhanced_nightvision)
return;
}
// If this thing is in a map section that's not in view it can't possibly be visible
if (!thruportal && !(currentmapsection[thing->subsector->mapsection >> 3] & (1 << (thing->subsector->mapsection & 7)))) return;
@ -626,9 +689,11 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
topclip = rendersector->PortalBlocksMovement(sector_t::ceiling) ? LARGE_VALUE : rendersector->GetPortalPlaneZ(sector_t::ceiling);
bottomclip = rendersector->PortalBlocksMovement(sector_t::floor) ? -LARGE_VALUE : rendersector->GetPortalPlaneZ(sector_t::floor);
DWORD spritetype = (thing->renderflags & RF_SPRITETYPEMASK);
x = thingpos.X;
z = thingpos.Z - thing->Floorclip;
z = thingpos.Z;
y = thingpos.Y;
if (spritetype == RF_FLATSPRITE) z -= thing->Floorclip;
// [RH] Make floatbobbing a renderer-only effect.
if (thing->flags2 & MF2_FLOATBOB)
@ -636,7 +701,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
float fz = thing->GetBobOffset(r_TicFracF);
z += fz;
}
modelframe = gl_FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
if (!modelframe)
{
@ -681,7 +746,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
float viewvecX;
float viewvecY;
switch (thing->renderflags & RF_SPRITETYPEMASK)
switch (spritetype)
{
case RF_FACESPRITE:
viewvecX = GLRenderer->mViewVector.X;
@ -693,6 +758,7 @@ void GLSprite::Process(AActor* thing, sector_t * sector, int thruportal)
y2 = y + viewvecX*rightfac;
break;
case RF_FLATSPRITE:
case RF_WALLSPRITE:
viewvecX = thing->Angles.Yaw.Cos();
viewvecY = thing->Angles.Yaw.Sin();
@ -930,7 +996,7 @@ void GLSprite::ProcessParticle (particle_t *particle, sector_t *sector)//, int s
lightlevel = gl_ClampLight(sector->GetTexture(sector_t::ceiling) == skyflatnum ?
sector->GetCeilingLight() : sector->GetFloorLight());
foglevel = sector->lightlevel;
foglevel = (BYTE)clamp<short>(sector->lightlevel, 0, 255);
if (gl_fixedcolormap)
{

View file

@ -272,7 +272,7 @@ void GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float ma
if ((maplightbottomleft<ztop[0] && maplightbottomright>ztop[1]) ||
(maplightbottomleft>ztop[0] && maplightbottomright<ztop[1]))
{
float clen = MAX<float>(fabsf(glseg.x2 - glseg.x1), fabsf(glseg.y2 - glseg.y2));
float clen = MAX<float>(fabsf(glseg.x2 - glseg.x1), fabsf(glseg.y2 - glseg.y1));
float dch = ztop[1] - ztop[0];
float dfh = maplightbottomright - maplightbottomleft;
@ -312,7 +312,7 @@ void GLWall::SplitWallComplex(sector_t * frontsector, bool translucent, float ma
if ((maplightbottomleft<zbottom[0] && maplightbottomright>zbottom[1]) ||
(maplightbottomleft>zbottom[0] && maplightbottomright<zbottom[1]))
{
float clen = MAX<float>(fabsf(glseg.x2 - glseg.x1), fabsf(glseg.y2 - glseg.y2));
float clen = MAX<float>(fabsf(glseg.x2 - glseg.x1), fabsf(glseg.y2 - glseg.y1));
float dch = zbottom[1] - zbottom[0];
float dfh = maplightbottomright - maplightbottomleft;
@ -395,25 +395,25 @@ void GLWall::SplitWall(sector_t * frontsector, bool translucent)
continue;
}
if (gl.glslversion >= 1.3f)
// check for an intersection with the upper and lower planes of the wall segment
if ((maplightbottomleft<ztop[0] && maplightbottomright>ztop[1]) ||
(maplightbottomleft > ztop[0] && maplightbottomright < ztop[1]) ||
(maplightbottomleft<zbottom[0] && maplightbottomright>zbottom[1]) ||
(maplightbottomleft > zbottom[0] && maplightbottomright < zbottom[1]))
{
// check for an intersection with the upper and lower planes of the wall segment
if ((maplightbottomleft<ztop[0] && maplightbottomright>ztop[1]) ||
(maplightbottomleft > ztop[0] && maplightbottomright < ztop[1]) ||
(maplightbottomleft<zbottom[0] && maplightbottomright>zbottom[1]) ||
(maplightbottomleft > zbottom[0] && maplightbottomright < zbottom[1]))
if (gl.glslversion >= 1.3f)
{
// Use hardware clipping if this cannot be done cleanly.
this->lightlist = &lightlist;
PutWall(translucent);
goto out;
}
}
else
{
// crappy fallback if no clip planes available
SplitWallComplex(frontsector, translucent, maplightbottomleft, maplightbottomright);
return;
else
{
// crappy fallback if no clip planes available
SplitWallComplex(frontsector, translucent, maplightbottomleft, maplightbottomright);
}
goto out;
}
// 3D floor is completely within this light

View file

@ -71,7 +71,7 @@ EXTERN_CVAR (Bool, r_deathcamera)
//
//==========================================================================
void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp, float sx, float sy, bool hudModelStep, int OverrideShader, bool alphatexture)
void FGLRenderer::DrawPSprite (player_t * player,DPSprite *psp, float sx, float sy, bool hudModelStep, int OverrideShader, bool alphatexture)
{
float fU1,fV1;
float fU2,fV2;
@ -86,13 +86,13 @@ void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp, float sx, float
// [BB] In the HUD model step we just render the model and break out.
if ( hudModelStep )
{
gl_RenderHUDModel( psp, sx, sy);
gl_RenderHUDModel(psp, sx, sy);
return;
}
// decide which patch to use
bool mirror;
FTextureID lump = gl_GetSpriteFrame(psp->sprite, psp->frame, 0, 0, &mirror);
FTextureID lump = gl_GetSpriteFrame(psp->GetSprite(), psp->GetFrame(), 0, 0, &mirror);
if (!lump.isValid()) return;
FMaterial * tex = FMaterial::ValidateTexture(lump, true, false);
@ -174,6 +174,29 @@ void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp, float sx, float
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f);
}
//==========================================================================
//
//
//
//==========================================================================
static bool isBright(DPSprite *psp)
{
if (psp != nullptr && psp->GetState() != nullptr)
{
bool disablefullbright = false;
FTextureID lump = gl_GetSpriteFrame(psp->GetSprite(), psp->GetFrame(), 0, 0, NULL);
if (lump.isValid())
{
FMaterial * tex = FMaterial::ValidateTexture(lump, false, false);
if (tex)
disablefullbright = tex->tex->gl_info.bDisableFullbright;
}
return psp->GetState()->GetFullbright() && !disablefullbright;
}
return false;
}
//==========================================================================
//
// R_DrawPlayerSprites
@ -184,11 +207,9 @@ EXTERN_CVAR(Bool, gl_brightfog)
void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
{
bool statebright[2] = {false, false};
bool brightflash = false;
unsigned int i;
pspdef_t *psp;
int lightlevel=0;
float ofsx, ofsy;
FColormap cm;
sector_t * fakesec, fs;
AActor * playermo=players[consoleplayer].camera;
@ -202,33 +223,35 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
(r_deathcamera && camera->health <= 0))
return;
P_BobWeapon (player, &player->psprites[ps_weapon], &ofsx, &ofsy, r_TicFracF);
float bobx, boby, wx, wy;
DPSprite *weapon;
// check for fullbright
if (player->fixedcolormap==NOFIXEDCOLORMAP)
P_BobWeapon(camera->player, &bobx, &boby, r_TicFracF);
// Interpolate the main weapon layer once so as to be able to add it to other layers.
if ((weapon = camera->player->FindPSprite(PSP_WEAPON)) != nullptr)
{
for (i = 0, psp = player->psprites; i <= ps_flash; i++, psp++)
if (weapon->firstTic)
{
if (psp->state != NULL)
{
bool disablefullbright = false;
FTextureID lump = gl_GetSpriteFrame(psp->sprite, psp->frame, 0, 0, NULL);
if (lump.isValid())
{
FMaterial * tex=FMaterial::ValidateTexture(lump, false, false);
if (tex)
disablefullbright = tex->tex->gl_info.bDisableFullbright;
}
statebright[i] = !!psp->state->GetFullbright() && !disablefullbright;
}
wx = weapon->x;
wy = weapon->y;
}
else
{
wx = weapon->oldx + (weapon->x - weapon->oldx) * r_TicFracF;
wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF;
}
}
else
{
wx = 0;
wy = 0;
}
if (gl_fixedcolormap)
{
lightlevel=255;
cm.Clear();
statebright[0] = statebright[1] = true;
fakesec = viewsector;
}
else
@ -237,20 +260,6 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
// calculate light level for weapon sprites
lightlevel = gl_ClampLight(fakesec->lightlevel);
if (glset.lightmode == 8)
{
lightlevel = gl_CalcLightLevel(lightlevel, getExtraLight(), true);
// Korshun: the way based on max possible light level for sector like in software renderer.
float min_L = 36.0/31.0 - ((lightlevel/255.0) * (63.0/31.0)); // Lightlevel in range 0-63
if (min_L < 0)
min_L = 0;
else if (min_L > 1.0)
min_L = 1.0;
lightlevel = (1.0 - min_L) * 255;
}
lightlevel = gl_CheckSpriteGlow(viewsector, lightlevel, playermo->Pos());
// calculate colormap for weapon sprites
if (viewsector->e->XFloor.ffloors.Size() && !glset.nocoloredspritelighting)
@ -282,8 +291,27 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
cm=fakesec->ColorMap;
if (glset.nocoloredspritelighting) cm.ClearColor();
}
}
lightlevel = gl_CalcLightLevel(lightlevel, getExtraLight(), true);
if (glset.lightmode == 8)
{
// Korshun: the way based on max possible light level for sector like in software renderer.
float min_L = 36.0 / 31.0 - ((lightlevel / 255.0) * (63.0 / 31.0)); // Lightlevel in range 0-63
if (min_L < 0)
min_L = 0;
else if (min_L > 1.0)
min_L = 1.0;
lightlevel = (1.0 - min_L) * 255;
}
else
{
lightlevel = (2 * lightlevel + 255) / 3;
}
lightlevel = gl_CheckSpriteGlow(viewsector, lightlevel, playermo->Pos());
}
// Korshun: fullbright fog in opengl, render weapon sprites fullbright (but don't cancel out the light color!)
if (glset.brightfog && ((level.flags&LEVEL_HASFADETABLE) || cm.FadeColor != 0))
@ -332,7 +360,6 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
vis.RenderStyle.BlendOp = STYLEOP_Shadow;
}
}
statebright[0] = statebright[1] = false;
}
gl_SetRenderStyle(vis.RenderStyle, false, false);
@ -356,24 +383,19 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
gl_RenderState.BlendEquation(GL_FUNC_ADD);
if (statebright[0] || statebright[1])
{
// brighten the weapon to reduce the difference between
// normal sprite and fullbright flash.
if (glset.lightmode != 8) lightlevel = (2*lightlevel+255)/3;
}
// hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change
// light mode here to draw the weapon sprite.
int oldlightmode = glset.lightmode;
if (glset.lightmode == 8) glset.lightmode = 2;
for (i=0, psp=player->psprites; i<=ps_flash; i++,psp++)
for(DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext())
{
if (psp->state)
if (psp->GetState() != nullptr)
{
FColormap cmc = cm;
if (statebright[i])
int ll = lightlevel;
if (isBright(psp))
{
if (fakesec == viewsector || in_area != area_below)
{
@ -388,6 +410,7 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
cmc.LightColor.g = (3*cmc.LightColor.g + 0xff)/4;
cmc.LightColor.b = (3*cmc.LightColor.b + 0xff)/4;
}
ll = 255;
}
// set the lighting parameters
if (vis.RenderStyle.BlendOp == STYLEOP_Shadow)
@ -400,9 +423,33 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
{
gl_SetDynSpriteLight(playermo, NULL);
}
gl_SetColor(statebright[i] ? 255 : lightlevel, 0, cmc, trans, true);
gl_SetColor(ll, 0, cmc, trans, true);
}
DrawPSprite(player, psp, psp->sx + ofsx, psp->sy + ofsy, hudModelStep, OverrideShader, !!(vis.RenderStyle.Flags & STYLEF_RedIsAlpha));
if (psp->firstTic)
{ // Can't interpolate the first tic.
psp->firstTic = false;
psp->oldx = psp->x;
psp->oldy = psp->y;
}
float sx = psp->oldx + (psp->x - psp->oldx) * r_TicFracF;
float sy = psp->oldy + (psp->y - psp->oldy) * r_TicFracF;
if (psp->Flags & PSPF_ADDBOB)
{
sx += bobx;
sy += boby;
}
if (psp->Flags & PSPF_ADDWEAPON && psp->GetID() != PSP_WEAPON)
{
sx += wx;
sy += wy;
}
DrawPSprite(player, psp, sx, sy, hudModelStep, OverrideShader, !!(vis.RenderStyle.Flags & STYLEF_RedIsAlpha));
}
}
gl_RenderState.SetObjectColor(0xffffffff);
@ -419,8 +466,6 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
void FGLRenderer::DrawTargeterSprites()
{
int i;
pspdef_t *psp;
AActor * playermo=players[consoleplayer].camera;
player_t * player=playermo->player;
@ -435,6 +480,8 @@ void FGLRenderer::DrawTargeterSprites()
gl_RenderState.SetTextureMode(TM_MODULATE);
// The Targeter's sprites are always drawn normally.
for (i=ps_targetcenter, psp = &player->psprites[ps_targetcenter]; i<NUMPSPRITES; i++,psp++)
if (psp->state) DrawPSprite (player,psp,psp->sx, psp->sy, false, 0, false);
for (DPSprite *psp = player->FindPSprite(PSP_TARGETCENTER); psp != nullptr; psp = psp->GetNext())
{
if (psp->GetState() != nullptr) DrawPSprite(player, psp, psp->x, psp->y, false, 0, false);
}
}

View file

@ -69,14 +69,14 @@ void FState::SetAction(const char *name)
ActionFunc = FindGlobalActionFunction(name)->Variants[0].Implementation;
}
bool FState::CallAction(AActor *self, AActor *stateowner, FState **stateret)
bool FState::CallAction(AActor *self, AActor *stateowner, FStateParamInfo *info, FState **stateret)
{
if (ActionFunc != NULL)
{
ActionCycles.Clock();
static VMFrameStack stack;
VMValue params[3] = { self, stateowner, VMValue(this, ATAG_STATE) };
VMValue params[3] = { self, stateowner, VMValue(info, ATAG_STATEINFO) };
// If the function returns a state, store it at *stateret.
// If it doesn't return a state but stateret is non-NULL, we need
// to set *stateret to NULL.

View file

@ -55,6 +55,21 @@ struct FActorInfo;
class FArchive;
class FIntCVar;
enum EStateType
{
STATE_Actor,
STATE_Psprite,
STATE_StateChain,
};
struct FStateParamInfo
{
FState *mCallingState;
EStateType mStateType;
int mPSPIndex;
};
// Sprites that are fixed in position because they can have special meanings.
enum
{
@ -129,7 +144,7 @@ struct FState
void SetAction(VMFunction *func) { ActionFunc = func; }
void ClearAction() { ActionFunc = NULL; }
void SetAction(const char *name);
bool CallAction(AActor *self, AActor *stateowner, FState **stateret);
bool CallAction(AActor *self, AActor *stateowner, FStateParamInfo *stateinfo, FState **stateret);
static PClassActor *StaticFindStateOwner (const FState *state);
static PClassActor *StaticFindStateOwner (const FState *state, PClassActor *info);
static FRandom pr_statetics;
@ -338,7 +353,7 @@ void AddStateLight(FState *state, const char *lname);
PARAM_PROLOGUE; \
PARAM_OBJECT (self, type); \
PARAM_OBJECT_OPT (stateowner, AActor) { stateowner = self; } \
PARAM_STATE_OPT (callingstate) { callingstate = NULL; } \
PARAM_STATEINFO_OPT (stateinfo) { stateinfo = nullptr; } \
#define PARAM_ACTION_PROLOGUE PARAM_ACTION_PROLOGUE_TYPE(AActor)

View file

@ -315,7 +315,7 @@ void cht_DoCheat (player_t *player, int cheat)
// [GRB]
case CHT_RESSURECT:
if (player->playerstate != PST_LIVE && player->mo != NULL)
if (player->playerstate != PST_LIVE && player->mo != nullptr)
{
if (player->mo->IsKindOf(RUNTIME_CLASS(APlayerChunk)))
{
@ -344,9 +344,9 @@ void cht_DoCheat (player_t *player, int cheat)
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
}
player->mo->DamageType = NAME_None;
if (player->ReadyWeapon != NULL)
if (player->ReadyWeapon != nullptr)
{
P_SetPsprite(player, ps_weapon, player->ReadyWeapon->GetUpState());
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetUpState());
}
if (player->morphTics > 0)
@ -933,10 +933,8 @@ void cht_Take (player_t *player, const char *name, int amount)
if (weapon)
weapon->Destroy ();
player->ReadyWeapon = NULL;
player->ReadyWeapon = nullptr;
player->PendingWeapon = WP_NOCHANGE;
player->psprites[ps_weapon].state = NULL;
player->psprites[ps_flash].state = NULL;
}
}

View file

@ -302,7 +302,15 @@ static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc)
int y = sc.Number;
sc.MustGetStringName(",");
sc.MustGetString();
FListMenuItem *it = new FListMenuItemStaticText(x, y, sc.String, desc->mFont, desc->mFontColor, centered);
FString label = sc.String;
EColorRange cr = desc->mFontColor;
if (sc.CheckString(","))
{
sc.MustGetString();
cr = V_FindFontColor(sc.String);
if (cr == CR_UNTRANSLATED && !sc.Compare("untranslated")) cr = desc->mFontColor;
}
FListMenuItem *it = new FListMenuItemStaticText(x, y, label, desc->mFont, cr, centered);
desc->mItems.Push(it);
}
else if (sc.Compare("PatchItem"))
@ -644,6 +652,21 @@ static void ParseOptionSettings(FScanner &sc)
//
//=============================================================================
static EColorRange ParseOptionColor(FScanner &sc, FOptionMenuDescriptor *desc)
{
EColorRange cr = OptionSettings.mFontColor;
if (sc.CheckString(","))
{
sc.MustGetString();
EColorRange cr = V_FindFontColor(sc.String);
if (cr == CR_UNTRANSLATED && !sc.Compare("untranslated") && isdigit(sc.String[0]))
{
if (strtol(sc.String, NULL, 0)) cr = OptionSettings.mFontColorHeader;
}
}
return cr;
}
static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc)
{
sc.MustGetStringName("{");
@ -780,12 +803,7 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc)
{
sc.MustGetString();
FString label = sc.String;
bool cr = false;
if (sc.CheckString(","))
{
sc.MustGetNumber();
cr = !!sc.Number;
}
EColorRange cr = ParseOptionColor(sc, desc);
FOptionMenuItem *it = new FOptionMenuItemStaticText(label, cr);
desc->mItems.Push(it);
}
@ -799,12 +817,7 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc)
sc.MustGetStringName(",");
sc.MustGetString();
FName action = sc.String;
bool cr = false;
if (sc.CheckString(","))
{
sc.MustGetNumber();
cr = !!sc.Number;
}
EColorRange cr = ParseOptionColor(sc, desc);
FOptionMenuItem *it = new FOptionMenuItemStaticTextSwitchable(label, label2, action, cr);
desc->mItems.Push(it);
}

View file

@ -483,7 +483,13 @@ public:
FOptionMenuItemStaticText(const char *label, bool header)
: FOptionMenuItem(label, NAME_None, true)
{
mColor = header? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
mColor = header ? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
}
FOptionMenuItemStaticText(const char *label, EColorRange cr)
: FOptionMenuItem(label, NAME_None, true)
{
mColor = cr;
}
int Draw(FOptionMenuDescriptor *desc, int y, int indent, bool selected)
@ -512,10 +518,10 @@ class FOptionMenuItemStaticTextSwitchable : public FOptionMenuItem
int mCurrent;
public:
FOptionMenuItemStaticTextSwitchable(const char *label, const char *label2, FName action, bool header)
FOptionMenuItemStaticTextSwitchable(const char *label, const char *label2, FName action, EColorRange cr)
: FOptionMenuItem(label, action, true)
{
mColor = header? OptionSettings.mFontColorHeader : OptionSettings.mFontColor;
mColor = cr;
mAltText = label2;
mCurrent = 0;
}

View file

@ -3968,6 +3968,7 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
case APROP_Friction:
actor->Friction = ACSToDouble(value);
break;
case APROP_MaxStepHeight:
actor->MaxStepHeight = ACSToDouble(value);
@ -4189,31 +4190,6 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b
return tex == TexMan[secpic];
}
enum
{
// These are the original inputs sent by the player.
INPUT_OLDBUTTONS,
INPUT_BUTTONS,
INPUT_PITCH,
INPUT_YAW,
INPUT_ROLL,
INPUT_FORWARDMOVE,
INPUT_SIDEMOVE,
INPUT_UPMOVE,
// These are the inputs, as modified by P_PlayerThink().
// Most of the time, these will match the original inputs, but
// they can be different if a player is frozen or using a
// chainsaw.
MODINPUT_OLDBUTTONS,
MODINPUT_BUTTONS,
MODINPUT_PITCH,
MODINPUT_YAW,
MODINPUT_ROLL,
MODINPUT_FORWARDMOVE,
MODINPUT_SIDEMOVE,
MODINPUT_UPMOVE
};
int DLevelScript::GetPlayerInput(int playernum, int inputnum)
{
@ -4240,28 +4216,7 @@ int DLevelScript::GetPlayerInput(int playernum, int inputnum)
return 0;
}
switch (inputnum)
{
case INPUT_OLDBUTTONS: return p->original_oldbuttons; break;
case INPUT_BUTTONS: return p->original_cmd.buttons; break;
case INPUT_PITCH: return p->original_cmd.pitch; break;
case INPUT_YAW: return p->original_cmd.yaw; break;
case INPUT_ROLL: return p->original_cmd.roll; break;
case INPUT_FORWARDMOVE: return p->original_cmd.forwardmove; break;
case INPUT_SIDEMOVE: return p->original_cmd.sidemove; break;
case INPUT_UPMOVE: return p->original_cmd.upmove; break;
case MODINPUT_OLDBUTTONS: return p->oldbuttons; break;
case MODINPUT_BUTTONS: return p->cmd.ucmd.buttons; break;
case MODINPUT_PITCH: return p->cmd.ucmd.pitch; break;
case MODINPUT_YAW: return p->cmd.ucmd.yaw; break;
case MODINPUT_ROLL: return p->cmd.ucmd.roll; break;
case MODINPUT_FORWARDMOVE: return p->cmd.ucmd.forwardmove; break;
case MODINPUT_SIDEMOVE: return p->cmd.ucmd.sidemove; break;
case MODINPUT_UPMOVE: return p->cmd.ucmd.upmove; break;
default: return 0; break;
}
return P_Thing_CheckInputNum(p, inputnum);
}
enum
@ -4656,7 +4611,11 @@ static int DoGetCVar(FBaseCVar *cvar, bool is_string)
{
UCVarValue val;
if (is_string)
if (cvar == nullptr)
{
return 0;
}
else if (is_string)
{
val = cvar->GetGenericRep(CVAR_String);
return GlobalACSStrings.AddString(val.String);
@ -4673,44 +4632,6 @@ static int DoGetCVar(FBaseCVar *cvar, bool is_string)
}
}
static int GetUserCVar(int playernum, const char *cvarname, bool is_string)
{
if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum])
{
return 0;
}
FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true));
FBaseCVar *cvar;
if (cvar_p == NULL || (cvar = *cvar_p) == NULL || (cvar->GetFlags() & CVAR_IGNORE))
{
return 0;
}
return DoGetCVar(cvar, is_string);
}
static int GetCVar(AActor *activator, const char *cvarname, bool is_string)
{
FBaseCVar *cvar = FindCVar(cvarname, NULL);
// Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0.
if (cvar == NULL || (cvar->GetFlags() & CVAR_IGNORE))
{
return 0;
}
else
{
// For userinfo cvars, redirect to GetUserCVar
if (cvar->GetFlags() & CVAR_USERINFO)
{
if (activator == NULL || activator->player == NULL)
{
return 0;
}
return GetUserCVar(int(activator->player - players), cvarname, is_string);
}
return DoGetCVar(cvar, is_string);
}
}
static int SetUserCVar(int playernum, const char *cvarname, int value, bool is_string)
{
if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum])
@ -5395,7 +5316,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
case ACSF_GetCVarString:
if (argCount == 1)
{
return GetCVar(activator, FBehavior::StaticLookupString(args[0]), true);
return DoGetCVar(GetCVar(activator, FBehavior::StaticLookupString(args[0])), true);
}
break;
@ -5416,14 +5337,14 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args)
case ACSF_GetUserCVar:
if (argCount == 2)
{
return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), false);
return DoGetCVar(GetUserCVar(args[0], FBehavior::StaticLookupString(args[1])), false);
}
break;
case ACSF_GetUserCVarString:
if (argCount == 2)
{
return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), true);
return DoGetCVar(GetUserCVar(args[0], FBehavior::StaticLookupString(args[1])), true);
}
break;
@ -6047,7 +5968,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
PalEntry color = args[0];
bool fullbright = argCount > 1 ? !!args[1] : false;
int lifetime = argCount > 2 ? args[2] : 35;
int size = argCount > 3 ? args[3] : 1;
double size = argCount > 3 ? args[3] : 1.;
int x = argCount > 4 ? args[4] : 0;
int y = argCount > 5 ? args[5] : 0;
int z = argCount > 6 ? args[6] : 0;
@ -6059,17 +5980,18 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
int accelz = argCount > 12 ? args[12] : 0;
int startalpha = argCount > 13 ? args[13] : 0xFF; // Byte trans
int fadestep = argCount > 14 ? args[14] : -1;
double endsize = argCount > 15 ? args[15] : -1.;
startalpha = clamp<int>(startalpha, 0, 255); // Clamp to byte
lifetime = clamp<int>(lifetime, 0, 255); // Clamp to byte
fadestep = clamp<int>(fadestep, -1, 255); // Clamp to byte inc. -1 (indicating automatic)
size = clamp<int>(size, 0, 65535); // Clamp to word
size = fabs(size);
if (lifetime != 0)
P_SpawnParticle(DVector3(ACSToDouble(x), ACSToDouble(y), ACSToDouble(z)),
DVector3(ACSToDouble(xvel), ACSToDouble(yvel), ACSToDouble(zvel)),
DVector3(ACSToDouble(accelx), ACSToDouble(accely), ACSToDouble(accelz)),
color, fullbright, startalpha/255., lifetime, size, fadestep/255.);
color, startalpha/255., lifetime, size, endsize, fadestep/255., fullbright);
}
break;
@ -8126,6 +8048,17 @@ scriptwait:
break;
// [BC] Start ST PCD's
case PCD_ISNETWORKGAME:
PushToStack(netgame);
break;
case PCD_PLAYERTEAM:
if ( activator && activator->player )
PushToStack( activator->player->userinfo.GetTeam() );
else
PushToStack( 0 );
break;
case PCD_PLAYERHEALTH:
if (activator)
PushToStack (activator->health);
@ -8162,7 +8095,7 @@ scriptwait:
break;
case PCD_SINGLEPLAYER:
PushToStack (!netgame);
PushToStack (!multiplayer);
break;
// [BC] End ST PCD's
@ -9130,7 +9063,7 @@ scriptwait:
break;
case PCD_GETCVAR:
STACK(1) = GetCVar(activator, FBehavior::StaticLookupString(STACK(1)), false);
STACK(1) = DoGetCVar(GetCVar(activator, FBehavior::StaticLookupString(STACK(1))), false);
break;
case PCD_SETHUDSIZE:
@ -9606,8 +9539,12 @@ scriptwait:
break;
case PCD_CONSOLECOMMAND:
case PCD_CONSOLECOMMANDDIRECT:
Printf (TEXTCOLOR_RED GAMENAME " doesn't support execution of console commands from scripts\n");
sp -= 3;
if (pcd == PCD_CONSOLECOMMAND)
sp -= 3;
else
pc += 3;
break;
}
}

View file

@ -504,7 +504,7 @@ public:
PCD_PLAYERGOLDSKULL,
PCD_PLAYERBLACKCARD,
PCD_PLAYERSILVERCARD,
PCD_PLAYERONTEAM,
PCD_ISNETWORKGAME,
PCD_PLAYERTEAM,
/*120*/ PCD_PLAYERHEALTH,
PCD_PLAYERARMORPOINTS,
@ -519,7 +519,7 @@ public:
/*130*/ PCD_LSPEC6DIRECT, // be given names like PCD_DUMMY.
PCD_PRINTNAME,
PCD_MUSICCHANGE,
PCD_TEAM2FRAGPOINTS,
PCD_CONSOLECOMMANDDIRECT,
PCD_CONSOLECOMMAND,
PCD_SINGLEPLAYER, // [RH] End of Skull Tag p-codes
PCD_FIXEDMUL,

View file

@ -527,7 +527,7 @@ DAnimatedDoor::DAnimatedDoor ()
}
DAnimatedDoor::DAnimatedDoor (sector_t *sec)
: DMovingCeiling (sec)
: DMovingCeiling (sec, false)
{
}
@ -689,14 +689,11 @@ void DAnimatedDoor::Tick ()
//============================================================================
DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim)
: DMovingCeiling (sec)
: DMovingCeiling (sec, false)
{
double topdist;
FTextureID picnum;
// The DMovingCeiling constructor automatically sets up an interpolation for us.
// Stop it, since the ceiling is moving instantly here.
StopInterpolation();
m_DoorAnim = anim;
m_Line1 = line;

View file

@ -252,7 +252,6 @@ void P_InitEffects ()
blood2 = ParticleColor(RPART(kind)/3, GPART(kind)/3, BPART(kind)/3);
}
void P_ThinkParticles ()
{
int i;
@ -262,13 +261,19 @@ void P_ThinkParticles ()
prev = NULL;
while (i != NO_PARTICLE)
{
BYTE oldtrans;
particle = Particles + i;
i = particle->tnext;
if (!particle->notimefreeze && ((bglobal.freeze) || (level.flags2 & LEVEL2_FROZEN)))
{
prev = particle;
continue;
}
BYTE oldtrans;
oldtrans = particle->trans;
particle->trans -= particle->fade;
if (oldtrans < particle->trans || --particle->ttl == 0)
particle->size += particle->sizestep;
if (oldtrans < particle->trans || --particle->ttl <= 0 || (particle->size <= 0))
{ // The particle has expired, so free it
memset (particle, 0, sizeof(particle_t));
if (prev)
@ -309,8 +314,14 @@ void P_ThinkParticles ()
}
}
enum PSFlag
{
PS_FULLBRIGHT = 1,
PS_NOTIMEFREEZE = 1 << 5,
};
void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, bool fullbright, double startalpha, int lifetime, WORD size, double fadestep)
void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size,
double fadestep, double sizestep, int flags)
{
particle_t *particle = NewParticle();
@ -324,8 +335,10 @@ void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &a
if (fadestep < 0) particle->fade = FADEFROMTTL(lifetime);
else particle->fade = int(fadestep * 255);
particle->ttl = lifetime;
particle->bright = fullbright;
particle->size = (WORD)size;
particle->bright = !!(flags & PS_FULLBRIGHT);
particle->size = size;
particle->sizestep = sizestep;
particle->notimefreeze = !!(flags & PS_NOTIMEFREEZE);
}
}
@ -462,8 +475,8 @@ void P_RunEffect (AActor *actor, int effects)
speed = (M_Random () - 128) * (1./200);
particle->Vel.X += speed * an.Cos();
particle->Vel.Y += speed * an.Sin();
particle->Vel.Z -= 1. / 80;
particle->Acc.Z -= 1. / 40;
particle->Vel.Z += 1. / 80;
particle->Acc.Z += 1. / 40;
if (M_Random () & 7)
particle->color = grey2;
else

View file

@ -59,13 +59,15 @@ struct particle_t
DVector3 Acc;
BYTE ttl;
BYTE trans;
WORD size;
double size;
double sizestep;
BYTE bright;
BYTE fade;
int color;
WORD tnext;
WORD snext;
subsector_t * subsector;
bool notimefreeze;
};
extern particle_t *Particles;
@ -83,7 +85,7 @@ particle_t *JitterParticle (int ttl);
particle_t *JitterParticle (int ttl, double drift);
void P_ThinkParticles (void);
void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, bool fullbright, double startalpha, int lifetime, WORD size, double fadestep);
void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size, double fadestep, double sizestep, int flags = 0);
void P_InitEffects (void);
void P_RunEffects (void);

View file

@ -77,7 +77,6 @@ extern int bmapnegy;
// P_PSPR
//
void P_SetupPsprites (player_t* curplayer, bool startweaponup);
void P_MovePsprites (player_t* curplayer);
void P_DropWeapon (player_t* player);
@ -161,9 +160,35 @@ bool P_Thing_Raise(AActor *thing, AActor *raiser);
bool P_Thing_CanRaise(AActor *thing);
PClassActor *P_GetSpawnableType(int spawnnum);
void InitSpawnablesFromMapinfo();
int P_Thing_CheckInputNum(player_t *p, int inputnum);
int P_Thing_Warp(AActor *caller, AActor *reference, double xofs, double yofs, double zofs, DAngle angle, int flags, double heightoffset, double radiusoffset, DAngle pitch);
bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr);
enum
{
// These are the original inputs sent by the player.
INPUT_OLDBUTTONS,
INPUT_BUTTONS,
INPUT_PITCH,
INPUT_YAW,
INPUT_ROLL,
INPUT_FORWARDMOVE,
INPUT_SIDEMOVE,
INPUT_UPMOVE,
// These are the inputs, as modified by P_PlayerThink().
// Most of the time, these will match the original inputs, but
// they can be different if a player is frozen or using a
// chainsaw.
MODINPUT_OLDBUTTONS,
MODINPUT_BUTTONS,
MODINPUT_PITCH,
MODINPUT_YAW,
MODINPUT_ROLL,
MODINPUT_FORWARDMOVE,
MODINPUT_SIDEMOVE,
MODINPUT_UPMOVE
};
enum CPXF
{
CPXF_ANCESTOR = 1 << 0,
@ -335,6 +360,7 @@ struct FRailParams
double drift = 1.0;
PClassActor *spawnclass = nullptr;
int SpiralOffset = 270;
int limit = 0;
}; // [RH] Shoot a railgun
void P_RailAttack(FRailParams *params);

View file

@ -4611,6 +4611,8 @@ struct RailData
bool ThruSpecies;
bool MThruSpecies;
bool ThruActors;
int limit;
int count;
};
static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
@ -4665,7 +4667,11 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
}
data->RailHits.Push(newhit);
return data->StopAtOne ? TRACE_Stop : TRACE_Continue;
if (data->limit)
{
data->count++;
}
return (data->StopAtOne || (data->limit && (data->count >= data->limit))) ? TRACE_Stop : TRACE_Continue;
}
//==========================================================================
@ -4707,7 +4713,8 @@ void P_RailAttack(FRailParams *p)
RailData rail_data;
rail_data.Caller = source;
rail_data.limit = p->limit;
rail_data.count = 0;
rail_data.StopAtOne = !!(p->flags & RAF_NOPIERCE);
start.X = xy.X;
start.Y = xy.Y;
@ -5460,14 +5467,25 @@ bool P_AdjustFloorCeil(AActor *thing, FChangePosition *cpos)
}
bool isgood = P_CheckPosition(thing, thing->Pos(), tm);
thing->floorz = tm.floorz;
thing->ceilingz = tm.ceilingz;
thing->dropoffz = tm.dropoffz; // killough 11/98: remember dropoffs
thing->floorpic = tm.floorpic;
thing->floorterrain = tm.floorterrain;
thing->floorsector = tm.floorsector;
thing->ceilingpic = tm.ceilingpic;
thing->ceilingsector = tm.ceilingsector;
if (!(thing->flags4 & MF4_ACTLIKEBRIDGE))
{
thing->floorz = tm.floorz;
thing->ceilingz = tm.ceilingz;
thing->dropoffz = tm.dropoffz; // killough 11/98: remember dropoffs
thing->floorpic = tm.floorpic;
thing->floorterrain = tm.floorterrain;
thing->floorsector = tm.floorsector;
thing->ceilingpic = tm.ceilingpic;
thing->ceilingsector = tm.ceilingsector;
}
else
{
// Bridges only keep the info at their spawn position
// This is necessary to prevent moving sectors from altering the bridge's z-position.
// The bridge should remain at its current z, even if the sector change would cause
// floorz or ceilingz to be changed in a way that would make P_ZMovement adjust the bridge.
P_FindFloorCeiling(thing, FFCF_ONLYSPAWNPOS);
}
// restore the PASSMOBJ flag but leave the other flags alone.
thing->flags2 = (thing->flags2 & ~MF2_PASSMOBJ) | flags2;

View file

@ -38,18 +38,17 @@ struct intercept_t
inline int P_PointOnLineSidePrecise(double x, double y, const line_t *line)
{
return (y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - x) * line->Delta().Y > -EQUAL_EPSILON;
return (y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - x) * line->Delta().Y > EQUAL_EPSILON;
}
inline int P_PointOnLineSidePrecise(const DVector2 &pt, const line_t *line)
{
return (pt.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pt.X) * line->Delta().Y > -EQUAL_EPSILON;
return (pt.Y - line->v1->fY()) * line->Delta().X + (line->v1->fX() - pt.X) * line->Delta().Y > EQUAL_EPSILON;
}
inline int P_PointOnLineSide (double x, double y, const line_t *line)
{
extern int P_VanillaPointOnLineSide(double x, double y, const line_t* line);
return i_compatflags2 & COMPATF2_POINTONLINE
? P_VanillaPointOnLineSide(x, y, line) : P_PointOnLineSidePrecise(x, y, line);
}
@ -73,12 +72,12 @@ inline int P_PointOnLineSide(const DVector2 & p, const line_t *line)
inline int P_PointOnDivlineSide(double x, double y, const divline_t *line)
{
return (y - line->y) * line->dx + (line->x - x) * line->dy > -EQUAL_EPSILON;
return (y - line->y) * line->dx + (line->x - x) * line->dy > EQUAL_EPSILON;
}
inline int P_PointOnDivlineSide(const DVector2 &pos, const divline_t *line)
{
return (pos.Y - line->y) * line->dx + (line->x - pos.X) * line->dy > -EQUAL_EPSILON;
return (pos.Y - line->y) * line->dx + (line->x - pos.X) * line->dy > EQUAL_EPSILON;
}
//==========================================================================

View file

@ -557,7 +557,8 @@ bool AActor::SetState (FState *newstate, bool nofunction)
if (!nofunction)
{
FState *returned_state;
if (newstate->CallAction(this, this, &returned_state))
FStateParamInfo stp = { newstate, STATE_Actor, PSP_WEAPON };
if (newstate->CallAction(this, this, &stp, &returned_state))
{
// Check whether the called action function resulted in destroying the actor
if (ObjectFlags & OF_EuthanizeMe)
@ -998,12 +999,10 @@ void AActor::ClearInventory()
invp = &inv->Inventory;
}
}
if (player != NULL)
if (player != nullptr)
{
player->ReadyWeapon = NULL;
player->ReadyWeapon = nullptr;
player->PendingWeapon = WP_NOCHANGE;
player->psprites[ps_weapon].state = NULL;
player->psprites[ps_flash].state = NULL;
}
}
@ -2790,10 +2789,10 @@ void P_NightmareRespawn (AActor *mobj)
mo->Prev.Z = z; // Do not interpolate Z position if we changed it since spawning.
// spawn a teleport fog at old spot because of removal of the body?
P_SpawnTeleportFog(mobj, mobj->PosPlusZ(TELEFOGHEIGHT), true, true);
P_SpawnTeleportFog(mobj, mobj->Pos(), true, true);
// spawn a teleport fog at the new spot
P_SpawnTeleportFog(mobj, DVector3(mobj->SpawnPoint, z + TELEFOGHEIGHT), false, true);
P_SpawnTeleportFog(mobj, DVector3(mobj->SpawnPoint, z), false, true);
// remove the old monster
mobj->Destroy ();
@ -3869,7 +3868,8 @@ bool AActor::CheckNoDelay()
// For immediately spawned objects with the NoDelay flag set for their
// Spawn state, explicitly call the current state's function.
FState *newstate;
if (state->CallAction(this, this, &newstate))
FStateParamInfo stp = { state, STATE_Actor, PSP_WEAPON };
if (state->CallAction(this, this, &stp, &newstate))
{
if (ObjectFlags & OF_EuthanizeMe)
{
@ -4686,7 +4686,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
if (multiplayer)
{
Spawn ("TeleportFog", mobj->Vec3Angle(20., mobj->Angles.Yaw, TELEFOGHEIGHT), ALLOW_REPLACE);
P_SpawnTeleportFog(mobj, mobj->Vec3Angle(20., mobj->Angles.Yaw, 0.), false, true);
}
// "Fix" for one of the starts on exec.wad MAP01: If you start inside the ceiling,

File diff suppressed because it is too large Load diff

View file

@ -35,59 +35,83 @@
// the right spot at 320x200.
#define WEAPONTOP (32+6./16)
class AInventory;
class FArchive;
//
// Overlay psprites are scaled shapes
// drawn directly on the view screen,
// coordinates are given for a 320*200 view screen.
//
typedef enum
enum PSPLayers // These are all called by the owner's ReadyWeapon.
{
ps_weapon,
ps_flash,
ps_targetcenter,
ps_targetleft,
ps_targetright,
NUMPSPRITES
} psprnum_t;
/*
inline FArchive &operator<< (FArchive &arc, psprnum_t &i)
{
BYTE val = (BYTE)i;
arc << val;
i = (psprnum_t)val;
return arc;
}
*/
struct pspdef_t
{
FState* state; // a NULL state means not active
int tics;
double sx;
double sy;
int sprite;
int frame;
bool processPending; // true: waiting for periodic processing on this tick
PSP_STRIFEHANDS = -1,
PSP_WEAPON = 1,
PSP_FLASH = 1000,
PSP_TARGETCENTER = INT_MAX - 2,
PSP_TARGETLEFT,
PSP_TARGETRIGHT,
};
class FArchive;
enum PSPFlags
{
PSPF_ADDWEAPON = 1 << 0,
PSPF_ADDBOB = 1 << 1,
PSPF_POWDOUBLE = 1 << 2,
PSPF_CVARFAST = 1 << 3,
};
FArchive &operator<< (FArchive &, pspdef_t &);
class DPSprite : public DObject
{
DECLARE_CLASS (DPSprite, DObject)
HAS_OBJECT_POINTERS
public:
DPSprite(player_t *owner, AActor *caller, int id);
class player_t;
class AActor;
struct FState;
static void NewTick();
void SetState(FState *newstate, bool pending = false);
int GetID() const { return ID; }
int GetSprite() const { return Sprite; }
int GetFrame() const { return Frame; }
int GetTics() const { return Tics; }
FState* GetState() const { return State; }
DPSprite* GetNext() { return Next; }
AActor* GetCaller() { return Caller; }
double x, y;
double oldx, oldy;
bool firstTic;
int Tics;
int Flags;
private:
DPSprite () {}
void Serialize(FArchive &arc);
void Tick();
void Destroy();
TObjPtr<AActor> Caller;
TObjPtr<DPSprite> Next;
player_t *Owner;
FState *State;
int Sprite;
int Frame;
int ID;
bool processPending; // true: waiting for periodic processing on this tick
friend class player_t;
friend void CopyPlayer(player_t *dst, player_t *src, const char *name);
};
void P_NewPspriteTick();
void P_SetPsprite (player_t *player, int position, FState *state, bool nofunction=false);
void P_CalcSwing (player_t *player);
void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending = false);
void P_BringUpWeapon (player_t *player);
void P_FireWeapon (player_t *player);
void P_DropWeapon (player_t *player);
void P_BobWeapon (player_t *player, pspdef_t *psp, float *x, float *y, double ticfrac);
void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac);
DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0);
void P_GunShot (AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch);

View file

@ -56,7 +56,7 @@
#include "p_acs.h"
#include "p_terrain.h"
static void CopyPlayer (player_t *dst, player_t *src, const char *name);
void CopyPlayer (player_t *dst, player_t *src, const char *name);
static void ReadOnePlayer (FArchive &arc, bool skipload);
static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNow, bool skipload);
static void SpawnExtraPlayers ();
@ -255,7 +255,7 @@ static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNo
delete[] nametemp;
}
static void CopyPlayer (player_t *dst, player_t *src, const char *name)
void CopyPlayer (player_t *dst, player_t *src, const char *name)
{
// The userinfo needs to be saved for real players, but it
// needs to come from the save for bots.
@ -274,7 +274,7 @@ static void CopyPlayer (player_t *dst, player_t *src, const char *name)
dst->cheats |= chasecam;
if (dst->Bot != NULL)
if (dst->Bot != nullptr)
{
botinfo_t *thebot = bglobal.botinfo;
while (thebot && stricmp (name, thebot->name))
@ -296,10 +296,23 @@ static void CopyPlayer (player_t *dst, player_t *src, const char *name)
dst->userinfo.SkinNumChanged(R_FindSkin(skins[dst->userinfo.GetSkin()].name, dst->CurrentPlayerClass));
// Make sure the player pawn points to the proper player struct.
if (dst->mo != NULL)
if (dst->mo != nullptr)
{
dst->mo->player = dst;
}
// Same for the psprites.
DPSprite *pspr = dst->psprites;
while (pspr)
{
pspr->Owner = dst;
pspr = pspr->Next;
}
// Don't let the psprites be destroyed when src is destroyed.
src->psprites = nullptr;
// These 2 variables may not be overwritten.
dst->attackdown = attackdown;
dst->usedown = usedown;

View file

@ -3193,50 +3193,32 @@ static void P_GroupLines (bool buildmap)
{
if (linesDoneInEachSector[i] != sector->linecount)
{
I_Error ("P_GroupLines: miscounted");
I_Error("P_GroupLines: miscounted");
}
if (sector->linecount != 0)
if (sector->linecount > 3)
{
bbox.ClearBox ();
bbox.ClearBox();
for (j = 0; j < sector->linecount; ++j)
{
li = sector->lines[j];
bbox.AddToBox (li->v1->fPos());
bbox.AddToBox (li->v2->fPos());
bbox.AddToBox(li->v1->fPos());
bbox.AddToBox(li->v2->fPos());
}
// set the center to the middle of the bounding box
sector->centerspot.X = (bbox.Right() + bbox.Left()) / 2;
sector->centerspot.Y = (bbox.Top() + bbox.Bottom()) / 2;
}
// set the center to the middle of the bounding box
sector->centerspot.X = (bbox.Right() + bbox.Left()) / 2;
sector->centerspot.Y = (bbox.Top() + bbox.Bottom()) / 2;
// For triangular sectors the above does not calculate good points unless the longest of the triangle's lines is perfectly horizontal and vertical
if (sector->linecount == 3)
else if (sector->linecount > 0)
{
vertex_t *Triangle[2];
Triangle[0] = sector->lines[0]->v1;
Triangle[1] = sector->lines[0]->v2;
if (sector->linecount > 1)
// For triangular sectors the above does not calculate good points unless the longest of the triangle's lines is perfectly horizontal and vertical
DVector2 pos = { 0,0 };
for (int i = 0; i < sector->linecount; i++)
{
double dx = Triangle[1]->fX() - Triangle[0]->fX();
double dy = Triangle[1]->fY() - Triangle[0]->fY();
// Find another point in the sector that does not lie
// on the same line as the first two points.
for (j = 0; j < 2; ++j)
{
vertex_t *v;
v = (j == 1) ? sector->lines[1]->v1 : sector->lines[1]->v2;
if ( (v->fY() - Triangle[0]->fY()) * dx + (Triangle[0]->fX() - v->fX() * dy) != 0)
{
sector->centerspot.X = (Triangle[0]->fX() / 3 + Triangle[1]->fX() / 3 + v->fX() / 3);
sector->centerspot.Y = (Triangle[0]->fY() / 3 + Triangle[1]->fY() / 3 + v->fY() / 3);
break;
}
}
pos += sector->lines[i]->v1->fPos() + sector->lines[i]->v2->fPos();
}
sector->centerspot = pos / (2 * sector->linecount);
}
}
delete[] linesDoneInEachSector;
times[3].Unclock();
@ -3330,14 +3312,17 @@ void P_LoadReject (MapData * map, bool junk)
//
// [RH] P_LoadBehavior
//
void P_LoadBehavior (MapData * map)
void P_LoadBehavior(MapData * map)
{
map->Seek(ML_BEHAVIOR);
FBehavior::StaticLoadModule (-1, map->file, map->Size(ML_BEHAVIOR));
if (!FBehavior::StaticCheckAllGood ())
if (map->Size(ML_BEHAVIOR) > 0)
{
Printf ("ACS scripts unloaded.\n");
FBehavior::StaticUnloadModules ();
map->Seek(ML_BEHAVIOR);
FBehavior::StaticLoadModule(-1, map->file, map->Size(ML_BEHAVIOR));
}
if (!FBehavior::StaticCheckAllGood())
{
Printf("ACS scripts unloaded.\n");
FBehavior::StaticUnloadModules();
}
}

View file

@ -89,7 +89,8 @@ void P_SpawnTeleportFog(AActor *mobj, const DVector3 &pos, bool beforeTele, bool
}
else
{
mo = Spawn((beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType), pos, ALLOW_REPLACE);
double fogDelta = mobj->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
mo = Spawn((beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType), DVector3(pos, pos.Z + fogDelta), ALLOW_REPLACE);
}
if (mo != NULL && setTarget)
@ -192,10 +193,9 @@ bool P_Teleport (AActor *thing, DVector3 pos, DAngle angle, int flags)
{
if (!predicting)
{
double fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
DVector2 vector = angle.ToVector(20);
DVector2 fogpos = P_GetOffsetPosition(pos.X, pos.Y, vector.X, vector.Y);
P_SpawnTeleportFog(thing, DVector3(fogpos, thing->Z() + fogDelta), false, true);
P_SpawnTeleportFog(thing, DVector3(fogpos, thing->Z()), false, true);
}
if (thing->player)

View file

@ -98,7 +98,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, DAngle angle, bool fog, i
mobj->Angles.Yaw = (angle != 1000000. ? angle : spot->Angles.Yaw);
if (fog)
{
P_SpawnTeleportFog(mobj, spot->PosPlusZ(TELEFOGHEIGHT), false, true);
P_SpawnTeleportFog(mobj, spot->Pos(), false, true);
}
if (mobj->flags & MF_SPECIAL)
mobj->flags |= MF_DROPPED; // Don't respawn
@ -666,14 +666,43 @@ void InitSpawnablesFromMapinfo()
InitClassMap(SpawnableThings, SpawnablesFromMapinfo);
InitClassMap(StrifeTypes, ConversationIDsFromMapinfo);
}
int P_Thing_CheckInputNum(player_t *p, int inputnum)
{
int renum = 0;
if (p)
{
switch (inputnum)
{
case INPUT_OLDBUTTONS: renum = p->original_oldbuttons; break;
case INPUT_BUTTONS: renum = p->original_cmd.buttons; break;
case INPUT_PITCH: renum = p->original_cmd.pitch; break;
case INPUT_YAW: renum = p->original_cmd.yaw; break;
case INPUT_ROLL: renum = p->original_cmd.roll; break;
case INPUT_FORWARDMOVE: renum = p->original_cmd.forwardmove; break;
case INPUT_SIDEMOVE: renum = p->original_cmd.sidemove; break;
case INPUT_UPMOVE: renum = p->original_cmd.upmove; break;
case MODINPUT_OLDBUTTONS: renum = p->oldbuttons; break;
case MODINPUT_BUTTONS: renum = p->cmd.ucmd.buttons; break;
case MODINPUT_PITCH: renum = p->cmd.ucmd.pitch; break;
case MODINPUT_YAW: renum = p->cmd.ucmd.yaw; break;
case MODINPUT_ROLL: renum = p->cmd.ucmd.roll; break;
case MODINPUT_FORWARDMOVE: renum = p->cmd.ucmd.forwardmove; break;
case MODINPUT_SIDEMOVE: renum = p->cmd.ucmd.sidemove; break;
case MODINPUT_UPMOVE: renum = p->cmd.ucmd.upmove; break;
default: renum = 0; break;
}
}
return renum;
}
bool P_Thing_CheckProximity(AActor *self, PClass *classname, double distance, int count, int flags, int ptr)
{
AActor *ref = COPY_AAPTR(self, ptr);
// We need these to check out.
if (!ref || !classname || distance <= 0)
return nullptr;
return false;
int counter = 0;
bool result = false;

View file

@ -88,7 +88,7 @@ void P_Ticker (void)
if (paused || P_CheckTickerPaused())
return;
P_NewPspriteTick();
DPSprite::NewTick();
// [RH] Frozen mode is only changed every 4 tics, to make it work with A_Tracer().
if ((level.time & 3) == 0)
@ -118,10 +118,7 @@ void P_Ticker (void)
// Since things will be moving, it's okay to interpolate them in the renderer.
r_NoInterpolate = false;
if (!bglobal.freeze && !(level.flags2 & LEVEL2_FROZEN))
{
P_ThinkParticles (); // [RH] make the particles think
}
P_ThinkParticles(); // [RH] make the particles think
for (i = 0; i<MAXPLAYERS; i++)
if (playeringame[i] &&

View file

@ -434,7 +434,7 @@ bool FTraceInfo::LineCheck(intercept_t *in, double dist, DVector3 hit)
sector_t *hsec = CurSector->GetHeightSec();
if (Results->CrossedWater == NULL &&
hsec != NULL &&
//CurSector->heightsec->waterzone &&
Start.Z > hsec->floorplane.ZatPoint(Start) &&
hit.Z <= hsec->floorplane.ZatPoint(hit))
{
// hit crossed a water plane
@ -846,6 +846,7 @@ bool FTraceInfo::TraceTraverse (int ptflags)
if (Results->CrossedWater == NULL &&
CurSector->heightsec != NULL &&
CurSector->heightsec->floorplane.ZatPoint(Start) < Start.Z &&
CurSector->heightsec->floorplane.ZatPoint(Results->HitPos) >= Results->HitPos.Z)
{
// Save the result so that the water check doesn't destroy it.

View file

@ -271,6 +271,7 @@ player_t::player_t()
WeaponState(0),
ReadyWeapon(0),
PendingWeapon(0),
psprites(0),
cheats(0),
timefreezer(0),
refire(0),
@ -316,7 +317,11 @@ player_t::player_t()
{
memset (&cmd, 0, sizeof(cmd));
memset (frags, 0, sizeof(frags));
memset (psprites, 0, sizeof(psprites));
}
player_t::~player_t()
{
DestroyPSprites();
}
player_t &player_t::operator=(const player_t &p)
@ -372,7 +377,7 @@ player_t &player_t::operator=(const player_t &p)
extralight = p.extralight;
fixedcolormap = p.fixedcolormap;
fixedlightlevel = p.fixedlightlevel;
memcpy(psprites, &p.psprites, sizeof(psprites));
psprites = p.psprites;
morphTics = p.morphTics;
MorphedPlayerClass = p.MorphedPlayerClass;
MorphStyle = p.MorphStyle;
@ -434,6 +439,7 @@ size_t player_t::FixPointers (const DObject *old, DObject *rep)
if (ReadyWeapon == old) ReadyWeapon = static_cast<AWeapon *>(rep), changed++;
if (PendingWeapon == old) PendingWeapon = static_cast<AWeapon *>(rep), changed++;
if (*&PremorphWeapon == old) PremorphWeapon = static_cast<AWeapon *>(rep), changed++;
if (psprites == old) psprites = static_cast<DPSprite *>(rep), changed++;
if (*&ConversationNPC == old) ConversationNPC = replacement, changed++;
if (*&ConversationPC == old) ConversationPC = replacement, changed++;
if (*&MUSINFOactor == old) MUSINFOactor = replacement, changed++;
@ -452,6 +458,7 @@ size_t player_t::PropagateMark()
GC::Mark(ConversationPC);
GC::Mark(MUSINFOactor);
GC::Mark(PremorphWeapon);
GC::Mark(psprites);
if (PendingWeapon != WP_NOCHANGE)
{
GC::Mark(PendingWeapon);
@ -1371,34 +1378,37 @@ void APlayerPawn::ActivateMorphWeapon ()
{
PClassActor *morphweapon = PClass::FindActor (MorphWeapon);
player->PendingWeapon = WP_NOCHANGE;
player->psprites[ps_weapon].sy = WEAPONTOP;
if (morphweapon == NULL || !morphweapon->IsDescendantOf (RUNTIME_CLASS(AWeapon)))
if (player->ReadyWeapon != nullptr)
{
player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP;
}
if (morphweapon == nullptr || !morphweapon->IsDescendantOf (RUNTIME_CLASS(AWeapon)))
{ // No weapon at all while morphed!
player->ReadyWeapon = NULL;
P_SetPsprite (player, ps_weapon, NULL);
player->ReadyWeapon = nullptr;
}
else
{
player->ReadyWeapon = static_cast<AWeapon *>(player->mo->FindInventory (morphweapon));
if (player->ReadyWeapon == NULL)
if (player->ReadyWeapon == nullptr)
{
player->ReadyWeapon = static_cast<AWeapon *>(player->mo->GiveInventoryType (morphweapon));
if (player->ReadyWeapon != NULL)
if (player->ReadyWeapon != nullptr)
{
player->ReadyWeapon->GivenAsMorphWeapon = true; // flag is used only by new beastweap semantics in P_UndoPlayerMorph
}
}
if (player->ReadyWeapon != NULL)
if (player->ReadyWeapon != nullptr)
{
P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState());
}
else
{
P_SetPsprite (player, ps_weapon, NULL);
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetReadyState());
}
}
P_SetPsprite (player, ps_flash, NULL);
if (player->ReadyWeapon != nullptr)
{
P_SetPsprite(player, PSP_FLASH, nullptr);
}
player->PendingWeapon = WP_NOCHANGE;
}
@ -2115,7 +2125,7 @@ void P_DeathThink (player_t *player)
int dir;
DAngle delta;
P_MovePsprites (player);
player->TickPSprites();
player->onground = (player->mo->Z() <= player->mo->floorz);
if (player->mo->IsKindOf (RUNTIME_CLASS(APlayerChunk)))
@ -2635,7 +2645,7 @@ void P_PlayerThink (player_t *player)
}
}
// Cycle psprites
P_MovePsprites (player);
player->TickPSprites();
// Other Counters
if (player->damagecount)
@ -3065,8 +3075,56 @@ void player_t::Serialize (FArchive &arc)
for (i = 0; i < MAXPLAYERS; i++)
arc << frags[i];
for (i = 0; i < NUMPSPRITES; i++)
arc << psprites[i];
if (SaveVersion < 4547)
{
int layer = PSP_WEAPON;
for (i = 0; i < 5; i++)
{
FState *state;
int tics;
double sx, sy;
int sprite;
int frame;
arc << state << tics
<< sx << sy
<< sprite << frame;
if (state != nullptr &&
((layer < PSP_TARGETCENTER && ReadyWeapon != nullptr) ||
(layer >= PSP_TARGETCENTER && mo->FindInventory(RUNTIME_CLASS(APowerTargeter), true))))
{
DPSprite *pspr;
pspr = GetPSprite(PSPLayers(layer));
pspr->State = state;
pspr->Tics = tics;
pspr->Sprite = sprite;
pspr->Frame = frame;
pspr->Owner = this;
if (layer == PSP_FLASH)
{
pspr->x = 0;
pspr->y = 0;
}
else
{
pspr->x = sx;
pspr->y = sy;
}
}
if (layer == PSP_WEAPON)
layer = PSP_FLASH;
else if (layer == PSP_FLASH)
layer = PSP_TARGETCENTER;
else
layer++;
}
}
else
arc << psprites;
arc << CurrentPlayerClass;

View file

@ -270,14 +270,31 @@ static line_t *FindDestination(line_t *src, int tag)
static void SetRotation(FLinePortal *port)
{
if (port != NULL && port->mDestination != NULL)
if (port != nullptr && port->mDestination != nullptr)
{
line_t *dst = port->mDestination;
line_t *line = port->mOrigin;
DAngle angle = dst->Delta().Angle() - line->Delta().Angle() + 180.;
port->mSinRot = sindeg(angle.Degrees); // Here precision matters so use the slower but more precise versions.
port->mCosRot = cosdeg(angle.Degrees);
port->mAngleDiff = angle;
if (port->mType != PORTT_LINKED)
{
line_t *dst = port->mDestination;
line_t *line = port->mOrigin;
DAngle angle = dst->Delta().Angle() - line->Delta().Angle() + 180.;
port->mSinRot = sindeg(angle.Degrees); // Here precision matters so use the slower but more precise versions.
port->mCosRot = cosdeg(angle.Degrees);
port->mAngleDiff = angle;
if ((line->sidedef[0]->Flags & WALLF_POLYOBJ) || (dst->sidedef[0]->Flags & WALLF_POLYOBJ))
{
port->mFlags |= PORTF_POLYOBJ;
}
else
{
port->mFlags &= ~PORTF_POLYOBJ;
}
}
else
{
// Linked portals have no angular difference.
port->mSinRot = port->mCosRot = 0.;
port->mAngleDiff = 0.;
}
}
}
@ -323,11 +340,6 @@ void P_SpawnLinePortal(line_t* line)
{
port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE : port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT : PORTF_TYPEINTERACTIVE;
}
// Get the angle between the two linedefs, for rotating
// orientation and velocity. Rotate 180 degrees, and flip
// the position across the exit linedef, if reversed.
SetRotation(port);
}
else if (line->args[2] == PORTT_LINKEDEE && line->args[0] == 0)
{
@ -348,7 +360,6 @@ void P_SpawnLinePortal(line_t* line)
port->mType = PORTT_LINKED;
port->mAlign = PORG_ABSOLUTE;
port->mDefFlags = PORTF_TYPEINTERACTIVE;
SetRotation(port);
// we need to create the backlink here, too.
lines[i].portalindex = linePortals.Reserve(1);
@ -360,8 +371,6 @@ void P_SpawnLinePortal(line_t* line)
port->mType = PORTT_LINKED;
port->mAlign = PORG_ABSOLUTE;
port->mDefFlags = PORTF_TYPEINTERACTIVE;
SetRotation(port);
}
}
}
@ -411,6 +420,9 @@ void P_UpdatePortal(FLinePortal *port)
}
}
}
// Cache the angle between the two linedefs, for rotating.
SetRotation(port);
}
//============================================================================
@ -591,6 +603,7 @@ void P_TranslatePortalXY(line_t* src, double& x, double& y)
if (!src) return;
FLinePortal *port = src->getPortal();
if (!port) return;
if (port->mFlags & PORTF_POLYOBJ) SetRotation(port); // update the angle for polyportals.
// offsets from line
double nposx = x - src->v1->fX();
@ -618,6 +631,7 @@ void P_TranslatePortalVXVY(line_t* src, double &velx, double &vely)
if (!src) return;
FLinePortal *port = src->getPortal();
if (!port) return;
if (port->mFlags & PORTF_POLYOBJ) SetRotation(port); // update the angle for polyportals.
double orig_velx = velx;
double orig_vely = vely;
@ -636,6 +650,7 @@ void P_TranslatePortalAngle(line_t* src, DAngle& angle)
if (!src) return;
FLinePortal *port = src->getPortal();
if (!port) return;
if (port->mFlags & PORTF_POLYOBJ) SetRotation(port); // update the angle for polyportals.
angle = (angle + port->mAngleDiff).Normalized360();
}

View file

@ -145,6 +145,7 @@ enum
PORTF_PASSABLE = 2,
PORTF_SOUNDTRAVERSE = 4,
PORTF_INTERACTIVE = 8,
PORTF_POLYOBJ = 16,
PORTF_TYPETELEPORT = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE,
PORTF_TYPEINTERACTIVE = PORTF_VISIBLE | PORTF_PASSABLE | PORTF_SOUNDTRAVERSE | PORTF_INTERACTIVE,

View file

@ -1038,11 +1038,17 @@ FScriptPosition &FScriptPosition::operator=(const FScriptPosition &other)
//
//==========================================================================
CVAR(Bool, strictdecorate, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
void FScriptPosition::Message (int severity, const char *message, ...) const
{
FString composed;
if ((severity == MSG_DEBUG || severity == MSG_DEBUGLOG) && !developer) return;
if (severity == MSG_OPTERROR)
{
severity = strictdecorate ? MSG_ERROR : MSG_WARNING;
}
if (message == NULL)
{

View file

@ -124,6 +124,7 @@ enum
MSG_WARNING,
MSG_FATAL,
MSG_ERROR,
MSG_OPTERROR,
MSG_DEBUG,
MSG_LOG,
MSG_DEBUGLOG,

View file

@ -431,11 +431,11 @@ void LoadActors ()
FScanner sc(lump);
ParseDecorate (sc);
}
FinishThingdef();
if (FScriptPosition::ErrorCounter > 0)
{
I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter);
}
FinishThingdef();
timer.Unclock();
if (!batchrun) Printf("DECORATE parsing took %.2f ms\n", timer.TimeMS());
// Base time: ~52 ms

View file

@ -350,7 +350,7 @@ int MatchString (const char *in, const char **strings);
//#define PUSH_PARAMINFO self, stateowner, CallingState, ParameterIndex, statecall
#define CALL_ACTION(name,self) { /*AF_##name(self, self, NULL, 0, NULL)*/ \
VMValue params[3] = { self, self, VMValue(NULL, ATAG_STATE) }; \
VMValue params[3] = { self, self, VMValue(NULL, ATAG_STATEINFO) }; \
stack->Call(name##_VMPtr, params, countof(params), NULL, 0, NULL); \
}
@ -360,7 +360,7 @@ int MatchString (const char *in, const char **strings);
#define ACTION_RETURN_BOOL(v) ACTION_RETURN_INT(v)
// Checks to see what called the current action function
#define ACTION_CALL_FROM_ACTOR() (callingstate == self->state)
#define ACTION_CALL_FROM_WEAPON() (self->player && callingstate != self->state && !(stateowner->flags5 & MF5_INSTATECALL))
#define ACTION_CALL_FROM_INVENTORY() (!(stateowner->flags5 & MF5_INSTATECALL))
#define ACTION_CALL_FROM_ACTOR() (stateinfo == nullptr || stateinfo->mStateType == STATE_Actor)
#define ACTION_CALL_FROM_PSPRITE() (self->player && stateinfo != nullptr && stateinfo->mStateType == STATE_Psprite)
#define ACTION_CALL_FROM_INVENTORY() (stateinfo != nullptr && stateinfo->mStateType == STATE_StateChain)
#endif

View file

@ -95,6 +95,7 @@ static FRandom pr_spawnitemex ("SpawnItemEx");
static FRandom pr_burst ("Burst");
static FRandom pr_monsterrefire ("MonsterRefire");
static FRandom pr_teleport("A_Teleport");
static FRandom pr_bfgselfdamage("BFGSelfDamage");
//==========================================================================
//
@ -119,7 +120,6 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state)
ret[0].PointerAt((void **)&nextstate);
ret[1].IntAt(&retval);
this->flags5 |= MF5_INSTATECALL;
FState *savedstate = this->state;
while (state != NULL)
@ -132,8 +132,9 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state)
VMFrameStack stack;
PPrototype *proto = state->ActionFunc->Proto;
VMReturn *wantret;
FStateParamInfo stp = { state, STATE_StateChain, PSP_WEAPON };
params[2] = VMValue(state, ATAG_STATE);
params[2] = VMValue(&stp, ATAG_STATEINFO);
retval = true; // assume success
wantret = NULL; // assume no return value wanted
numret = 0;
@ -189,7 +190,6 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state)
}
state = nextstate;
}
this->flags5 &= ~MF5_INSTATECALL;
this->state = savedstate;
return !!result;
}
@ -312,6 +312,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance)
DVector3 diff = self->Vec3To(target);
if (checkz)
diff.Z += (target->Height - self->Height) / 2;
else
diff.Z = 0.;
ret->SetFloat(diff.Length());
}
@ -513,6 +515,69 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCrouchFactor)
return 0;
}
//==========================================================================
//
// GetCVar
//
// NON-ACTION function that works like ACS's GetCVar.
//
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCVar)
{
if (numret > 0)
{
assert(ret != nullptr);
PARAM_SELF_PROLOGUE(AActor);
PARAM_STRING(cvarname);
FBaseCVar *cvar = GetCVar(self, cvarname);
if (cvar == nullptr)
{
ret->SetFloat(0);
}
else
{
ret->SetFloat(cvar->GetGenericRep(CVAR_Float).Float);
}
return 1;
}
return 0;
}
//==========================================================================
//
// GetPlayerInput
//
// NON-ACTION function that works like ACS's GetPlayerInput.
// Takes a pointer as anyone may or may not be a player.
//==========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetPlayerInput)
{
if (numret > 0)
{
assert(ret != nullptr);
PARAM_SELF_PROLOGUE(AActor);
PARAM_INT (inputnum);
PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; }
AActor *mobj = COPY_AAPTR(self, ptr);
//Need a player.
if (!mobj || !mobj->player)
{
ret->SetInt(0);
}
else
{
ret->SetInt(P_Thing_CheckInputNum(mobj->player, inputnum));
}
return 1;
}
return 0;
}
//===========================================================================
//
// __decorate_internal_state__
@ -1304,6 +1369,72 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusThrust)
return 0;
}
//==========================================================================
//
// A_RadiusDamageSelf
//
//==========================================================================
enum
{
RDSF_BFGDAMAGE = 1,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RadiusDamageSelf)
{
PARAM_ACTION_PROLOGUE;
PARAM_INT_OPT(damage) { damage = 128; }
PARAM_FLOAT_OPT(distance) { distance = 128; }
PARAM_INT_OPT(flags) { flags = 0; }
PARAM_CLASS_OPT(flashtype, AActor) { flashtype = NULL; }
int i;
int damageSteps;
int actualDamage;
double actualDistance;
actualDistance = self->Distance3D(self->target);
if (actualDistance < distance)
{
// [XA] Decrease damage with distance. Use the BFG damage
// calculation formula if the flag is set (essentially
// a generalization of SMMU's BFG11K behavior, used
// with fraggle's blessing.)
damageSteps = damage - int(damage * actualDistance / distance);
if (flags & RDSF_BFGDAMAGE)
{
actualDamage = 0;
for (i = 0; i < damageSteps; ++i)
actualDamage += (pr_bfgselfdamage() & 7) + 1;
}
else
{
actualDamage = damageSteps;
}
// optional "flash" effect -- spawn an actor on
// the player to indicate bad things happened.
AActor *flash = NULL;
if(flashtype != NULL)
flash = Spawn(flashtype, self->target->PosPlusZ(self->target->Height / 4), ALLOW_REPLACE);
int dmgFlags = 0;
FName dmgType = NAME_BFGSplash;
if (flash != NULL)
{
if (flash->flags5 & MF5_PUFFGETSOWNER) flash->target = self->target;
if (flash->flags3 & MF3_FOILINVUL) dmgFlags |= DMG_FOILINVUL;
if (flash->flags7 & MF7_FOILBUDDHA) dmgFlags |= DMG_FOILBUDDHA;
dmgType = flash->DamageType;
}
int newdam = P_DamageMobj(self->target, self, self->target, actualDamage, dmgType, dmgFlags);
P_TraceBleed(newdam > 0 ? newdam : actualDamage, self->target, self);
}
return 0;
}
//==========================================================================
//
// Execute a line special / script
@ -1644,7 +1775,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfNoAmmo)
PARAM_ACTION_PROLOGUE;
PARAM_STATE(jump);
if (!ACTION_CALL_FROM_WEAPON())
if (!ACTION_CALL_FROM_PSPRITE() || self->player->ReadyWeapon == nullptr)
{
ACTION_RETURN_STATE(NULL);
}
@ -1693,7 +1824,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
DAngle bslope = 0.;
int laflags = (flags & FBF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0;
if ((flags & FBF_USEAMMO) && weapon && ACTION_CALL_FROM_WEAPON())
if ((flags & FBF_USEAMMO) && weapon && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo(weapon->bAltFire, true))
return 0; // out of ammo
@ -1784,7 +1915,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireCustomMissile)
FTranslatedLineTarget t;
// Only use ammo if called from a weapon
if (useammo && ACTION_CALL_FROM_WEAPON() && weapon)
if (useammo && ACTION_CALL_FROM_PSPRITE() && weapon)
{
if (!weapon->DepleteAmmo(weapon->bAltFire, true))
return 0; // out of ammo
@ -1876,7 +2007,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
pitch = P_AimLineAttack (self, angle, range, &t);
// only use ammo when actually hitting something!
if ((flags & CPF_USEAMMO) && t.linetarget && weapon && ACTION_CALL_FROM_WEAPON())
if ((flags & CPF_USEAMMO) && t.linetarget && weapon && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo(weapon->bAltFire, true))
return 0; // out of ammo
@ -1966,6 +2097,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; }
PARAM_FLOAT_OPT (spawnofs_z) { spawnofs_z = 0; }
PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; }
PARAM_INT_OPT (limit) { limit = 0; }
if (range == 0) range = 8192;
if (sparsity == 0) sparsity=1.0;
@ -1976,7 +2108,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
AWeapon *weapon = self->player->ReadyWeapon;
// only use ammo when actually hitting something!
if (useammo && weapon != NULL && ACTION_CALL_FROM_WEAPON())
if (useammo && weapon != NULL && ACTION_CALL_FROM_PSPRITE())
{
if (!weapon->DepleteAmmo(weapon->bAltFire, true))
return 0; // out of ammo
@ -2006,6 +2138,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
p.drift = driftspeed;
p.spawnclass = spawnclass;
p.SpiralOffset = SpiralOffset;
p.limit = limit;
P_RailAttack(&p);
return 0;
}
@ -2043,6 +2176,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; }
PARAM_FLOAT_OPT (spawnofs_z) { spawnofs_z = 0; }
PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; }
PARAM_INT_OPT (limit) { limit = 0; }
if (range == 0) range = 8192.;
if (sparsity == 0) sparsity = 1;
@ -2125,6 +2259,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
p.drift = driftspeed;
p.spawnclass = spawnclass;
p.SpiralOffset = SpiralOffset;
p.limit = 0;
P_RailAttack(&p);
self->SetXYZ(savedpos);
@ -2560,7 +2695,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnItem)
ACTION_RETURN_BOOL(true);
}
if (ACTION_CALL_FROM_WEAPON())
if (ACTION_CALL_FROM_PSPRITE())
{
// Used from a weapon, so use some ammo
AWeapon *weapon = self->player->ReadyWeapon;
@ -2685,7 +2820,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ThrowGrenade)
{
ACTION_RETURN_BOOL(true);
}
if (ACTION_CALL_FROM_WEAPON())
if (ACTION_CALL_FROM_PSPRITE())
{
// Used from a weapon, so use some ammo
AWeapon *weapon = self->player->ReadyWeapon;
@ -3147,6 +3282,7 @@ enum SPFflag
SPF_RELVEL = 1 << 2,
SPF_RELACCEL = 1 << 3,
SPF_RELANG = 1 << 4,
SPF_NOTIMEFREEZE = 1 << 5,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle)
@ -3155,7 +3291,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle)
PARAM_COLOR (color);
PARAM_INT_OPT (flags) { flags = 0; }
PARAM_INT_OPT (lifetime) { lifetime = 35; }
PARAM_INT_OPT (size) { size = 1; }
PARAM_FLOAT_OPT (size) { size = 1.; }
PARAM_ANGLE_OPT (angle) { angle = 0.; }
PARAM_FLOAT_OPT (xoff) { xoff = 0; }
PARAM_FLOAT_OPT (yoff) { yoff = 0; }
@ -3168,11 +3304,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle)
PARAM_FLOAT_OPT (accelz) { accelz = 0; }
PARAM_FLOAT_OPT (startalpha) { startalpha = 1.; }
PARAM_FLOAT_OPT (fadestep) { fadestep = -1.; }
PARAM_FLOAT_OPT (sizestep) { sizestep = 0.; }
startalpha = clamp(startalpha, 0., 1.);
if (fadestep > 0) fadestep = clamp(fadestep, 0., 1.);
size = clamp<int>(size, 0, 65535); // Clamp to word
size = fabs(size);
if (lifetime != 0)
{
if (flags & SPF_RELANG) angle += self->Angles.Yaw;
@ -3199,7 +3335,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle)
acc.X = accelx * c + accely * s;
acc.Y = accelx * s - accely * c;
}
P_SpawnParticle(self->Vec3Offset(pos), vel, acc, color, !!(flags & SPF_FULLBRIGHT), startalpha, lifetime, size, fadestep);
P_SpawnParticle(self->Vec3Offset(pos), vel, acc, color, startalpha, lifetime, size, fadestep, sizestep, flags);
}
return 0;
}
@ -5737,19 +5873,21 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics)
PARAM_ACTION_PROLOGUE;
PARAM_INT(tics_to_set);
if (stateowner != self && self->player != NULL && stateowner->IsKindOf(RUNTIME_CLASS(AWeapon)))
{ // Is this a weapon? Need to check psp states for a match, then. Blah.
for (int i = 0; i < NUMPSPRITES; ++i)
if (ACTION_CALL_FROM_PSPRITE())
{
DPSprite *pspr = self->player->FindPSprite(stateinfo->mPSPIndex);
if (pspr != nullptr)
{
if (self->player->psprites[i].state == callingstate)
{
self->player->psprites[i].tics = tics_to_set;
return 0;
}
pspr->Tics = tics_to_set;
return 0;
}
}
// Just set tics for self.
self->tics = tics_to_set;
else if (ACTION_CALL_FROM_ACTOR())
{
// Just set tics for self.
self->tics = tics_to_set;
}
// for inventory state chains this needs to be ignored.
return 0;
}
@ -6900,10 +7038,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection)
{
DAngle current = mobj->Angles.Pitch;
const DVector2 velocity = mobj->Vel.XY();
DAngle pitch = VecToAngle(velocity.Length(), -mobj->Vel.Z);
DAngle pitch = VecToAngle(velocity.Length(), mobj->Vel.Z);
if (pitchlimit > 0)
{
DAngle pdelta = deltaangle(current, pitch);
DAngle pdelta = deltaangle(-current, pitch);
if (fabs(pdelta) > pitchlimit)
{
@ -6930,3 +7068,4 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection)
}
ACTION_RETURN_BOOL(true);
}

View file

@ -265,6 +265,11 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(RF, INVISIBLE, AActor, renderflags),
DEFINE_FLAG(RF, FORCEYBILLBOARD, AActor, renderflags),
DEFINE_FLAG(RF, FORCEXYBILLBOARD, AActor, renderflags),
DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard
// [fgsfds] Flat sprites
DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags),
DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags),
DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags),
// Bounce flags
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),

View file

@ -208,7 +208,7 @@ public:
virtual bool isConstant() const;
virtual void RequestAddress();
virtual VMFunction *GetDirectFunction();
bool IsNumeric() const { return ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT; }
bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
virtual ExpEmit Emit(VMFunctionBuilder *build);

View file

@ -358,10 +358,22 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
if (basex->ValueType->GetRegType() == REGT_INT)
{
FxExpression *x = basex;
basex = NULL;
delete this;
return x;
if (basex->ValueType != TypeName)
{
FxExpression *x = basex;
basex = NULL;
delete this;
return x;
}
else
{
// Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :(
if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name");
else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars());
FxExpression * x = new FxConstant(0, ScriptPosition);
delete this;
return x;
}
}
else if (basex->ValueType->GetRegType() == REGT_FLOAT)
{
@ -374,12 +386,9 @@ FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
}
return this;
}
else
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
return NULL;
}
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
return NULL;
}
//==========================================================================
@ -443,14 +452,26 @@ FxExpression *FxFloatCast::Resolve(FCompileContext &ctx)
}
else if (basex->ValueType->GetRegType() == REGT_INT)
{
if (basex->isConstant())
if (basex->ValueType != TypeName)
{
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition);
if (basex->isConstant())
{
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition);
delete this;
return x;
}
return this;
}
else
{
// Ugh. This should abort, but too many mods fell into this logic hole somewhere, so this seroious error needs to be reduced to a warning. :(
if (!basex->isConstant()) ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got a name");
else ScriptPosition.Message(MSG_OPTERROR, "Numeric type expected, got \"%s\"", static_cast<FxConstant*>(basex)->GetValue().GetName().GetChars());
FxExpression *x = new FxConstant(0.0, ScriptPosition);
delete this;
return x;
}
return this;
}
else
{
@ -2895,7 +2916,7 @@ ExpEmit FxDamage::Emit(VMFunctionBuilder *build)
build->Emit(OP_LO, dmgfunc.RegNum, 0/*self*/, build->GetConstantInt(myoffsetof(AActor, Damage)));
// If it's non-null...
build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(0, ATAG_GENERIC));
build->Emit(OP_EQA_K, 1, dmgfunc.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC));
size_t nulljump = build->Emit(OP_JMP, 0);
// ...call it
@ -3903,7 +3924,7 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
{
/* lax */
// Since this happens in released WADs it must pass without a terminal error... :(
ScriptPosition.Message(MSG_WARNING,
ScriptPosition.Message(MSG_OPTERROR,
"Unknown class name '%s'",
clsname.GetChars(), desttype->TypeName.GetChars());
}
@ -4074,7 +4095,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
destination = scope->FindState(names.Size()-1, &names[1], false);
if (destination == NULL)
{
ScriptPosition.Message(MSG_WARNING, "Unknown state jump destination");
ScriptPosition.Message(MSG_OPTERROR, "Unknown state jump destination");
/* lax */
return this;
}

View file

@ -457,7 +457,7 @@ DEFINE_PROPERTY(skip_super, 0, Actor)
}
if (bag.StateSet)
{
bag.ScriptPosition.Message(MSG_WARNING,
bag.ScriptPosition.Message(MSG_OPTERROR,
"'skip_super' must appear before any state definitions.");
return;
}

View file

@ -152,6 +152,7 @@ enum
ATAG_AREGISTER, // pointer to an address register
ATAG_STATE, // pointer to FState
ATAG_STATEINFO, // FState plus some info.
ATAG_RNG, // pointer to FRandom
};
@ -914,6 +915,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_ANGLE_OPT_AT(p,x) DAngle x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else
#define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else
#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else
#define PARAM_STATEINFO_OPT_AT(p,x) FStateParamInfo *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATEINFO || param[p].a == NULL)); x = (FStateParamInfo *)param[p].a; } else
#define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else
#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else
#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); } else
@ -943,6 +945,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_ANGLE_OPT(x) ++paramnum; PARAM_ANGLE_OPT_AT(paramnum,x)
#define PARAM_STRING_OPT(x) ++paramnum; PARAM_STRING_OPT_AT(paramnum,x)
#define PARAM_STATE_OPT(x) ++paramnum; PARAM_STATE_OPT_AT(paramnum,x)
#define PARAM_STATEINFO_OPT(x) ++paramnum; PARAM_STATEINFO_OPT_AT(paramnum,x)
#define PARAM_POINTER_OPT(x,type) ++paramnum; PARAM_POINTER_OPT_AT(paramnum,x,type)
#define PARAM_OBJECT_OPT(x,type) ++paramnum; PARAM_OBJECT_OPT_AT(paramnum,x,type)
#define PARAM_CLASS_OPT(x,base) ++paramnum; PARAM_CLASS_OPT_AT(paramnum,x,base)

View file

@ -153,7 +153,7 @@ static void InitTokenMap()
TOKENDEF (TK_NoDelay, ZCC_NODELAY);
TOKENDEF (TK_Offset, ZCC_OFFSET);
TOKENDEF (TK_CanRaise, ZCC_CANRAISE);
TOKENDEF (TK_Light, ZCC_CANRAISE);
TOKENDEF (TK_Light, ZCC_LIGHT);
ZCC_InitOperators();
ZCC_InitConversions();

View file

@ -1,6 +1,7 @@
#library "strfhelp"
#include "zcommon.acs"
#library "strfhelp"
#define VDOORSPEED 16
#define VDOORWAIT 150
@ -69,6 +70,7 @@ script << 0 >> (int type, int tag)
case 230:
i = GetLineRowOffset() & 31;
if (i == 0) break;
if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
{
Door_Open (tag, VDOORSPEED);
@ -78,6 +80,7 @@ script << 0 >> (int type, int tag)
case 227:
i = GetLineRowOffset() & 31;
if (i == 0) break;
if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
{
Door_Close (tag, VDOORSPEED);
@ -126,6 +129,7 @@ script << 0 >> (int type, int tag)
case 193:
i = GetLineRowOffset() & 31;
if (i == 0) break;
if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
{
Floor_LowerToLowest (tag, 8);
@ -158,6 +162,7 @@ script << 0 >> (int type, int tag)
case 187:
i = GetLineRowOffset() & 31;
if (i == 0) break;
if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
{
ClearForceField (tag);
@ -203,6 +208,7 @@ script << 0 >> (int type, int tag)
case 216:
i = GetLineRowOffset() & 31;
if (i == 0) break;
if (CheckInventory (QuestItems[i]) || gametype() == GAME_NET_DEATHMATCH)
{
Door_Raise (tag, VDOORSPEED, VDOORWAIT);

View file

@ -34,8 +34,7 @@ ACTOR Actor native //: Thinker
DefThreshold 100
BloodType "Blood", "BloodSplatter", "AxeBlood"
ExplosionDamage 128
MissileHeight 32
MissileHeight 32
// Functions
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
@ -47,6 +46,8 @@ ACTOR Actor native //: Thinker
native int GetSpawnHealth();
native int GetGibHealth();
native float GetCrouchFactor(int ptr = AAPTR_PLAYER1);
native float GetCVar(string cvar);
native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT);
// Action functions
// Meh, MBF redundant functions. Only for DeHackEd support.
@ -55,7 +56,7 @@ ACTOR Actor native //: Thinker
// End of MBF redundant functions.
action native A_MonsterRail();
action native A_BFGSpray(class<Actor> spraytype = "BFGExtra", int numrays = 40, int damagecount = 15, float/*angle*/ angle = 90, float distance = 16*64, float/*angle*/ vrange = 32, int damage = 0);
action native A_BFGSpray(class<Actor> spraytype = "BFGExtra", int numrays = 40, int damagecount = 15, float/*angle*/ angle = 90, float distance = 16*64, float/*angle*/ vrange = 32, int damage = 0, int flags = 0);
action native A_Pain();
action native A_NoBlocking();
action native A_XScream();
@ -189,7 +190,7 @@ ACTOR Actor native //: Thinker
native state A_Jump(int chance = 256, state label, ...);
native void A_CustomMissile(class<Actor> missiletype, float spawnheight = 32, float spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET);
native void A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET);
native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270);
native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270, int limit = 0);
native state A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT);
native state A_JumpIfCloser(float distance, state label, bool noz = false);
native state A_JumpIfTracerCloser(float distance, state label, bool noz = false);
@ -214,7 +215,7 @@ ACTOR Actor native //: Thinker
native void A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false);
native void A_SetMass(int mass);
native void A_SpawnDebris(class<Actor> spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1);
native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, int size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1);
native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, float size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1, float sizestep = 0);
native state A_CheckSight(state label);
native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false);
native void A_DropInventory(class<Inventory> itemtype);
@ -246,6 +247,7 @@ ACTOR Actor native //: Thinker
native void A_Burst(class<Actor> chunktype);
action native A_Blast(int flags = 0, float strength = 255, float radius = 255, float speed = 20, class<Actor> blasteffect = "BlastEffect", sound blastsound = "BlastRadius");
action native A_RadiusThrust(int force = 128, int distance = -1, int flags = RTF_AFFECTSOURCE, int fullthrustdistance = 0);
action native A_RadiusDamageSelf(int damage = 128, float distance = 128, int flags = 0, class<Actor> flashtype = "None");
action native A_Explode(int damage = -1, int distance = -1, int flags = XF_HURTSOURCE, bool alert = false, int fulldamagedistance = 0, int nails = 0, int naildamage = 10, class<Actor> pufftype = "BulletPuff");
action native A_Stop();
action native A_Respawn(int flags = 1);
@ -327,11 +329,17 @@ ACTOR Actor native //: Thinker
native state A_CheckSightOrRange(float distance, state label, bool two_dimension = false);
native state A_CheckRange(float distance, state label, bool two_dimension = false);
action native bool A_FaceMovementDirection(float offset = 0, float anglelimit = 0, float pitchlimit = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
action native int A_ClearOverlays(int sstart = 0, int sstop = 0, bool safety = true);
native void A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0);
native void A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0);
action native A_CopyFriendliness(int ptr_source = AAPTR_MASTER);
action native bool A_Overlay(int layer, state start = "", bool nooverride = false);
action native A_WeaponOffset(float wx = 0, float wy = 32, int flags = 0);
action native A_OverlayOffset(int layer = PSP_WEAPON, float wx = 0, float wy = 32, int flags = 0);
action native A_OverlayFlags(int layer, int flags, bool set);
native int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0);
native int ACS_NamedSuspend(name script, int mapnum=0);
native int ACS_NamedTerminate(name script, int mapnum=0);

View file

@ -18,6 +18,10 @@ const int SF_NOPULLIN = 32;
const int SF_NOTURN = 64;
const int SF_STEALARMOR = 128;
// Flags for A_BFGSpray
const int BFGF_HURTSOURCE = 1;
const int BFGF_MISSILEORIGIN = 2;
// Flags for A_CustomMissile
const int CMF_AIMOFFSET = 1;
const int CMF_AIMDIRECTION = 2;
@ -180,6 +184,9 @@ const int RTF_NOIMPACTDAMAGE = 2;
const int RTF_NOTMISSILE = 4;
const int RTF_THRUSTZ = 16;
// Flags for A_RadiusDamageSelf
const int RDSF_BFGDAMAGE = 1;
// Flags for A_Blast
const int BF_USEAMMO = 1;
const int BF_DONTWARN = 2;
@ -539,6 +546,7 @@ enum
SPF_RELVEL = 1 << 2,
SPF_RELACCEL = 1 << 3,
SPF_RELANG = 1 << 4,
SPF_NOTIMEFREEZE = 1 << 5,
SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG
};
@ -568,4 +576,79 @@ enum
WOF_KEEPX = 1,
WOF_KEEPY = 1 << 1,
WOF_ADD = 1 << 2,
};
};
// Flags for psprite layers
enum
{
PSPF_ADDWEAPON = 1 << 0,
PSPF_ADDBOB = 1 << 1,
PSPF_POWDOUBLE = 1 << 2,
PSPF_CVARFAST = 1 << 3,
};
// Default psprite layers
enum
{
PSP_WEAPON = 1,
PSP_FLASH = 1000,
};
enum
{
// These are the original inputs sent by the player.
INPUT_OLDBUTTONS,
INPUT_BUTTONS,
INPUT_PITCH,
INPUT_YAW,
INPUT_ROLL,
INPUT_FORWARDMOVE,
INPUT_SIDEMOVE,
INPUT_UPMOVE,
// These are the inputs, as modified by P_PlayerThink().
// Most of the time, these will match the original inputs, but
// they can be different if a player is frozen or using a
// chainsaw.
MODINPUT_OLDBUTTONS,
MODINPUT_BUTTONS,
MODINPUT_PITCH,
MODINPUT_YAW,
MODINPUT_ROLL,
MODINPUT_FORWARDMOVE,
MODINPUT_SIDEMOVE,
MODINPUT_UPMOVE
};
enum
{
BT_ATTACK = 1<<0, // Press "Fire".
BT_USE = 1<<1, // Use button, to open doors, activate switches.
BT_JUMP = 1<<2,
BT_CROUCH = 1<<3,
BT_TURN180 = 1<<4,
BT_ALTATTACK = 1<<5, // Press your other "Fire".
BT_RELOAD = 1<<6, // [XA] Reload key. Causes state jump in A_WeaponReady.
BT_ZOOM = 1<<7, // [XA] Zoom key. Ditto.
// The rest are all ignored by the play simulation and are for scripts.
BT_SPEED = 1<<8,
BT_STRAFE = 1<<9,
BT_MOVERIGHT = 1<<10,
BT_MOVELEFT = 1<<11,
BT_BACK = 1<<12,
BT_FORWARD = 1<<13,
BT_RIGHT = 1<<14,
BT_LEFT = 1<<15,
BT_LOOKUP = 1<<16,
BT_LOOKDOWN = 1<<17,
BT_MOVEUP = 1<<18,
BT_MOVEDOWN = 1<<19,
BT_SHOWSCORES = 1<<20,
BT_USER1 = 1<<21,
BT_USER2 = 1<<22,
BT_USER3 = 1<<23,
BT_USER4 = 1<<24,
};

View file

@ -11,7 +11,7 @@ ACTOR Inventory native
action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class<Actor> pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class<BasicArmorBonus> armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = "");
action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class<Actor> pufftype = "BulletPuff", int flags = 1, float range = 0);
action native A_FireCustomMissile(class<Actor> missiletype, float angle = 0, bool useammo = true, float spawnofs_xy = 0, float spawnheight = 0, int flags = 0, float pitch = 0);
action native A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270);
action native A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class<Actor> pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class<Actor> spawnclass = "none", float spawnofs_z = 0, int spiraloffset = 270, int limit = 0);
action native A_Light(int extralight);
action native A_Light0();
action native A_Light1();
@ -48,8 +48,7 @@ ACTOR Inventory native
action native A_RestoreSpecialDoomThing();
action native A_RestoreSpecialThing1();
action native A_RestoreSpecialThing2();
action native A_WeaponOffset(float wx = 0, float wy = 32, int flags = 0);
States
{
HideDoomish:

View file

@ -425,6 +425,11 @@ D0139194F7817BF06F3988DFC47DB38D // Whispers of Satan map29
multiexit
}
C98F79709BD7E0E4C19026AB9575EC6F // cc-cod.zip:codlev.wad map07
{
maskedmidtex
}
D7F6E9F08C39A17026349A04F8C0B0BE // Return to Hadron, e1m9
19D03FFC875589E21EDBB7AB74EF4AEF // Return to Hadron, e1m9, 2016.01.03 update
{

View file

@ -1,5 +1,16 @@
// Must be sorted in identification order (easiest to recognize first!)
IWad
{
Name = "Delaweare"
Autoname = "delaweare"
Game = "Doom"
Config = "Delaweare"
Mapinfo = "mapinfo/doom2.txt"
MustContain = "TITLEMAP", "ROVEA0", "GRLURD01", "SQOUI01"
BannerColors = "00 00 00", "ff ff ff"
}
IWad
{
Name = "The Adventures of Square"
@ -393,4 +404,5 @@ Names
"hacx.wad"
"hacx2.wad"
"square1.pk3"
"delaweare.wad"
}

View file

@ -108,5 +108,7 @@ CMPTMNU_SECTORSOUNDS = "Sector sounds use centre as source";
OPTVAL_MAPDEFINEDCOLORSONLY = "Map defined colours only";
C_GRAY = "\ccgrey";
C_DARKGRAY = "\cudark grey";
DSPLYMNU_MOVEBOB = "View bob amount while moving";
DSPLYMNU_STILLBOB = "View bob amount while not moving";
OPTVAL_ANYFIXEDCOLORMAP = "Any fixed colourmap";

View file

@ -700,6 +700,8 @@ OptionMenu "VideoOptions"
Option "$DSPLYMNU_NOMONSTERINTERPOLATION", "nomonsterinterpolation", "NoYes"
Slider "$DSPLYMNU_MENUDIM", "dimamount", 0, 1.0, 0.05, 2
ColorPicker "$DSPLYMNU_DIMCOLOR", "dimcolor"
Slider "$DSPLYMNU_MOVEBOB", "movebob", 0, 1.0, 0.05, 2
Slider "$DSPLYMNU_STILLBOB", "stillbob", 0, 1.0, 0.05, 2
}
//-------------------------------------------------------------------------------------------