diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index e4acc75a6..f79924b2b 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -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 &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 &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); } diff --git a/src/d_player.h b/src/d_player.h index 40178dac1..48649de7a 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -380,6 +380,7 @@ class player_t { public: player_t(); + ~player_t(); player_t &operator= (const player_t &p); void Serialize (FArchive &arc); @@ -435,6 +436,7 @@ public: AWeapon *ReadyWeapon; AWeapon *PendingWeapon; // WP_NOCHANGE if not changing + TObjPtr psprites; // view sprites (gun, etc) int cheats; // bit flags int timefreezer; // Player has an active time freezer @@ -454,7 +456,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 @@ -526,6 +527,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. diff --git a/src/dsectoreffect.cpp b/src/dsectoreffect.cpp index 180aa9e81..d33eeb061 100644 --- a/src/dsectoreffect.cpp +++ b/src/dsectoreffect.cpp @@ -126,11 +126,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) diff --git a/src/dsectoreffect.h b/src/dsectoreffect.h index 3a564afc4..792771fb6 100644 --- a/src/dsectoreffect.h +++ b/src/dsectoreffect.h @@ -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 (); }; diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 21119f8a0..3842c7279 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -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_WEAPON()) { 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 (); @@ -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_WEAPON()) { 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_WEAPON()) { 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_WEAPON()) { 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) { @@ -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 : 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); } } diff --git a/src/g_game.cpp b/src/g_game.cpp index 7c31e09c0..3c9d274c8 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1750,6 +1750,8 @@ void G_DoPlayerPop(int playernum) players[playernum].mo = NULL; players[playernum].camera = NULL; } + + players[playernum].DestroyPSprites(); } void G_ScreenShot (char *filename) diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp index 3251e3812..b70e4ff08 100644 --- a/src/g_heretic/a_chicken.cpp +++ b/src/g_heretic/a_chicken.cpp @@ -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; } diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 504321061..d20146339 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -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 (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; diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index d936e8d1d..de4e1d75f 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -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 diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index c83726b44..f47ad6a9d 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -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); } } } diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index c8f3aa19f..3624ed625 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -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; diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp index b53442c14..ea767dccd 100644 --- a/src/g_hexen/a_pig.cpp +++ b/src/g_hexen/a_pig.cpp @@ -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; diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 305260ebf..786e49695 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1110,17 +1110,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)) @@ -1132,7 +1132,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()); } } @@ -1295,29 +1295,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)) @@ -1328,13 +1341,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; @@ -1343,17 +1354,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); } } } @@ -1363,11 +1374,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); } } @@ -1375,10 +1392,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)); } } diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 9ed285ca5..2a52756ab 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -182,6 +182,7 @@ protected: void EndEffect (); void PositionAccuracy (); void Travelled (); + void AttachToOwner(AActor *other); bool HandlePickup(AInventory *item); }; diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index adb010d0c..e7ebfc77b 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -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()); } //=========================================================================== diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 854cb4106..a09c49303 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -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; diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 097965e34..a64c5bae9 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -350,11 +350,10 @@ 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; + P_SetPsprite(self->player, PSP_STRIFEHANDS, self->FindState("FireHands")); + self->player->ReadyWeapon = nullptr; self->player->PendingWeapon = WP_NOCHANGE; self->player->playerstate = PST_LIVE; self->player->extralight = 3; @@ -376,12 +375,13 @@ 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); + psp->SetState(psp->GetState() + (self->FindState("FireHandsLower") - self->FindState("FireHands"))); } return 0; } @@ -390,13 +390,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--; } diff --git a/src/g_strife/a_strifeweapons.cpp b/src/g_strife/a_strifeweapons.cpp index 96d53d431..f81ca79f7 100644 --- a/src/g_strife/a_strifeweapons.cpp +++ b/src/g_strife/a_strifeweapons.cpp @@ -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(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(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(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; } diff --git a/src/info.cpp b/src/info.cpp index 49f139ebe..7198a5de4 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -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. diff --git a/src/info.h b/src/info.h index 6d3de5015..6ced755a3 100644 --- a/src/info.h +++ b/src/info.h @@ -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) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index ff9e2ac9a..6b2f4f595 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -314,7 +314,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))) { @@ -343,9 +343,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) @@ -932,10 +932,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; } } diff --git a/src/p_doors.cpp b/src/p_doors.cpp index b122768bb..d6a5f3a44 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -526,7 +526,7 @@ DAnimatedDoor::DAnimatedDoor () } DAnimatedDoor::DAnimatedDoor (sector_t *sec) - : DMovingCeiling (sec) + : DMovingCeiling (sec, false) { } diff --git a/src/p_local.h b/src/p_local.h index f7862d45f..0acbdc35f 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -76,7 +76,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); @@ -334,6 +333,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); diff --git a/src/p_map.cpp b/src/p_map.cpp index 69d18ce18..cf7655917 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4610,6 +4610,8 @@ struct RailData bool ThruSpecies; bool MThruSpecies; bool ThruActors; + int limit; + int count; }; static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata) @@ -4664,7 +4666,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; } //========================================================================== @@ -4706,7 +4712,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; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 21455207b..be875b951 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -556,7 +556,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) @@ -997,12 +998,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; } } @@ -3868,7 +3867,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) { diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index fad782b41..d91b7ab00 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -93,25 +93,165 @@ static const FGenericButtons ButtonChecks[] = // CODE -------------------------------------------------------------------- +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +IMPLEMENT_POINTY_CLASS(DPSprite) + DECLARE_POINTER(Caller) + DECLARE_POINTER(Next) +END_POINTERS + +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +DPSprite::DPSprite(player_t *owner, AActor *caller, int id) +: processPending(true), + firstTic(true), + x(.0), y(.0), + oldx(.0), oldy(.0), + Flags(0), ID(id), + Caller(caller), + Owner(owner) +{ + DPSprite *prev = nullptr; + DPSprite *next = Owner->psprites; + while (next != nullptr && next->ID < ID) + { + prev = next; + next = next->Next; + } + Next = next; + GC::WriteBarrier(this, next); + if (prev == nullptr) + { + Owner->psprites = this; + GC::WriteBarrier(this); + } + else + { + prev->Next = this; + GC::WriteBarrier(prev, this); + } + + if (Next && Next->ID == ID && ID != 0) + Next->Destroy(); // Replace it. + + if (Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) || Caller->IsKindOf(RUNTIME_CLASS(APlayerPawn))) + Flags = (PSPF_ADDWEAPON|PSPF_ADDBOB|PSPF_POWDOUBLE|PSPF_CVARFAST); +} + +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +DPSprite *player_t::FindPSprite(int layer) +{ + if (layer == 0) + return nullptr; + + DPSprite *pspr = psprites; + while (pspr) + { + if (pspr->ID == layer) + break; + + pspr = pspr->Next; + } + + return pspr; +} + +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending) +{ + if (player == nullptr) return; + player->GetPSprite(id)->SetState(state, pending); +} + +DPSprite *player_t::GetPSprite(PSPLayers layer) +{ + AActor *oldcaller = nullptr; + AActor *newcaller = nullptr; + + if (layer >= PSP_TARGETCENTER) + { + if (mo != nullptr) + { + newcaller = mo->FindInventory(RUNTIME_CLASS(APowerTargeter), true); + } + } + else if (layer == PSP_STRIFEHANDS) + { + newcaller = mo; + } + else + { + newcaller = ReadyWeapon; + } + + assert(newcaller != nullptr); + + DPSprite *pspr = FindPSprite(layer); + if (pspr == nullptr) + { + pspr = new DPSprite(this, newcaller, layer); + } + else + { + oldcaller = pspr->Caller; + } + + // Always update the caller here in case we switched weapon + // or if the layer was being used by an inventory item before. + pspr->Caller = newcaller; + + if (newcaller != oldcaller) + { // Only change the flags if this layer was created now or if we updated the caller. + if (layer >= PSP_TARGETCENTER) + { // The targeter layers were affected by those. + pspr->Flags |= (PSPF_CVARFAST|PSPF_POWDOUBLE); + } + } + + return pspr; +} + //--------------------------------------------------------------------------- // // PROC P_NewPspriteTick // //--------------------------------------------------------------------------- -void P_NewPspriteTick() +void DPSprite::NewTick() { // This function should be called after the beginning of a tick, before any possible // prprite-event, or near the end, after any possible psprite event. // Because data is reset for every tick (which it must be) this has no impact on savegames. - for (int i = 0; iprocessPending = true; + pspr->oldx = pspr->x; + pspr->oldy = pspr->y; + + pspr = pspr->Next; } } } @@ -123,79 +263,90 @@ void P_NewPspriteTick() // //--------------------------------------------------------------------------- -void P_SetPsprite (player_t *player, int position, FState *state, bool nofunction) +void DPSprite::SetState(FState *newstate, bool pending) { - pspdef_t *psp; - - if (position == ps_weapon && !nofunction) + if (ID == PSP_WEAPON) { // A_WeaponReady will re-set these as needed - player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK | + Owner->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK | WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK); } - psp = &player->psprites[position]; - psp->processPending = false; // Do not subsequently perform periodic processing within the same tick. + processPending = pending; do { - if (state == NULL) + if (newstate == nullptr) { // Object removed itself. - psp->state = NULL; - break; + Destroy(); + return; } - psp->state = state; + State = newstate; - if (state->sprite != SPR_FIXED) + if (newstate->sprite != SPR_FIXED) { // okay to change sprite and/or frame - if (!state->GetSameFrame()) + if (!newstate->GetSameFrame()) { // okay to change frame - psp->frame = state->GetFrame(); + Frame = newstate->GetFrame(); } - if (state->sprite != SPR_NOCHANGE) + if (newstate->sprite != SPR_NOCHANGE) { // okay to change sprite - psp->sprite = state->sprite; + Sprite = newstate->sprite; } } + Tics = newstate->GetTics(); // could be 0 - if (sv_fastweapons == 2 && position == ps_weapon) - psp->tics = state->ActionFunc == NULL ? 0 : 1; - else if (sv_fastweapons == 3) - psp->tics = (state->GetTics() != 0); - else if (sv_fastweapons) - psp->tics = 1; // great for producing decals :) - else - psp->tics = state->GetTics(); // could be 0 - - if (state->GetMisc1()) - { // Set coordinates. - psp->sx = state->GetMisc1(); - } - if (state->GetMisc2()) + if (Flags & PSPF_CVARFAST) { - psp->sy = state->GetMisc2(); + if (sv_fastweapons == 2 && ID == PSP_WEAPON) + Tics = newstate->ActionFunc == nullptr ? 0 : 1; + else if (sv_fastweapons == 3) + Tics = (newstate->GetTics() != 0); + else if (sv_fastweapons) + Tics = 1; // great for producing decals :) } - if (!nofunction && player->mo != NULL) - { - FState *newstate; - if (state->CallAction(player->mo, player->ReadyWeapon, &newstate)) + if (ID != PSP_FLASH) + { // It's still possible to set the flash layer's offsets with the action function. + if (newstate->GetMisc1()) + { // Set coordinates. + x = newstate->GetMisc1(); + } + if (newstate->GetMisc2()) { - if (newstate != NULL) + y = newstate->GetMisc2(); + } + } + + if (Owner->mo != nullptr) + { + FState *nextstate; + FStateParamInfo stp = { newstate, STATE_Psprite, ID }; + if (newstate->CallAction(Owner->mo, Caller, &stp, &nextstate)) + { + // It's possible this call resulted in this very layer being replaced. + if (ObjectFlags & OF_EuthanizeMe) { - state = newstate; - psp->tics = 0; + return; + } + if (nextstate != nullptr) + { + newstate = nextstate; + Tics = 0; continue; } - if (psp->state == NULL) + if (State == nullptr) { - break; + Destroy(); + return; } } } - state = psp->state->GetNextState(); - } while (!psp->tics); // An initial state of 0 could cycle through. + newstate = State->GetNextState(); + } while (!Tics); // An initial state of 0 could cycle through. + + return; } //--------------------------------------------------------------------------- @@ -209,15 +360,14 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio void P_BringUpWeapon (player_t *player) { - FState *newstate; AWeapon *weapon; if (player->PendingWeapon == WP_NOCHANGE) { - if (player->ReadyWeapon != NULL) + if (player->ReadyWeapon != nullptr) { - 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; } @@ -226,7 +376,7 @@ void P_BringUpWeapon (player_t *player) // If the player has a tome of power, use this weapon's powered up // version, if one is available. - if (weapon != NULL && + if (weapon != nullptr && weapon->SisterWeapon && weapon->SisterWeapon->WeaponFlags & WIF_POWERED_UP && player->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true)) @@ -234,30 +384,26 @@ void P_BringUpWeapon (player_t *player) weapon = weapon->SisterWeapon; } - if (weapon != NULL) + player->PendingWeapon = WP_NOCHANGE; + player->ReadyWeapon = weapon; + player->mo->weaponspecial = 0; + + if (weapon != nullptr) { if (weapon->UpSound) { S_Sound (player->mo, CHAN_WEAPON, weapon->UpSound, 1, ATTN_NORM); } - newstate = weapon->GetUpState (); player->refire = 0; - } - else - { - newstate = NULL; - } - player->PendingWeapon = WP_NOCHANGE; - player->ReadyWeapon = weapon; - player->psprites[ps_weapon].sy = player->cheats & CF_INSTANTWEAPSWITCH - ? WEAPONTOP : WEAPONBOTTOM; - // make sure that the previous weapon's flash state is terminated. - // When coming here from a weapon drop it may still be active. - P_SetPsprite(player, ps_flash, NULL); - P_SetPsprite (player, ps_weapon, newstate); - player->mo->weaponspecial = 0; -} + player->GetPSprite(PSP_WEAPON)->y = player->cheats & CF_INSTANTWEAPSWITCH + ? WEAPONTOP : WEAPONBOTTOM; + // make sure that the previous weapon's flash state is terminated. + // When coming here from a weapon drop it may still be active. + P_SetPsprite(player, PSP_FLASH, nullptr); + P_SetPsprite(player, PSP_WEAPON, weapon->GetUpState()); + } +} //--------------------------------------------------------------------------- // @@ -271,24 +417,24 @@ void P_FireWeapon (player_t *player, FState *state) // [SO] 9/2/02: People were able to do an awful lot of damage // when they were observers... - if (player->Bot == NULL && bot_observer) + if (player->Bot == nullptr && bot_observer) { return; } weapon = player->ReadyWeapon; - if (weapon == NULL || !weapon->CheckAmmo (AWeapon::PrimaryFire, true)) + if (weapon == nullptr || !weapon->CheckAmmo (AWeapon::PrimaryFire, true)) { return; } player->mo->PlayAttacking (); weapon->bAltFire = false; - if (state == NULL) + if (state == nullptr) { state = weapon->GetAtkState(!!player->refire); } - P_SetPsprite (player, ps_weapon, state); + P_SetPsprite(player, PSP_WEAPON, state); if (!(weapon->WeaponFlags & WIF_NOALERT)) { P_NoiseAlert (player->mo, player->mo, false); @@ -307,13 +453,13 @@ void P_FireWeaponAlt (player_t *player, FState *state) // [SO] 9/2/02: People were able to do an awful lot of damage // when they were observers... - if (player->Bot == NULL && bot_observer) + if (player->Bot == nullptr && bot_observer) { return; } weapon = player->ReadyWeapon; - if (weapon == NULL || weapon->FindState(NAME_AltFire) == NULL || !weapon->CheckAmmo (AWeapon::AltFire, true)) + if (weapon == nullptr || weapon->FindState(NAME_AltFire) == nullptr || !weapon->CheckAmmo (AWeapon::AltFire, true)) { return; } @@ -321,12 +467,12 @@ void P_FireWeaponAlt (player_t *player, FState *state) player->mo->PlayAttacking (); weapon->bAltFire = true; - if (state == NULL) + if (state == nullptr) { state = weapon->GetAltAtkState(!!player->refire); } - P_SetPsprite (player, ps_weapon, state); + P_SetPsprite(player, PSP_WEAPON, state); if (!(weapon->WeaponFlags & WIF_NOALERT)) { P_NoiseAlert (player->mo, player->mo, false); @@ -343,15 +489,15 @@ void P_FireWeaponAlt (player_t *player, FState *state) void P_DropWeapon (player_t *player) { - if (player == NULL) + if (player == nullptr) { return; } // Since the weapon is dropping, stop blocking switching. player->WeaponState &= ~WF_DISABLESWITCH; - if (player->ReadyWeapon != NULL) + if (player->ReadyWeapon != nullptr) { - P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetDownState()); + P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetDownState()); } } @@ -367,7 +513,7 @@ 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) { static float curbob; double xx[2], yy[2]; @@ -377,7 +523,7 @@ void P_BobWeapon (player_t *player, pspdef_t *psp, float *x, float *y, double ti weapon = player->ReadyWeapon; - if (weapon == NULL || weapon->WeaponFlags & WIF_DONTBOB) + if (weapon == nullptr || weapon->WeaponFlags & WIF_DONTBOB) { *x = *y = 0; return; @@ -528,7 +674,7 @@ void DoReadyWeaponToFire (AActor *self, bool prim, bool alt) } // Play ready sound, if any. - if (weapon->ReadySound && player->psprites[ps_weapon].state == weapon->FindState(NAME_Ready)) + if (weapon->ReadySound && player->GetPSprite(PSP_WEAPON)->GetState() == weapon->FindState(NAME_Ready)) { if (!(weapon->WeaponFlags & WIF_READYSNDHALF) || pr_wpnreadysnd() < 128) { @@ -547,8 +693,8 @@ void DoReadyWeaponToBob (AActor *self) { // Prepare for bobbing action. self->player->WeaponState |= WF_WEAPONBOBBING; - self->player->psprites[ps_weapon].sx = 0; - self->player->psprites[ps_weapon].sy = WEAPONTOP; + self->player->GetPSprite(PSP_WEAPON)->x = 0; + self->player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP; } } @@ -673,12 +819,12 @@ void P_CheckWeaponSwitch (player_t *player) static void P_CheckWeaponButtons (player_t *player) { - if (player->Bot == NULL && bot_observer) + if (player->Bot == nullptr && bot_observer) { return; } AWeapon *weapon = player->ReadyWeapon; - if (weapon == NULL) + if (weapon == nullptr) { return; } @@ -693,11 +839,11 @@ static void P_CheckWeaponButtons (player_t *player) // [XA] don't change state if still null, so if the modder // sets WRF_xxx to true but forgets to define the corresponding // state, the weapon won't disappear. ;) - if (state != NULL) + if (state != nullptr) { - P_SetPsprite(player, ps_weapon, state); + P_SetPsprite(player, PSP_WEAPON, state); return; - } + } } } } @@ -785,7 +931,7 @@ DEFINE_ACTION_FUNCTION(AInventory, A_CheckReload) //--------------------------------------------------------------------------- // -// PROC A_WeaponOffset +// PROC A_OverlayOffset // //--------------------------------------------------------------------------- enum WOFFlags @@ -795,48 +941,95 @@ enum WOFFlags WOF_ADD = 1 << 2, }; -DEFINE_ACTION_FUNCTION(AInventory, A_WeaponOffset) +void A_OverlayOffset(AActor *self, int layer, double wx, double wy, int flags) { - PARAM_ACTION_PROLOGUE; - PARAM_FLOAT_OPT(wx) { wx = 0.; } - PARAM_FLOAT_OPT(wy) { wy = 32.; } - PARAM_INT_OPT(flags) { flags = 0; } - if ((flags & WOF_KEEPX) && (flags & WOF_KEEPY)) { - return 0; + return; } player_t *player = self->player; - pspdef_t *psp; + DPSprite *psp; if (player && (player->playerstate != PST_DEAD)) { - psp = &player->psprites[ps_weapon]; + psp = player->FindPSprite(layer); + + if (psp == nullptr) + return; + if (!(flags & WOF_KEEPX)) { if (flags & WOF_ADD) { - psp->sx += wx; + psp->x += wx; } else { - psp->sx = wx; + psp->x = wx; } } if (!(flags & WOF_KEEPY)) { if (flags & WOF_ADD) { - psp->sy += wy; + psp->y += wy; } else { - psp->sy = wy; + psp->y = wy; } } } - +} + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayOffset) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(layer) { layer = PSP_WEAPON; } + PARAM_FLOAT_OPT(wx) { wx = 0.; } + PARAM_FLOAT_OPT(wy) { wy = 32.; } + PARAM_INT_OPT(flags) { flags = 0; } + A_OverlayOffset(self, layer, wx, wy, flags); + return 0; +} + +DEFINE_ACTION_FUNCTION(AActor, A_WeaponOffset) +{ + PARAM_ACTION_PROLOGUE; + PARAM_FLOAT_OPT(wx) { wx = 0.; } + PARAM_FLOAT_OPT(wy) { wy = 32.; } + PARAM_INT_OPT(flags) { flags = 0; } + A_OverlayOffset(self, PSP_WEAPON, wx, wy, flags); + return 0; +} + +//--------------------------------------------------------------------------- +// +// PROC A_OverlayFlags +// +//--------------------------------------------------------------------------- + +DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT(layer); + PARAM_INT(flags); + PARAM_BOOL(set); + + if (self->player == nullptr) + return 0; + + DPSprite *pspr = self->player->FindPSprite(layer); + + if (pspr == nullptr) + return 0; + + if (set) + pspr->Flags |= flags; + else + pspr->Flags &= ~flags; + return 0; } @@ -851,35 +1044,40 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Lower) PARAM_ACTION_PROLOGUE; player_t *player = self->player; - pspdef_t *psp; + DPSprite *psp; - if (NULL == player) + if (nullptr == player) { return 0; } - psp = &player->psprites[ps_weapon]; + if (nullptr == player->ReadyWeapon) + { + P_BringUpWeapon(player); + return 0; + } + psp = player->GetPSprite(PSP_WEAPON); if (player->morphTics || player->cheats & CF_INSTANTWEAPSWITCH) { - psp->sy = WEAPONBOTTOM; + psp->y = WEAPONBOTTOM; } else { - psp->sy += LOWERSPEED; + psp->y += LOWERSPEED; } - if (psp->sy < WEAPONBOTTOM) + if (psp->y < WEAPONBOTTOM) { // Not lowered all the way yet return 0; } if (player->playerstate == PST_DEAD) { // Player is dead, so don't bring up a pending weapon - psp->sy = WEAPONBOTTOM; + psp->y = WEAPONBOTTOM; // Player is dead, so keep the weapon off screen - P_SetPsprite (player, ps_weapon, NULL); + psp->SetState(nullptr); return 0; } // [RH] Clear the flash state. Only needed for Strife. - P_SetPsprite (player, ps_flash, NULL); + P_SetPsprite(player, PSP_FLASH, nullptr); P_BringUpWeapon (player); return 0; } @@ -894,14 +1092,14 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Raise) { PARAM_ACTION_PROLOGUE; - if (self == NULL) + if (self == nullptr) { return 0; } player_t *player = self->player; - pspdef_t *psp; + DPSprite *psp; - if (NULL == player) + if (nullptr == player) { return 0; } @@ -910,26 +1108,43 @@ DEFINE_ACTION_FUNCTION(AInventory, A_Raise) P_DropWeapon(player); return 0; } - psp = &player->psprites[ps_weapon]; - psp->sy -= RAISESPEED; - if (psp->sy > WEAPONTOP) + if (player->ReadyWeapon == nullptr) + { + return 0; + } + psp = player->GetPSprite(PSP_WEAPON); + psp->y -= RAISESPEED; + if (psp->y > WEAPONTOP) { // Not raised all the way yet return 0; } - psp->sy = WEAPONTOP; - if (player->ReadyWeapon != NULL) - { - P_SetPsprite (player, ps_weapon, player->ReadyWeapon->GetReadyState()); - } - else - { - player->psprites[ps_weapon].state = NULL; - } + psp->y = WEAPONTOP; + psp->SetState(player->ReadyWeapon->GetReadyState()); return 0; } +//--------------------------------------------------------------------------- +// +// PROC A_Overlay +// +//--------------------------------------------------------------------------- +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Overlay) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT (layer); + PARAM_STATE_OPT (state) { state = nullptr; } + player_t *player = self->player; + + if (player == nullptr) + return 0; + + DPSprite *pspr; + pspr = new DPSprite(player, stateowner, layer); + pspr->SetState(state); + return 0; +} // // A_GunFlash @@ -942,12 +1157,12 @@ enum GF_Flags DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_GunFlash) { PARAM_ACTION_PROLOGUE; - PARAM_STATE_OPT(flash) { flash = NULL; } + PARAM_STATE_OPT(flash) { flash = nullptr; } PARAM_INT_OPT (flags) { flags = 0; } player_t *player = self->player; - if (NULL == player) + if (nullptr == player) { return 0; } @@ -955,18 +1170,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_GunFlash) { player->mo->PlayAttacking2 (); } - if (flash == NULL) + if (flash == nullptr) { if (player->ReadyWeapon->bAltFire) { flash = player->ReadyWeapon->FindState(NAME_AltFlash); } - if (flash == NULL) + if (flash == nullptr) { flash = player->ReadyWeapon->FindState(NAME_Flash); } } - P_SetPsprite (player, ps_flash, flash); + P_SetPsprite(player, PSP_FLASH, flash); return 0; } @@ -1084,13 +1299,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_Light) void P_SetupPsprites(player_t *player, bool startweaponup) { - int i; - // Remove all psprites - for (i = 0; i < NUMPSPRITES; i++) - { - player->psprites[i].state = NULL; - } + player->DestroyPSprites(); + // Spawn the ready weapon player->PendingWeapon = !startweaponup ? player->ReadyWeapon : WP_NOCHANGE; P_BringUpWeapon (player); @@ -1104,61 +1315,162 @@ void P_SetupPsprites(player_t *player, bool startweaponup) // //------------------------------------------------------------------------ -void P_MovePsprites (player_t *player) +void player_t::TickPSprites() { - int i; - pspdef_t *psp; - FState *state; - - // [RH] If you don't have a weapon, then the psprites should be NULL. - if (player->ReadyWeapon == NULL && (player->health > 0 || player->mo->DamageType != NAME_Fire)) + DPSprite *pspr = psprites; + while (pspr) { - P_SetPsprite (player, ps_weapon, NULL); - P_SetPsprite (player, ps_flash, NULL); - if (player->PendingWeapon != WP_NOCHANGE) + // Destroy the psprite if it's from a weapon that isn't currently selected by the player + // or if it's from an inventory item that the player no longer owns. + if ((pspr->Caller == nullptr || + (pspr->Caller->IsKindOf(RUNTIME_CLASS(AInventory)) && barrier_cast(pspr->Caller)->Owner != pspr->Owner->mo) || + (pspr->Caller->IsKindOf(RUNTIME_CLASS(AWeapon)) && pspr->Caller != pspr->Owner->ReadyWeapon))) { - P_BringUpWeapon (player); + pspr->Destroy(); } + else + { + pspr->Tick(); + } + + pspr = pspr->Next; + } + + if (ReadyWeapon == nullptr && (health > 0 || mo->DamageType != NAME_Fire)) + { + if (PendingWeapon != WP_NOCHANGE) + P_BringUpWeapon(this); } else { - psp = &player->psprites[0]; - for (i = 0; i < NUMPSPRITES; i++, psp++) + P_CheckWeaponSwitch(this); + if (WeaponState & (WF_WEAPONREADY | WF_WEAPONREADYALT)) { - if ((state = psp->state) != NULL && psp->processPending) // a null state means not active + P_CheckWeaponFire(this); + } + // Check custom buttons + P_CheckWeaponButtons(this); + } +} + +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +void DPSprite::Tick() +{ + if (processPending) + { + // drop tic count and possibly change state + if (Tics != -1) // a -1 tic count never changes + { + Tics--; + + // [BC] Apply double firing speed. + if ((Flags & PSPF_POWDOUBLE) && Tics && (Owner->cheats & CF_DOUBLEFIRINGSPEED)) + Tics--; + + if (!Tics) + SetState(State->GetNextState()); + } + } +} + +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +void DPSprite::Serialize(FArchive &arc) +{ + Super::Serialize(arc); + + arc << Next << Caller << Owner << Flags + << State << Tics << Sprite << Frame + << ID << x << y << oldx << oldy; +} + +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +void player_t::DestroyPSprites() +{ + DPSprite *pspr = psprites; + psprites = nullptr; + while (pspr) + { + DPSprite *next = pspr->Next; + pspr->Next = nullptr; + pspr->Destroy(); + pspr = next; + } +} + +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +void DPSprite::Destroy() +{ + // Do not crash if this gets called on partially initialized objects. + if (Owner != nullptr && Owner->psprites != nullptr) + { + if (Owner->psprites != this) + { + DPSprite *prev = Owner->psprites; + while (prev != nullptr && prev->Next != this) + prev = prev->Next; + + if (prev != nullptr && prev->Next == this) { - // drop tic count and possibly change state - if (psp->tics != -1) // a -1 tic count never changes - { - psp->tics--; - - // [BC] Apply double firing speed. - if ( psp->tics && (player->cheats & CF_DOUBLEFIRINGSPEED)) - psp->tics--; - - if(!psp->tics) - { - P_SetPsprite (player, i, psp->state->GetNextState()); - } - } + prev->Next = Next; + GC::WriteBarrier(prev, Next); } } - player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx; - player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy; - P_CheckWeaponSwitch (player); - if (player->WeaponState & (WF_WEAPONREADY | WF_WEAPONREADYALT)) + else { - P_CheckWeaponFire (player); - } - - // Check custom buttons - P_CheckWeaponButtons(player); + Owner->psprites = Next; + GC::WriteBarrier(Next); } + } + Super::Destroy(); } -FArchive &operator<< (FArchive &arc, pspdef_t &def) +//------------------------------------------------------------------------ +// +// +// +//------------------------------------------------------------------------ + +ADD_STAT(psprites) { - arc << def.state << def.tics << def.sx << def.sy - << def.sprite << def.frame; - return arc; + FString out; + DPSprite *pspr; + for (int i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + out.AppendFormat("[psprites] player: %d | layers: ", i); + + pspr = players[i].psprites; + while (pspr) + { + out.AppendFormat("%d, ", pspr->GetID()); + + pspr = pspr->GetNext(); + } + + out.AppendFormat("\n"); + } + + return out; } diff --git a/src/p_pspr.h b/src/p_pspr.h index 397ac4fff..2c7a36518 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -34,59 +34,82 @@ // 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; } + 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 Caller; + TObjPtr 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); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index e64a97fca..2b812bd96 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -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; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index cdb180e60..cec39b93a 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3329,14 +3329,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(); } } diff --git a/src/p_tick.cpp b/src/p_tick.cpp index f0f1e2ea8..978c2c7ef 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -87,7 +87,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) diff --git a/src/p_trace.cpp b/src/p_trace.cpp index 67a516f9c..16fff3fbe 100644 --- a/src/p_trace.cpp +++ b/src/p_trace.cpp @@ -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. diff --git a/src/p_user.cpp b/src/p_user.cpp index 486044070..e4b6ec6bd 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -270,6 +270,7 @@ player_t::player_t() WeaponState(0), ReadyWeapon(0), PendingWeapon(0), + psprites(0), cheats(0), timefreezer(0), refire(0), @@ -315,7 +316,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) @@ -371,7 +376,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; @@ -433,6 +438,7 @@ size_t player_t::FixPointers (const DObject *old, DObject *rep) if (ReadyWeapon == old) ReadyWeapon = static_cast(rep), changed++; if (PendingWeapon == old) PendingWeapon = static_cast(rep), changed++; if (*&PremorphWeapon == old) PremorphWeapon = static_cast(rep), changed++; + if (psprites == old) psprites = static_cast(rep), changed++; if (*&ConversationNPC == old) ConversationNPC = replacement, changed++; if (*&ConversationPC == old) ConversationPC = replacement, changed++; if (*&MUSINFOactor == old) MUSINFOactor = replacement, changed++; @@ -451,6 +457,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); @@ -1370,34 +1377,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(player->mo->FindInventory (morphweapon)); - if (player->ReadyWeapon == NULL) + if (player->ReadyWeapon == nullptr) { player->ReadyWeapon = static_cast(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; } @@ -2114,7 +2124,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))) @@ -2634,7 +2644,7 @@ void P_PlayerThink (player_t *player) } } // Cycle psprites - P_MovePsprites (player); + player->TickPSprites(); // Other Counters if (player->damagecount) @@ -3064,8 +3074,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; diff --git a/src/r_things.cpp b/src/r_things.cpp index 836f58690..612dfdd45 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -93,6 +93,7 @@ extern double globaluclip, globaldclip; extern float MaskedScaleY; #define MINZ double((2048*4) / double(1 << 20)) +#define BASEXCENTER (160) #define BASEYCENTER (100) EXTERN_CVAR (Bool, st_scale) @@ -112,9 +113,15 @@ double pspriteyscale; fixed_t sky1scale; // [RH] Sky 1 scale factor fixed_t sky2scale; // [RH] Sky 2 scale factor -vissprite_t *VisPSprites[NUMPSPRITES]; -int VisPSpritesX1[NUMPSPRITES]; -FDynamicColormap *VisPSpritesBaseColormap[NUMPSPRITES]; +// Used to store a psprite's drawing information if it needs to be drawn later. +struct vispsp_t +{ + vissprite_t *vis; + FDynamicColormap *basecolormap; + int x1; +}; +TArray vispsprites; +unsigned int vispspindex; static int spriteshade; @@ -1271,48 +1278,41 @@ void R_AddSprites (sector_t *sec, int lightlevel, int fakeside) } } - // // R_DrawPSprite // -void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double sy) +void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac) { double tx; int x1; int x2; + double sx, sy; spritedef_t* sprdef; spriteframe_t* sprframe; FTextureID picnum; WORD flip; FTexture* tex; vissprite_t* vis; - static vissprite_t avis[NUMPSPRITES + 1]; - static vissprite_t *avisp[countof(avis)]; - bool noaccel; + bool noaccel; + bool isweapon; + static TArray avis; - assert(pspnum >= 0 && pspnum < NUMPSPRITES); - - if (avisp[0] == NULL) - { - for (unsigned i = 0; i < countof(avis); ++i) - { - avisp[i] = &avis[i]; - } - } + if (avis.Size() < vispspindex + 1) + avis.Reserve(avis.Size() - vispspindex + 1); // decide which patch to use - if ( (unsigned)psp->sprite >= (unsigned)sprites.Size ()) + if ((unsigned)pspr->GetSprite() >= (unsigned)sprites.Size()) { - DPrintf ("R_DrawPSprite: invalid sprite number %i\n", psp->sprite); + DPrintf("R_DrawPSprite: invalid sprite number %i\n", pspr->GetSprite()); return; } - sprdef = &sprites[psp->sprite]; - if (psp->frame >= sprdef->numframes) + sprdef = &sprites[pspr->GetSprite()]; + if (pspr->GetFrame() >= sprdef->numframes) { - DPrintf ("R_DrawPSprite: invalid sprite frame %i : %i\n", psp->sprite, psp->frame); + DPrintf("R_DrawPSprite: invalid sprite frame %i : %i\n", pspr->GetSprite(), pspr->GetFrame()); return; } - sprframe = &SpriteFrames[sprdef->spriteframes + psp->frame]; + sprframe = &SpriteFrames[sprdef->spriteframes + pspr->GetFrame()]; picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; @@ -1321,15 +1321,39 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double if (tex->UseType == FTexture::TEX_Null) return; + isweapon = pspr->GetCaller()->IsKindOf(RUNTIME_CLASS(AWeapon)); + + if (pspr->firstTic) + { // Can't interpolate the first tic. + pspr->firstTic = false; + pspr->oldx = pspr->x; + pspr->oldy = pspr->y; + } + + sx = pspr->oldx + (pspr->x - pspr->oldx) * ticfrac; + sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac; + + if (pspr->Flags & PSPF_ADDBOB) + { + sx += bobx; + sy += boby; + } + + if (pspr->Flags & PSPF_ADDWEAPON && pspr->GetID() != PSP_WEAPON) + { + sx += wx; + sy += wy; + } + // calculate edges of the shape - tx = sx - (320 / 2); + tx = sx - BASEXCENTER; tx -= tex->GetScaledLeftOffset(); x1 = xs_RoundToInt(CenterX + tx * pspritexscale); // off the right side if (x1 > viewwidth) - return; + return; tx += tex->GetScaledWidth(); x2 = xs_RoundToInt(CenterX + tx * pspritexscale); @@ -1337,9 +1361,9 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double // off the left side if (x2 <= 0) return; - + // store information in a vissprite - vis = avisp[NUMPSPRITES]; + vis = &avis[vispspindex]; vis->renderflags = owner->renderflags; vis->floorclip = 0; @@ -1347,14 +1371,14 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double if (camera->player && (RenderTarget != screen || viewheight == RenderTarget->GetHeight() || - (RenderTarget->GetWidth() > 320 && !st_scale))) + (RenderTarget->GetWidth() > (BASEXCENTER * 2) && !st_scale))) { // Adjust PSprite for fullscreen views - AWeapon *weapon = NULL; - if (camera->player != NULL) + AWeapon *weapon = nullptr; + if (camera->player != nullptr) { weapon = camera->player->ReadyWeapon; } - if (pspnum <= ps_flash && weapon != NULL && weapon->YAdjust != 0) + if (isweapon && weapon != nullptr && weapon->YAdjust != 0) { if (RenderTarget != screen || viewheight == RenderTarget->GetHeight()) { @@ -1362,11 +1386,11 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double } else { - vis->texturemid -= StatusBar->GetDisplacement () * weapon->YAdjust; + vis->texturemid -= StatusBar->GetDisplacement() * weapon->YAdjust; } } } - if (pspnum <= ps_flash) + if (isweapon) { // Move the weapon down for 1280x1024. vis->texturemid -= BaseRatioSizes[WidescreenRatio][2]; } @@ -1390,11 +1414,11 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double } if (vis->x1 > x1) - vis->startfrac += vis->xiscale*(vis->x1-x1); + vis->startfrac += vis->xiscale*(vis->x1 - x1); noaccel = false; - FDynamicColormap *colormap_to_use = NULL; - if (pspnum <= ps_flash) + FDynamicColormap *colormap_to_use = nullptr; + if (isweapon) { vis->Style.Alpha = float(owner->Alpha); vis->Style.RenderStyle = owner->RenderStyle; @@ -1415,16 +1439,16 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double { if (invertcolormap) { // Fade to white - mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(255,255,255), mybasecolormap->Desaturate); + mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(255, 255, 255), mybasecolormap->Desaturate); invertcolormap = false; } else { // Fade to black - mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(0,0,0), mybasecolormap->Desaturate); + mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(0, 0, 0), mybasecolormap->Desaturate); } } - if (realfixedcolormap != NULL && (!r_swtruecolor || (r_shadercolormaps && screen->Accel2D))) + if (realfixedcolormap != nullptr && (!r_swtruecolor || (r_shadercolormaps && screen->Accel2D))) { // fixed color vis->Style.BaseColormap = realfixedcolormap; vis->Style.ColormapNum = 0; @@ -1440,7 +1464,7 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double vis->Style.BaseColormap = mybasecolormap; vis->Style.ColormapNum = fixedlightlev >> COLORMAPSHIFT; } - else if (!foggy && psp->state->GetFullbright()) + else if (!foggy && pspr->GetState()->GetFullbright()) { // full bright vis->Style.BaseColormap = mybasecolormap; // [RH] use basecolormap vis->Style.ColormapNum = 0; @@ -1451,7 +1475,7 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double vis->Style.ColormapNum = GETPALOOKUP(0, spriteshade); } } - if (camera->Inventory != NULL) + if (camera->Inventory != nullptr) { BYTE oldcolormapnum = vis->Style.ColormapNum; FColormap *oldcolormap = vis->Style.BaseColormap; @@ -1488,7 +1512,7 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double } // If the main colormap has fixed lights, and this sprite is being drawn with that // colormap, disable acceleration so that the lights can remain fixed. - if (!noaccel && realfixedcolormap == NULL && + if (!noaccel && realfixedcolormap == nullptr && NormalLightHasFixedLights && mybasecolormap == &NormalLight && vis->pic->UseBasePalette()) { @@ -1512,18 +1536,19 @@ void R_DrawPSprite (pspdef_t* psp, int pspnum, AActor *owner, double sx, double style.CheckFuzz(); if (style.BlendOp != STYLEOP_Fuzz) { - VisPSpritesX1[pspnum] = x1; - VisPSpritesBaseColormap[pspnum] = colormap_to_use; - VisPSprites[pspnum] = vis; - swapvalues(avisp[pspnum], avisp[NUMPSPRITES]); + if (vispsprites.Size() < vispspindex + 1) + vispsprites.Reserve(vispsprites.Size() - vispspindex + 1); + + vispsprites[vispspindex].vis = vis; + vispsprites[vispspindex].basecolormap = colormap_to_use; + vispsprites[vispspindex].x1 = x1; + vispspindex++; return; } } - R_DrawVisSprite (vis); + R_DrawVisSprite(vis); } - - //========================================================================== // // R_DrawPlayerSprites @@ -1534,7 +1559,8 @@ void R_DrawPlayerSprites () { int i; int lightnum; - pspdef_t* psp; + DPSprite* psp; + DPSprite* weapon; sector_t* sec = NULL; static sector_t tempsec; int floorlight, ceilinglight; @@ -1547,28 +1573,35 @@ void R_DrawPlayerSprites () (r_deathcamera && camera->health <= 0)) return; - if(fixedlightlev < 0 && viewsector->e && viewsector->e->XFloor.lightlist.Size()) { - for(i = viewsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--) - if(ViewPos.Z <= viewsector->e->XFloor.lightlist[i].plane.Zat0()) { + if (fixedlightlev < 0 && viewsector->e && viewsector->e->XFloor.lightlist.Size()) + { + for (i = viewsector->e->XFloor.lightlist.Size() - 1; i >= 0; i--) + { + if (ViewPos.Z <= viewsector->e->XFloor.lightlist[i].plane.Zat0()) + { rover = viewsector->e->XFloor.lightlist[i].caster; - if(rover) { - if(rover->flags & FF_DOUBLESHADOW && ViewPos.Z <= rover->bottom.plane->Zat0()) + if (rover) + { + if (rover->flags & FF_DOUBLESHADOW && ViewPos.Z <= rover->bottom.plane->Zat0()) break; sec = rover->model; - if(rover->flags & FF_FADEWALLS) + if (rover->flags & FF_FADEWALLS) basecolormap = sec->ColorMap; else basecolormap = viewsector->e->XFloor.lightlist[i].extra_colormap; } break; } - if(!sec) { + } + if(!sec) + { sec = viewsector; basecolormap = sec->ColorMap; } floorlight = ceilinglight = sec->lightlevel; - } else { - // This used to use camera->Sector but due to interpolation that can be incorrect + } + else + { // This used to use camera->Sector but due to interpolation that can be incorrect // when the interpolated viewpoint is in a different sector than the camera. sec = R_FakeFlat (viewsector, &tempsec, &floorlight, &ceilinglight, false); @@ -1592,27 +1625,47 @@ void R_DrawPlayerSprites () if (camera->player != NULL) { double centerhack = CenterY; - float ofsx, ofsy; + double wx, wy; + float bobx, boby; CenterY = viewheight / 2; - P_BobWeapon (camera->player, &camera->player->psprites[ps_weapon], &ofsx, &ofsy, r_TicFracF); + 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) + { + if (weapon->firstTic) + { + 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; + } // add all active psprites - for (i = 0, psp = camera->player->psprites; - i < NUMPSPRITES; - i++, psp++) + psp = camera->player->psprites; + while (psp) { // [RH] Don't draw the targeter's crosshair if the player already has a crosshair set. - if (psp->state && (i != ps_targetcenter || CrosshairImage == NULL)) + // It's possible this psprite's caller is now null but the layer itself hasn't been destroyed + // because it didn't tick yet (if we typed 'take all' while in the console for example). + // In this case let's simply not draw it to avoid crashing. + if ((psp->GetID() != PSP_TARGETCENTER || CrosshairImage == nullptr) && psp->GetCaller() != nullptr) { - R_DrawPSprite (psp, i, camera, psp->sx + ofsx, psp->sy + ofsy); - } - // [RH] Don't bob the targeter. - if (i == ps_flash) - { - ofsx = ofsy = 0; + R_DrawPSprite(psp, camera, bobx, boby, wx, wy, r_TicFracF); } + + psp = psp->GetNext(); } CenterY = centerhack; @@ -1630,63 +1683,60 @@ void R_DrawPlayerSprites () void R_DrawRemainingPlayerSprites() { - for (int i = 0; i < NUMPSPRITES; ++i) + for (unsigned int i = 0; i < vispspindex; i++) { vissprite_t *vis; - vis = VisPSprites[i]; - VisPSprites[i] = NULL; + vis = vispsprites[i].vis; + FDynamicColormap *colormap = vispsprites[i].basecolormap; + bool flip = vis->xiscale < 0; + FSpecialColormap *special = NULL; + PalEntry overlay = 0; + FColormapStyle colormapstyle; + bool usecolormapstyle = false; - if (vis != NULL) + if (vis->Style.BaseColormap >= &SpecialColormaps[0] && + vis->Style.BaseColormap < &SpecialColormaps[SpecialColormaps.Size()]) { - FDynamicColormap *colormap = VisPSpritesBaseColormap[i]; - bool flip = vis->xiscale < 0; - FSpecialColormap *special = NULL; - PalEntry overlay = 0; - FColormapStyle colormapstyle; - bool usecolormapstyle = false; - - if (vis->Style.BaseColormap >= &SpecialColormaps[0] && - vis->Style.BaseColormap < &SpecialColormaps[SpecialColormaps.Size()]) - { - special = static_cast(vis->Style.BaseColormap); - } - else if (colormap->Color == PalEntry(255,255,255) && - colormap->Desaturate == 0) - { - overlay = colormap->Fade; - overlay.a = BYTE(vis->Style.ColormapNum * 255 / NUMCOLORMAPS); - } - else - { - usecolormapstyle = true; - colormapstyle.Color = colormap->Color; - colormapstyle.Fade = colormap->Fade; - colormapstyle.Desaturate = colormap->Desaturate; - colormapstyle.FadeLevel = vis->Style.ColormapNum / float(NUMCOLORMAPS); - } - screen->DrawTexture(vis->pic, - viewwindowx + VisPSpritesX1[i], - viewwindowy + viewheight/2 - vis->texturemid * vis->yscale - 0.5, - DTA_DestWidthF, FIXED2DBL(vis->pic->GetWidth() * vis->xscale), - DTA_DestHeightF, vis->pic->GetHeight() * vis->yscale, - DTA_Translation, TranslationToTable(vis->Translation), - DTA_FlipX, flip, - DTA_TopOffset, 0, - DTA_LeftOffset, 0, - DTA_ClipLeft, viewwindowx, - DTA_ClipTop, viewwindowy, - DTA_ClipRight, viewwindowx + viewwidth, - DTA_ClipBottom, viewwindowy + viewheight, - DTA_AlphaF, vis->Style.Alpha, - DTA_RenderStyle, vis->Style.RenderStyle, - DTA_FillColor, vis->FillColor, - DTA_SpecialColormap, special, - DTA_ColorOverlay, overlay.d, - DTA_ColormapStyle, usecolormapstyle ? &colormapstyle : NULL, - TAG_DONE); + special = static_cast(vis->Style.BaseColormap); } + else if (colormap->Color == PalEntry(255,255,255) && + colormap->Desaturate == 0) + { + overlay = colormap->Fade; + overlay.a = BYTE(vis->Style.ColormapNum * 255 / NUMCOLORMAPS); + } + else + { + usecolormapstyle = true; + colormapstyle.Color = colormap->Color; + colormapstyle.Fade = colormap->Fade; + colormapstyle.Desaturate = colormap->Desaturate; + colormapstyle.FadeLevel = vis->Style.ColormapNum / float(NUMCOLORMAPS); + } + screen->DrawTexture(vis->pic, + viewwindowx + vispsprites[i].x1, + viewwindowy + viewheight/2 - vis->texturemid * vis->yscale - 0.5, + DTA_DestWidthF, FIXED2DBL(vis->pic->GetWidth() * vis->xscale), + DTA_DestHeightF, vis->pic->GetHeight() * vis->yscale, + DTA_Translation, TranslationToTable(vis->Translation), + DTA_FlipX, flip, + DTA_TopOffset, 0, + DTA_LeftOffset, 0, + DTA_ClipLeft, viewwindowx, + DTA_ClipTop, viewwindowy, + DTA_ClipRight, viewwindowx + viewwidth, + DTA_ClipBottom, viewwindowy + viewheight, + DTA_AlphaF, vis->Style.Alpha, + DTA_RenderStyle, vis->Style.RenderStyle, + DTA_FillColor, vis->FillColor, + DTA_SpecialColormap, special, + DTA_ColorOverlay, overlay.d, + DTA_ColormapStyle, usecolormapstyle ? &colormapstyle : NULL, + TAG_DONE); } + + vispspindex = 0; } // diff --git a/src/r_things.h b/src/r_things.h index f5cd30e00..04d5487ee 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -132,7 +132,6 @@ void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Sp void R_CacheSprite (spritedef_t *sprite); void R_SortVisSprites (int (*compare)(const void *, const void *), size_t first); void R_AddSprites (sector_t *sec, int lightlevel, int fakeside); -void R_AddPSprites (); void R_DrawSprites (); void R_ClearSprites (); void R_DrawMasked (); diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index d522ad573..21ab33dfb 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -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_WEAPON() (self->player && stateinfo != nullptr && stateinfo->mStateType == STATE_Psprite) +#define ACTION_CALL_FROM_INVENTORY() (stateinfo != nullptr && stateinfo->mStateType == STATE_StateChain) #endif diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 4d88a56fc..77c2fcbd1 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -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"); //========================================================================== // @@ -132,8 +133,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; @@ -1334,6 +1336,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 @@ -1996,6 +2064,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; @@ -2036,6 +2105,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; } @@ -2073,6 +2143,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; @@ -2155,6 +2226,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); @@ -5768,19 +5840,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_WEAPON()) + { + 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; } diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d500458a2..04410189a 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -2916,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 diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 317a69846..52b354028 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -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) diff --git a/src/zscript/zcc_parser.cpp b/src/zscript/zcc_parser.cpp index 2b914d033..1f1fa4541 100644 --- a/src/zscript/zcc_parser.cpp +++ b/src/zscript/zcc_parser.cpp @@ -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(); diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 2ce48b036..8e6f0f338 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -56,7 +56,7 @@ ACTOR Actor native //: Thinker // End of MBF redundant functions. action native A_MonsterRail(); - action native A_BFGSpray(class 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 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(); @@ -190,7 +190,7 @@ ACTOR Actor native //: Thinker native state A_Jump(int chance = 256, state label, ...); native void A_CustomMissile(class 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 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 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 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 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 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); @@ -247,6 +247,7 @@ ACTOR Actor native //: Thinker native void A_Burst(class chunktype); action native A_Blast(int flags = 0, float strength = 255, float radius = 255, float speed = 20, class 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 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 pufftype = "BulletPuff"); action native A_Stop(); action native A_Respawn(int flags = 1); @@ -333,6 +334,11 @@ ACTOR Actor native //: Thinker 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 A_Overlay(int layer, state start = ""); + 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); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index f5072d55e..160646ff0 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -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; @@ -569,4 +576,20 @@ enum WOF_KEEPX = 1, WOF_KEEPY = 1 << 1, WOF_ADD = 1 << 2, -}; \ No newline at end of file +}; + +// 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, +}; diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index f7250117d..a49dfd14c 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -11,7 +11,7 @@ ACTOR Inventory native action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = "", sound MissSound = ""); action native A_FireBullets(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class 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 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 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 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 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: