From 33a4058533c5b8d4ba5377433e5af798c857c20b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 10 Oct 2009 11:37:36 +0000 Subject: [PATCH] Update to ZDoom r1905: - Added Gez's seeker missile submission. - Added Gez's thing activation submission. - added a NULL pointer check to fog spawning in unmorphing code. - fixed: frozen corpses need to be treated as solid by z-movement code. - fixed: AAmbientSound::Serialize was adjusting its timer value for savegames even when it was set to a 'don't check' value. git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@539 b0f79afe-0144-0410-b225-9a4edf0717df --- docs/rh-log.txt | 15 ++ src/actor.h | 29 ++-- src/g_hexen/a_clericholy.cpp | 30 ---- src/g_hexen/a_hexenglobal.h | 1 - src/g_hexen/a_magestaff.cpp | 36 ----- src/g_raven/a_minotaur.cpp | 43 ----- src/g_raven/ravenshared.h | 1 - src/g_shared/a_morph.cpp | 5 +- src/p_interaction.cpp | 14 +- src/p_lnspec.cpp | 32 +++- src/p_lnspec.h | 1 + src/p_map.cpp | 123 ++++++++++---- src/p_mobj.cpp | 77 ++++++--- src/s_advsound.cpp | 31 +++- src/svnrevision.h | 4 +- src/thingdef/thingdef_codeptr.cpp | 14 +- src/thingdef/thingdef_data.cpp | 6 +- src/thingdef/thingdef_parse.cpp | 3 + src/thingdef/thingdef_properties.cpp | 2 +- src/win32/fb_d3d9.cpp | 152 +++++++++++++++--- src/win32/win32iface.h | 4 +- .../shaders/d3d/sm14/GammaCorrection.pso | Bin 0 -> 460 bytes 22 files changed, 398 insertions(+), 225 deletions(-) create mode 100644 wadsrc/static/shaders/d3d/sm14/GammaCorrection.pso diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 17b6e5c2..08263f07 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,18 @@ +October 9, 2009 (Changes by Graf Zahl) +- Added Gez's seeker missile submission. +- Added Gez's thing activation submission. +- added a NULL pointer check to fog spawning in unmorphing code. +- fixed: frozen corpses need to be treated as solid by z-movement code. +- fixed: AAmbientSound::Serialize was adjusting its timer value for savegames + even when it was set to a 'don't check' value. + +October 8, 2009 +- Reinstated the off-by-one check in D3DFB from r399. I thought I could get by + at just fixing it at a specific value, since the supply of SM14 cards isn't + all that diverse and all from ATI, but apparently Radeon 8500s and 9000s + have different precision levels in their pixel shaders. See bug report + + October 8, 2009 (Changes by Graf Zahl) - Added a PainThreshold actor property. - fixed: Teleport_EndGame did not set the end sequence name properly. diff --git a/src/actor.h b/src/actor.h index 5b436ffc..d3908990 100644 --- a/src/actor.h +++ b/src/actor.h @@ -218,7 +218,7 @@ enum MF3_CRASHED = 0x00200000, // Actor entered its crash state MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles) MF3_AVOIDMELEE = 0x00800000, // Avoids melee attacks (same as MBF's monster_backing but must be explicitly set) - /* = 0x01000000, */ + MF3_SCREENSEEKER = 0x01000000, // Fails the IsOkayToAttack test if potential target is outside player FOV MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact MF3_BLOODLESSIMPACT = 0x08000000, // Projectile does not leave blood @@ -432,19 +432,23 @@ enum EBounceFlags }; -// Used to affect the logic for MF5_USESPECIAL and MF6_BUMPSPECIAL +// Used to affect the logic for thing activation through death, USESPECIAL and BUMPSPECIAL // "thing" refers to what has the flag and the special, "trigger" refers to what used or bumped it enum EThingSpecialActivationType { - THINGSPEC_Default = 0, // Normal behavior: a player must be the trigger, and is the activator - THINGSPEC_ThingActs = 1, // The thing itself is the activator of the special - THINGSPEC_ThingTargets = 2, // The thing changes its target to the trigger - THINGSPEC_TriggerTargets = 4, // The trigger changes its target to the thing - THINGSPEC_MonsterTrigger = 8, // The thing can be triggered by a monster - THINGSPEC_MissileTrigger = 16, // The thing can be triggered by a projectile - THINGSPEC_ClearSpecial = 32, // Clears special after successful activation - THINGSPEC_NoDeathSpecial = 64, // Don't activate special on death - THINGSPEC_TriggerActs = 128, // The trigger is the activator of the special (overrides LEVEL_ACTOWNSPECIAL Hexen hack) + THINGSPEC_Default = 0, // Normal behavior: a player must be the trigger, and is the activator + THINGSPEC_ThingActs = 1, // The thing itself is the activator of the special + THINGSPEC_ThingTargets = 1<<1, // The thing changes its target to the trigger + THINGSPEC_TriggerTargets = 1<<2, // The trigger changes its target to the thing + THINGSPEC_MonsterTrigger = 1<<3, // The thing can be triggered by a monster + THINGSPEC_MissileTrigger = 1<<4, // The thing can be triggered by a projectile + THINGSPEC_ClearSpecial = 1<<5, // Clears special after successful activation + THINGSPEC_NoDeathSpecial = 1<<6, // Don't activate special on death + THINGSPEC_TriggerActs = 1<<7, // The trigger is the activator of the special + // (overrides LEVEL_ACTOWNSPECIAL Hexen hack) + THINGSPEC_Activate = 1<<8, // The thing is activated when triggered + THINGSPEC_Deactivate = 1<<9, // The thing is deactivated when triggered + THINGSPEC_Switch = 1<<10, // The thing is alternatively activated and deactivated when triggered }; // [RH] Like msecnode_t, but for the blockmap @@ -605,7 +609,7 @@ public: virtual bool SpecialBlastHandling (AActor *source, fixed_t strength); // Called by RoughBlockCheck - virtual bool IsOkayToAttack (AActor *target); + bool IsOkayToAttack (AActor *target); // Plays the actor's ActiveSound if its voice isn't already making noise. void PlayActiveSound (); @@ -808,6 +812,7 @@ public: fixed_t pushfactor; int lastpush; int activationtype; // How the thing behaves when activated with USESPECIAL or BUMPSPECIAL + int lastbump; // Last time the actor was bumped, used to control BUMPSPECIAL int Score; // manipulated by score items, ACS or DECORATE. The engine doesn't use this itself for anything. FNameNoInit Tag; // Strife's tag name. FIXME: should be case sensitive! diff --git a/src/g_hexen/a_clericholy.cpp b/src/g_hexen/a_clericholy.cpp index 6ad6522c..01d13931 100644 --- a/src/g_hexen/a_clericholy.cpp +++ b/src/g_hexen/a_clericholy.cpp @@ -145,36 +145,6 @@ bool AHolySpirit::SpecialBlastHandling (AActor *source, fixed_t strength) return true; } -bool AHolySpirit::IsOkayToAttack (AActor *link) -{ - if ((link->flags3&MF3_ISMONSTER || - (link->player && link != target)) - && !(link->flags2&MF2_DORMANT)) - { - if (target != NULL && link->IsFriend(target)) - { - return false; - } - if (!(link->flags & MF_SHOOTABLE)) - { - return false; - } - if (multiplayer && !deathmatch && link->player && target != NULL && target->player) - { - return false; - } - if (link == target) - { - return false; - } - else if (P_CheckSight (this, link)) - { - return true; - } - } - return false; -} - //============================================================================ // // A_CHolyAttack2 diff --git a/src/g_hexen/a_hexenglobal.h b/src/g_hexen/a_hexenglobal.h index a942998f..a2082777 100644 --- a/src/g_hexen/a_hexenglobal.h +++ b/src/g_hexen/a_hexenglobal.h @@ -9,7 +9,6 @@ class AHolySpirit : public AActor public: bool Slam (AActor *thing); bool SpecialBlastHandling (AActor *source, fixed_t strength); - bool IsOkayToAttack (AActor *link); }; class AFighterWeapon : public AWeapon diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp index 76610f69..2316edde 100644 --- a/src/g_hexen/a_magestaff.cpp +++ b/src/g_hexen/a_magestaff.cpp @@ -88,7 +88,6 @@ class AMageStaffFX2 : public AActor DECLARE_CLASS(AMageStaffFX2, AActor) public: int SpecialMissileHit (AActor *victim); - bool IsOkayToAttack (AActor *link); bool SpecialBlastHandling (AActor *source, fixed_t strength); }; @@ -106,41 +105,6 @@ int AMageStaffFX2::SpecialMissileHit (AActor *victim) return -1; } -bool AMageStaffFX2::IsOkayToAttack (AActor *link) -{ - if (((link->flags3 & MF3_ISMONSTER) || link->player) && !(link->flags2 & MF2_DORMANT)) - { - if (!(link->flags & MF_SHOOTABLE)) - { - return false; - } - if (multiplayer && !deathmatch && link->player && target->player) - { - return false; - } - if (link == target) - { - return false; - } - if (target != NULL && target->IsFriend(link)) - { - return false; - } - if (P_CheckSight (this, link)) - { - AActor *master = target; - angle_t angle = R_PointToAngle2 (master->x, master->y, - link->x, link->y) - master->angle; - angle >>= 24; - if (angle>226 || angle<30) - { - return true; - } - } - } - return false; -} - bool AMageStaffFX2::SpecialBlastHandling (AActor *source, fixed_t strength) { // Reflect to originator diff --git a/src/g_raven/a_minotaur.cpp b/src/g_raven/a_minotaur.cpp index 3dc9e141..0958edb8 100644 --- a/src/g_raven/a_minotaur.cpp +++ b/src/g_raven/a_minotaur.cpp @@ -82,49 +82,6 @@ void AMinotaurFriend::Serialize (FArchive &arc) arc << StartTime; } -bool AMinotaurFriend::IsOkayToAttack (AActor *link) -{ - if ((link->flags3 & MF3_ISMONSTER) && (link != tracer)) - { - if (!((link->flags ^ flags) & MF_FRIENDLY)) - { // Don't attack friends - if (link->flags & MF_FRIENDLY) - { - if (!deathmatch || link->FriendPlayer == 0 || FriendPlayer == 0 || - link->FriendPlayer != FriendPlayer) - { - return false; - } - } - else - { - return false; - } - } - if (!(link->flags&MF_SHOOTABLE)) - { - return false; - } - if (link->flags2&MF2_DORMANT) - { - return false; - } - if ((link->flags5 & MF5_SUMMONEDMONSTER) && (link->tracer == tracer)) - { - return false; - } - if (multiplayer && !deathmatch && link->player) - { - return false; - } - if (P_CheckSight (this, link)) - { - return true; - } - } - return false; -} - void AMinotaurFriend::Die (AActor *source, AActor *inflictor) { Super::Die (source, inflictor); diff --git a/src/g_raven/ravenshared.h b/src/g_raven/ravenshared.h index 7afd7594..fb9edf27 100644 --- a/src/g_raven/ravenshared.h +++ b/src/g_raven/ravenshared.h @@ -20,7 +20,6 @@ class AMinotaurFriend : public AMinotaur public: int StartTime; - bool IsOkayToAttack (AActor *target); void Die (AActor *source, AActor *inflictor); bool OkayToSwitchTarget (AActor *other); void BeginPlay (); diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index f12c36ae..917ae5a9 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -314,7 +314,10 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, } angle = mo->angle >> ANGLETOFINESHIFT; - Spawn(exit_flash, pmo->x + 20*finecosine[angle], pmo->y + 20*finesine[angle], pmo->z + TELEFOGHEIGHT, ALLOW_REPLACE); + if (exit_flash != NULL) + { + Spawn(exit_flash, pmo->x + 20*finecosine[angle], pmo->y + 20*finesine[angle], pmo->z + TELEFOGHEIGHT, ALLOW_REPLACE); + } mo->SetupWeaponSlots(); // Use original class's weapon slots. beastweap = player->ReadyWeapon; if (player->PremorphWeapon != NULL) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 8c024655..0602226f 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -420,17 +420,11 @@ void AActor::Die (AActor *source, AActor *inflictor) // the activator of the script. // New: In Hexen, the thing that died is the activator, // so now a level flag selects who the activator gets to be. - if (special && (!(flags & MF_SPECIAL) || (flags3 & MF3_ISMONSTER)) && !(activationtype & THINGSPEC_NoDeathSpecial)) + // Everything is now moved to P_ActivateThingSpecial(). + if (special && (!(flags & MF_SPECIAL) || (flags3 & MF3_ISMONSTER)) + && !(activationtype & THINGSPEC_NoDeathSpecial)) { - // Activation flags override LEVEL_ACTOWNSPECIAL if set. - AActor *activator = (activationtype & THINGSPEC_TriggerActs ? source : - (activationtype & THINGSPEC_ThingActs ? this : (level.flags & LEVEL_ACTOWNSPECIAL ? this : source))); - if (activationtype & THINGSPEC_ThingTargets) - this->target = source; - if (activationtype & THINGSPEC_TriggerTargets) - source->target = this; - LineSpecials[special] (NULL, activator, false, args[0], args[1], args[2], args[3], args[4]); - special = 0; + P_ActivateThingSpecial(this, source, true); } if (CountsAsKill()) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 17333f7d..f0f2faf1 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1061,6 +1061,30 @@ FUNC(LS_HealThing) return it ? true : false; } +// So that things activated/deactivated by ACS or DECORATE *and* by +// the BUMPSPECIAL or USESPECIAL flags work correctly both ways. +void DoActivateThing(AActor * thing, AActor * activator) +{ + if (thing->activationtype & THINGSPEC_Activate) + { + thing->activationtype &= ~THINGSPEC_Activate; // Clear flag + if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching + thing->activationtype |= THINGSPEC_Deactivate; + } + thing->Activate (activator); +} + +void DoDeactivateThing(AActor * thing, AActor * activator) +{ + if (thing->activationtype & THINGSPEC_Deactivate) + { + thing->activationtype &= ~THINGSPEC_Deactivate; // Clear flag + if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching + thing->activationtype |= THINGSPEC_Activate; + } + thing->Deactivate (activator); +} + FUNC(LS_Thing_Activate) // Thing_Activate (tid) { @@ -1076,7 +1100,7 @@ FUNC(LS_Thing_Activate) // Actor might remove itself as part of activation, so get next // one before activating it. AActor *temp = iterator.Next (); - actor->Activate (it); + DoActivateThing(actor, it); actor = temp; count++; } @@ -1085,7 +1109,7 @@ FUNC(LS_Thing_Activate) } else if (it != NULL) { - it->Activate(it); + DoActivateThing(it, it); return true; } return false; @@ -1106,7 +1130,7 @@ FUNC(LS_Thing_Deactivate) // Actor might removes itself as part of deactivation, so get next // one before we activate it. AActor *temp = iterator.Next (); - actor->Deactivate (it); + DoDeactivateThing(actor, it); actor = temp; count++; } @@ -1115,7 +1139,7 @@ FUNC(LS_Thing_Deactivate) } else if (it != NULL) { - it->Deactivate(it); + DoDeactivateThing(it, it); return true; } return false; diff --git a/src/p_lnspec.h b/src/p_lnspec.h index 49594724..2f5a6781 100644 --- a/src/p_lnspec.h +++ b/src/p_lnspec.h @@ -196,5 +196,6 @@ typedef int (*lnSpecFunc)(struct line_t *line, extern lnSpecFunc LineSpecials[256]; int P_FindLineSpecial (const char *string, int *min_args=NULL, int *max_args=NULL); +bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death=false); #endif //__P_LNSPEC_H__ diff --git a/src/p_map.cpp b/src/p_map.cpp index 8bd38498..3f04ce0d 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -837,24 +837,13 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) // Check for MF6_BUMPSPECIAL // By default, only players can activate things by bumping into them - if ((thing->flags6 & MF6_BUMPSPECIAL)) + if ((thing->flags6 & MF6_BUMPSPECIAL) && ((tm.thing->player != NULL) + || ((thing->activationtype & THINGSPEC_MonsterTrigger) && (tm.thing->flags3 & MF3_ISMONSTER)) + || ((thing->activationtype & THINGSPEC_MissileTrigger) && (tm.thing->flags & MF_MISSILE)) + ) && (level.maptime > thing->lastbump)) // Leave the bumper enough time to go away { - if (((tm.thing->player != NULL) - || ((thing->activationtype & THINGSPEC_MonsterTrigger) && (thing->flags3 & MF3_ISMONSTER)) - || ((thing->activationtype & THINGSPEC_MissileTrigger) && (thing->flags & MF_MISSILE)) - )) - { // Target switching mechanism - if (thing->activationtype & THINGSPEC_ThingTargets) thing->target = tm.thing; - if (thing->activationtype & THINGSPEC_TriggerTargets) tm.thing->target = thing; - // Run the special - - int res = LineSpecials[thing->special] (NULL, - ((thing->activationtype & THINGSPEC_ThingActs) ? thing : tm.thing), // Who triggers? - false, thing->args[0], thing->args[1], thing->args[2], thing->args[3], thing->args[4]); - - if (thing->activationtype & THINGSPEC_ClearSpecial && res) thing->special = 0; - - } + if (P_ActivateThingSpecial(thing, tm.thing)) + thing->lastbump = level.maptime + TICRATE; } // Check for skulls slamming into things @@ -1441,10 +1430,15 @@ bool P_TestMobjZ (AActor *actor, bool quick, AActor **pOnmobj) { // Can't hit thing continue; } - if (thing->flags & (MF_SPECIAL|MF_NOCLIP|MF_CORPSE)) - { // [RH] Corpses and specials and noclippers don't block moves + if (thing->flags & (MF_SPECIAL|MF_NOCLIP)) + { // [RH] Specials and noclippers don't block moves continue; } + if (thing->flags & (MF_CORPSE)) + { // Corpses need a few more checks + if (!(actor->flags & MF_ICECORPSE)) + continue; + } if (!(thing->flags4 & MF4_ACTLIKEBRIDGE) && (actor->flags & MF_SPECIAL)) { // [RH] Only bridges block pickup items continue; @@ -3770,18 +3764,9 @@ bool P_UseTraverse(AActor *usething, fixed_t endx, fixed_t endy, bool &foundline // Check for puzzle item use or USESPECIAL flag // Extended to use the same activationtype mechanism as BUMPSPECIAL does if (in->d.thing->flags5 & MF5_USESPECIAL || in->d.thing->special == UsePuzzleItem) - { // Target switching mechanism - if (in->d.thing->activationtype & THINGSPEC_ThingTargets) in->d.thing->target = usething; - if (in->d.thing->activationtype & THINGSPEC_TriggerTargets) usething->target = in->d.thing; - // Run the special - if (LineSpecials[in->d.thing->special] (NULL, // Who triggers? - ((in->d.thing->activationtype & THINGSPEC_ThingActs) ? in->d.thing : usething), false, - in->d.thing->args[0], in->d.thing->args[1], in->d.thing->args[2], - in->d.thing->args[3], in->d.thing->args[4])) - { - if (in->d.thing->activationtype & THINGSPEC_ClearSpecial) in->d.thing->special = 0; + { + if (P_ActivateThingSpecial(in->d.thing, usething)) return true; - } } // Dead things can't talk. if (in->d.thing->health <= 0) @@ -4315,10 +4300,15 @@ void P_FindAboveIntersectors (AActor *actor) { // Can't hit thing continue; } - if (thing->flags & (MF_CORPSE|MF_SPECIAL)) + if (thing->flags & (MF_SPECIAL)) { // [RH] Corpses and specials don't block moves continue; } + if (thing->flags & (MF_CORPSE)) + { // Corpses need a few more checks + if (!(actor->flags & MF_ICECORPSE)) + continue; + } if (thing == actor) { // Don't clip against self continue; @@ -4364,10 +4354,15 @@ void P_FindBelowIntersectors (AActor *actor) { // Can't hit thing continue; } - if (thing->flags & (MF_CORPSE|MF_SPECIAL)) + if (thing->flags & (MF_SPECIAL)) { // [RH] Corpses and specials don't block moves continue; } + if (thing->flags & (MF_CORPSE)) + { // Corpses need a few more checks + if (!(actor->flags & MF_ICECORPSE)) + continue; + } if (thing == actor) { // Don't clip against self continue; @@ -5165,3 +5160,67 @@ static void SpawnDeepSplash (AActor *t1, const FTraceResults &trace, AActor *puf } } } + +//============================================================================= +// +// P_ActivateThingSpecial +// +// Handles the code for things activated by death, USESPECIAL or BUMPSPECIAL +// +//============================================================================= + +bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death) +{ + bool res = false; + + // Target switching mechanism + if (thing->activationtype & THINGSPEC_ThingTargets) thing->target = trigger; + if (thing->activationtype & THINGSPEC_TriggerTargets) trigger->target = thing; + + // State change mechanism. The thing needs to be not dead and to have at least one of the relevant flags + if (!death && (thing->activationtype & (THINGSPEC_Activate|THINGSPEC_Deactivate|THINGSPEC_Switch))) + { + // If a switchable thing does not know whether it should be activated + // or deactivated, the default is to activate it. + if ((thing->activationtype & THINGSPEC_Switch) + && !(thing->activationtype & (THINGSPEC_Activate|THINGSPEC_Deactivate))) + { + thing->activationtype |= THINGSPEC_Activate; + } + // Can it be activated? + if (thing->activationtype & THINGSPEC_Activate) + { + thing->activationtype &= ~THINGSPEC_Activate; // Clear flag + if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching + thing->activationtype |= THINGSPEC_Deactivate; + thing->Activate(trigger); + res = true; + } + // If not, can it be deactivated? + else if (thing->activationtype & THINGSPEC_Deactivate) + { + thing->activationtype &= ~THINGSPEC_Deactivate; // Clear flag + if (thing->activationtype & THINGSPEC_Switch) // Set other flag if switching + thing->activationtype |= THINGSPEC_Activate; + thing->Deactivate(trigger); + res = true; + } + } + + // Run the special, if any + if (thing->special) + { + res = !! LineSpecials[thing->special] (NULL, + // TriggerActs overrides the level flag, which only concerns thing activated by death + (((death && level.flags & LEVEL_ACTOWNSPECIAL && !(thing->activationtype & THINGSPEC_TriggerActs)) + || (thing->activationtype & THINGSPEC_ThingActs)) // Who triggers? + ? thing : trigger), + false, thing->args[0], thing->args[1], thing->args[2], thing->args[3], thing->args[4]); + + // Clears the special if it was run on thing's death or if flag is set. + if (death || (thing->activationtype & THINGSPEC_ClearSpecial && res)) thing->special = 0; + } + + // Returns the result + return res; +} diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index ee8afa50..cbdfc855 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -301,6 +301,10 @@ void AActor::Serialize (FArchive &arc) << Species << Score << Tag; + if (SaveVersion >= 1904) + { + arc << lastpush << lastbump; + } if (SaveVersion >= 1900) { @@ -2692,36 +2696,59 @@ void AActor::PlayActiveSound () bool AActor::IsOkayToAttack (AActor *link) { - if (player) // Minotaur looking around player + if (!(player // Original AActor::IsOkayToAttack was only for players + // || (flags & MF_FRIENDLY) // Maybe let friendly monsters use the function as well? + || (flags5 & MF5_SUMMONEDMONSTER) // AMinotaurFriend has its own version, generalized to other summoned monsters + || (flags2 & MF2_SEEKERMISSILE))) // AHolySpirit and AMageStaffFX2 as well, generalized to other seeker missiles + { // Normal monsters and other actors always return false. + return false; + } + // Standard things to eliminate: an actor shouldn't attack itself, + // or a non-shootable, dormant, non-player-and-non-monster actor. + if (link == this) return false; + if (!(link->player||(link->flags3 & MF3_ISMONSTER)))return false; + if (!(link->flags & MF_SHOOTABLE)) return false; + if (link->flags2 & MF2_DORMANT) return false; + + // An actor shouldn't attack friendly actors. The reference depends + // on the type of actor: for a player's actor, itself; for a projectile, + // its target; and for a summoned minion, its tracer. + AActor * Friend = NULL; + if (player) Friend = this; + else if (flags5 & MF5_SUMMONEDMONSTER) Friend = tracer; + else if (flags2 & MF2_SEEKERMISSILE) Friend = target; + else if ((flags & MF_FRIENDLY) && FriendPlayer) Friend = players[FriendPlayer-1].mo; + + // Friend checks + if (link == Friend) return false; + if (Friend == NULL) return false; + if (Friend->IsFriend(link)) return false; + if ((link->flags5 & MF5_SUMMONEDMONSTER) // No attack against minions on the same side + && (link->tracer == Friend)) return false; + if (multiplayer && !deathmatch // No attack against fellow players in coop + && link->player && Friend->player) return false; + if (((flags & link->flags) & MF_FRIENDLY) // No friendly infighting amongst minions + && IsFriend(link)) return false; + + // Now that all the actor checks are made, the line of sight can be checked + if (P_CheckSight (this, link)) { - if ((link->flags3 & MF3_ISMONSTER) || (link->player && (link != this))) + // AMageStaffFX2::IsOkayToAttack had an extra check here, generalized with a flag, + // to only allow the check to succeed if the enemy was in a ~84° FOV of the player + if (flags3 & MF3_SCREENSEEKER) { - if (IsFriend(link)) - { - return false; - } - if (!(link->flags & MF_SHOOTABLE)) - { - return false; - } - if (link->flags2 & MF2_DORMANT) - { - return false; - } - if ((link->flags5 & MF5_SUMMONEDMONSTER) && (link->tracer == this)) - { - return false; - } - if (multiplayer && !deathmatch && link->player) - { - return false; - } - if (P_CheckSight (this, link)) + angle_t angle = R_PointToAngle2(Friend->x, + Friend->y, link->x, link->y) - Friend->angle; + angle >>= 24; + if (angle>226 || angle<30) { return true; } } + // Other actors are not concerned by this check + else return true; } + // The sight check was failed, or the angle wasn't right for a screenseeker return false; } @@ -3677,7 +3704,7 @@ void AActor::Activate (AActor *activator) if (flags2 & MF2_DORMANT) { flags2 &= ~MF2_DORMANT; - FState *state = FindState("Active"); + FState *state = FindState(NAME_Active); if (state != NULL) { SetState(state); @@ -3697,7 +3724,7 @@ void AActor::Deactivate (AActor *activator) if (!(flags2 & MF2_DORMANT)) { flags2 |= MF2_DORMANT; - FState *state = FindState("Inactive"); + FState *state = FindState(NAME_Inactive); if (state != NULL) { SetState(state); diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 31d2d94f..14742f55 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1917,11 +1917,34 @@ void AAmbientSound::Serialize (FArchive &arc) Super::Serialize (arc); arc << bActive; - int checktime = NextCheck - gametic; - arc << checktime; - if (arc.IsLoading ()) + if (SaveVersion < 1902) { - NextCheck = checktime + gametic; + arc << NextCheck; + NextCheck += gametic; + if (NextCheck < 0) NextCheck = INT_MAX; + } + else + { + if (arc.IsStoring()) + { + if (NextCheck != INT_MAX) + { + int checktime = NextCheck - gametic; + arc << checktime; + } + else + { + arc << NextCheck; + } + } + else + { + arc << NextCheck; + if (NextCheck != INT_MAX) + { + NextCheck += gametic; + } + } } } diff --git a/src/svnrevision.h b/src/svnrevision.h index 71d42589..3b7c2da2 100644 --- a/src/svnrevision.h +++ b/src/svnrevision.h @@ -3,5 +3,5 @@ // This file was automatically generated by the // updaterevision tool. Do not edit by hand. -#define ZD_SVN_REVISION_STRING "1900" -#define ZD_SVN_REVISION_NUMBER 1900 +#define ZD_SVN_REVISION_STRING "1905" +#define ZD_SVN_REVISION_NUMBER 1905 diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 39a08cac..934a0b9b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -342,12 +342,24 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_StopSoundEx) // Generic seeker missile function // //========================================================================== +static FRandom pr_seekermissile ("SeekerMissile"); +enum +{ + SMF_LOOK = 1, +}; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SeekerMissile) { - ACTION_PARAM_START(2); + ACTION_PARAM_START(5); ACTION_PARAM_INT(ang1, 0); ACTION_PARAM_INT(ang2, 1); + ACTION_PARAM_INT(flags, 2); + ACTION_PARAM_INT(chance, 3); + ACTION_PARAM_INT(distance, 4); + if ((flags & SMF_LOOK) && (self->tracer == 0) && (pr_seekermissile()tracer = P_RoughMonsterSearch (self, distance); + } P_SeekerMissile(self, clamp(ang1, 0, 90) * ANGLE_1, clamp(ang2, 0, 90) * ANGLE_1); } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 7c7ee225..89741fca 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -92,6 +92,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF, NOLIFTDROP, AActor, flags), DEFINE_FLAG(MF, STEALTH, AActor, flags), DEFINE_FLAG(MF, ICECORPSE, AActor, flags), + DEFINE_FLAG(MF2, DONTREFLECT, AActor, flags2), DEFINE_FLAG(MF2, WINDTHRUST, AActor, flags2), DEFINE_FLAG(MF2, DONTSEEKINVISIBLE, AActor, flags2), @@ -121,6 +122,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF2, DORMANT, AActor, flags2), DEFINE_FLAG(MF2, SEEKERMISSILE, AActor, flags2), DEFINE_FLAG(MF2, REFLECTIVE, AActor, flags2), + DEFINE_FLAG(MF3, FLOORHUGGER, AActor, flags3), DEFINE_FLAG(MF3, CEILINGHUGGER, AActor, flags3), DEFINE_FLAG(MF3, NORADIUSDMG, AActor, flags3), @@ -141,13 +143,15 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF3, NOTARGET, AActor, flags3), DEFINE_FLAG(MF3, DONTGIB, AActor, flags3), DEFINE_FLAG(MF3, NOBLOCKMONST, AActor, flags3), - DEFINE_FLAG(MF3, AVOIDMELEE, AActor, flags3), DEFINE_FLAG(MF3, FULLVOLDEATH, AActor, flags3), + DEFINE_FLAG(MF3, AVOIDMELEE, AActor, flags3), + DEFINE_FLAG(MF3, SCREENSEEKER, AActor, flags3), DEFINE_FLAG(MF3, FOILINVUL, AActor, flags3), DEFINE_FLAG(MF3, NOTELEOTHER, AActor, flags3), DEFINE_FLAG(MF3, BLOODLESSIMPACT, AActor, flags3), DEFINE_FLAG(MF3, NOEXPLODEFLOOR, AActor, flags3), DEFINE_FLAG(MF3, PUFFONACTORS, AActor, flags3), + DEFINE_FLAG(MF4, QUICKTORETALIATE, AActor, flags4), DEFINE_FLAG(MF4, NOICEDEATH, AActor, flags4), DEFINE_FLAG(MF4, RANDOMIZE, AActor, flags4), diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index 6d83627a..7a84a3ed 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -465,6 +465,9 @@ static int ParseThingActivation (FScanner &sc) { "THINGSPEC_ClearSpecial", THINGSPEC_ClearSpecial}, { "THINGSPEC_NoDeathSpecial", THINGSPEC_NoDeathSpecial}, { "THINGSPEC_TriggerActs", THINGSPEC_TriggerActs}, + { "THINGSPEC_Activate", THINGSPEC_Activate}, + { "THINGSPEC_Deactivate", THINGSPEC_Deactivate}, + { "THINGSPEC_Switch", THINGSPEC_Switch}, { NULL, 0 } }; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 66e7cdc6..faa9fba4 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1072,7 +1072,7 @@ DEFINE_PROPERTY(projectile, 0, Actor) //========================================================================== DEFINE_PROPERTY(activation, N, Actor) { - // How the thing behaves when activated with MF5_USESPECIAL or MF6_BUMPSPECIAL + // How the thing behaves when activated by death, USESPECIAL or BUMPSPECIAL PROP_INT_PARM(val, 0); defaults->activationtype = val; } diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 71fcca21..a776144e 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -281,8 +281,6 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) GammaShader = NULL; BlockSurface[0] = NULL; BlockSurface[1] = NULL; - FBFormat = D3DFMT_UNKNOWN; - PalFormat = D3DFMT_UNKNOWN; VSync = vid_vsync; BlendingRect.left = 0; BlendingRect.top = 0; @@ -298,6 +296,7 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) QuadExtra = new BufferedQuad[MAX_QUAD_BATCH]; Packs = NULL; PixelDoubling = 0; + SkipAt = -1; Gamma = 1.0; FlashColor0 = 0; @@ -787,7 +786,6 @@ bool D3DFB::CreatePaletteTexture () { return false; } - PalFormat = D3DFMT_A8R8G8B8; return true; } @@ -1277,28 +1275,144 @@ void D3DFB::UpdateGammaTexture(float igamma) } } +//========================================================================== +// +// D3DFB :: DoOffByOneCheck +// +// Pixel Shader 1.x does not have enough precision to properly map a "color" +// from the source texture to an index in the palette texture. The best we +// can do is use 255 pixels of the palette and get the 256th from the +// texture border color. This routine determines which pixel of the texture +// is skipped so that we don't use it for palette data. +// +//========================================================================== + +void D3DFB::DoOffByOneCheck () +{ + IDirect3DSurface9 *savedrendertarget; + IDirect3DSurface9 *testsurf, *readsurf; + D3DLOCKED_RECT lockrect; + RECT testrect = { 0, 0, 256, 1 }; + float texright = 256.f / float(FBWidth); + float texbot = 1.f / float(FBHeight); + FBVERTEX verts[4] = + { + { -0.5f, -0.5f, 0.5f, 1.f, 0, ~0, 0.f, 0.f }, + { 255.5f, -0.5f, 0.5f, 1.f, 0, ~0, texright, 0.f }, + { 255.5f, 0.5f, 0.5f, 1.f, 0, ~0, texright, texbot }, + { -0.5f, 0.5f, 0.5f, 1.f, 0, ~0, 0.f, texbot } + }; + int i, c; + + if (SkipAt >= 0) + { + return; + } + + // Create an easily recognizable R3G3B2 palette. + if (SUCCEEDED(PaletteTexture->LockRect(0, &lockrect, NULL, 0))) + { + BYTE *pal = (BYTE *)(lockrect.pBits); + for (i = 0; i < 256; ++i) + { + pal[i*4+0] = (i & 0x03) << 6; // blue + pal[i*4+1] = (i & 0x1C) << 3; // green + pal[i*4+2] = (i & 0xE0); // red; + pal[i*4+3] = 255; + } + PaletteTexture->UnlockRect (0); + } + else + { + return; + } + // Prepare a texture with values 0-256. + if (SUCCEEDED(FBTexture->LockRect(0, &lockrect, &testrect, 0))) + { + for (i = 0; i < 256; ++i) + { + ((BYTE *)lockrect.pBits)[i] = i; + } + FBTexture->UnlockRect(0); + } + else + { + return; + } + // Create a render target that we can draw it to. + if (FAILED(D3DDevice->GetRenderTarget(0, &savedrendertarget))) + { + return; + } + if (FAILED(D3DDevice->CreateRenderTarget(256, 1, D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &testsurf, NULL))) + { + return; + } + if (FAILED(D3DDevice->CreateOffscreenPlainSurface(256, 1, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &readsurf, NULL))) + { + testsurf->Release(); + return; + } + if (FAILED(D3DDevice->SetRenderTarget(0, testsurf))) + { + testsurf->Release(); + readsurf->Release(); + return; + } + // Write it to the render target using the pixel shader. + D3DDevice->BeginScene(); + D3DDevice->SetTexture(0, FBTexture); + D3DDevice->SetTexture(1, PaletteTexture); + D3DDevice->SetFVF(D3DFVF_FBVERTEX); + D3DDevice->SetPixelShader(Shaders[SHADER_NormalColorPal]); + SetConstant(PSCONST_PaletteMod, 1.f, 0.5f / 256.f, 0, 0); + D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(FBVERTEX)); + D3DDevice->EndScene(); + D3DDevice->SetRenderTarget(0, savedrendertarget); + savedrendertarget->Release(); + // Now read it back and see where it skips an entry + if (SUCCEEDED(D3DDevice->GetRenderTargetData(testsurf, readsurf)) && + SUCCEEDED(readsurf->LockRect(&lockrect, &testrect, D3DLOCK_READONLY))) + { + const BYTE *pix = (const BYTE *)lockrect.pBits; + for (i = 0; i < 256; ++i, pix += 4) + { + c = (pix[0] >> 6) | // blue + ((pix[1] >> 5) << 2) | // green + ((pix[2] >> 5) << 5); // red + if (c != i) + { + break; + } + } + } + readsurf->UnlockRect(); + readsurf->Release(); + testsurf->Release(); + SkipAt = i; +} + void D3DFB::UploadPalette () { D3DLOCKED_RECT lockrect; - if (SUCCEEDED(PaletteTexture->LockRect (0, &lockrect, NULL, 0))) + if (SkipAt < 0) + { + if (SM14) + { + DoOffByOneCheck(); + } + else + { + SkipAt = 256; + } + } + if (SUCCEEDED(PaletteTexture->LockRect(0, &lockrect, NULL, 0))) { BYTE *pix = (BYTE *)lockrect.pBits; - int i, skipat; + int i; - // It is impossible to get the Radeon 9000 to do the proper palette - // lookup. It *will* skip at least one entry in the palette. So we - // let it and have it look at the texture border color for color 255. - // I assume that every other card based on a related graphics chipset - // is similarly affected, which basically means that all Shader Model - // 1.4 cards suffer from this problem, since they all use some variant - // of the ATI R200. - // - // [Oh, gee. Looking over the old documentation, I guess this is - // documented that PS 1.x cards don't have a lot of precision.] - skipat = SM14 ? 256 - 8 : 256; - - for (i = 0; i < skipat; ++i, pix += 4) + for (i = 0; i < SkipAt; ++i, pix += 4) { pix[0] = SourcePalette[i].b; pix[1] = SourcePalette[i].g; @@ -1314,7 +1428,7 @@ void D3DFB::UploadPalette () pix[2] = SourcePalette[i].r; pix[3] = 255; } - PaletteTexture->UnlockRect (0); + PaletteTexture->UnlockRect(0); BorderColor = D3DCOLOR_XRGB(SourcePalette[255].r, SourcePalette[255].g, SourcePalette[255].b); } } diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index bd2c7bb8..6c7c066b 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -338,6 +338,7 @@ private: bool CreatePaletteTexture(); bool CreateGammaTexture(); bool CreateVertexes(); + void DoOffByOneCheck(); void UploadPalette(); void UpdateGammaTexture(float igamma); void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync); @@ -391,14 +392,13 @@ private: int FlashAmount; int TrueHeight; int PixelDoubling; + int SkipAt; int LBOffsetI; float LBOffset; float Gamma; bool UpdatePending; bool NeedPalUpdate; bool NeedGammaUpdate; - D3DFORMAT FBFormat; - D3DFORMAT PalFormat; int FBWidth, FBHeight; bool VSync; RECT BlendingRect; diff --git a/wadsrc/static/shaders/d3d/sm14/GammaCorrection.pso b/wadsrc/static/shaders/d3d/sm14/GammaCorrection.pso new file mode 100644 index 0000000000000000000000000000000000000000..8abf541bc11754a15864d31fcba36720eaa402cd GIT binary patch literal 460 zcmY*Vu}T9$6r9~#IYA*mU~#23hi8;}>NJy3X4TA$iMVXNH;gmNm+`KX;DK?OA&dzz^F{+u|)83i#$_*%~pa#v8HJJ3At$ z1yi=voE`D3Yad=S8``JW{CIp3OI;LYS)i_!&jv-hUKgOba4})>ismjstg&!(?b@YQMdh? zh6NUL`45Gd7&eBR3XeSRt+?@g=6QIdqTktH2godqhE-Tt!4Yw^#D>@qhs-uJ5PZsw VRtHQ;)8AY3xTVK1JF|{E{sAD|PEh~= literal 0 HcmV?d00001