diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 454b4f739..4a9744b87 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,29 @@ +May 13, 2006 (Changes by Graf Zahl) +- Changed: The decision whether blood splatter sprites are spawned is no + longer determined by game. Instead there's a new flag, MF5_BLOODSPLATTER + which is deciding what to do. To keep backwards compatibility this flag + is unset for projectiles in Doom and Strife and set for them in Heretic + and Hexen. The same applies to DECORATE but of course the flag can be + manipulated here. +- BLODxx sprites are now globally renamed to BLUDxx when not playing Doom. + This allows using the same states in every game, including the + Raven-specific blood actors. +- Gave the bullet puff and the axe blood masses of 5 so that the make small + splashes. +- Added A_Light(value) code pointer for DECORATE to generalize the weapon + light effect. +- Added 'noskillmenu' option to MAPINFO episode definitions. This is for + WADs that want to implement a skill selection level. +- Added APROP_ChaseGoal and APROP_Frightened actor properties for ACS. +- Added MF5_CHASEGOAL flag that makes monsters to go after their goal even + if they have a valid target. +- Fixed some issues with the changes to P_NewChaseDir I made to include + MBF's dropoff logic. +- Added a PowerFrightener powerup class. It seemed like such a waste to + have this cool feature but no means to use it in a decent fashion. +- Fixed: S_Init and S_ParseSndInfo should call atterm only once but not + each time they are called. + May 11, 2006 - Merged a lot of these static destructor-only structs into regular functions added to the exit chain with atterm so that they can be called diff --git a/src/actor.h b/src/actor.h index 88b01b1e1..a333826fb 100644 --- a/src/actor.h +++ b/src/actor.h @@ -277,9 +277,11 @@ enum MF5_FASTMELEE = 0x00000002, // has a faster melee attack when DF_FAST_MONSTERS or nightmare is on. MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. MF5_BOUNCEONACTORS = 0x00000008, // bouncing missile doesn't explode when it hits an actor - MF5_EXPLODEONWATER = 0x00000010, // bouncing missile explpdes when hitting a water surface - MF5_AVOIDINGDROPOFF = 0x00000020, // Used to move monsters away fro dropoffs + MF5_EXPLODEONWATER = 0x00000010, // bouncing missile explodes when hitting a water surface + MF5_AVOIDINGDROPOFF = 0x00000020, // Used to move monsters away from dropoffs MF5_NODAMAGE = 0x00000040, // Actor can be shot and reacts to being shot but takes no damage + MF5_CHASEGOAL = 0x00000080, // Walks to goal instead of target if a valid goal is set. + MF5_BLOODSPLATTER = 0x00000100, // Blood splatter like in Raven's games. // --- mobj.renderflags --- diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index 75bc7cbb7..ed01b8fa2 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -110,6 +110,7 @@ IMPLEMENT_ACTOR (ABulletPuff, Doom, -1, 131) PROP_SpawnState (0) PROP_MeleeState (2) + PROP_Mass(5) END_DEFAULTS void ABulletPuff::BeginPlay () diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index 6c8c58dc6..6870f8259 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -373,6 +373,7 @@ FState AGoldWand::States[] = }; IMPLEMENT_ACTOR (AGoldWand, Heretic, -1, 0) + PROP_Flags5 (MF5_BLOODSPLATTER) PROP_Weapon_SelectionOrder (2000) PROP_Weapon_AmmoUse1 (USE_GWND_AMMO_1) PROP_Weapon_AmmoGive1 (25) @@ -1696,6 +1697,7 @@ FState AGauntlets::States[] = IMPLEMENT_ACTOR (AGauntlets, Heretic, 2005, 32) PROP_Flags (MF_SPECIAL) + PROP_Flags5 (MF5_BLOODSPLATTER) PROP_SpawnState (S_WGNT) PROP_Weapon_SelectionOrder (2300) @@ -1989,6 +1991,7 @@ FState ABlaster::States[] = IMPLEMENT_ACTOR (ABlaster, Heretic, 53, 28) PROP_Flags (MF_SPECIAL) + PROP_Flags5 (MF5_BLOODSPLATTER) PROP_SpawnState (S_BLSR) PROP_Weapon_SelectionOrder (500) diff --git a/src/g_hexen/a_clericmace.cpp b/src/g_hexen/a_clericmace.cpp index 47990180d..145abcd91 100644 --- a/src/g_hexen/a_clericmace.cpp +++ b/src/g_hexen/a_clericmace.cpp @@ -58,6 +58,7 @@ FState ACWeapMace::States[] = IMPLEMENT_ACTOR (ACWeapMace, Hexen, -1, 0) PROP_Weapon_SelectionOrder (3500) + PROP_Flags5 (MF5_BLOODSPLATTER) PROP_Weapon_Flags (WIF_BOT_MELEE) PROP_Weapon_UpState (S_CMACEUP) PROP_Weapon_DownState (S_CMACEDOWN) diff --git a/src/g_hexen/a_fighteraxe.cpp b/src/g_hexen/a_fighteraxe.cpp index 6cd88fc5d..3a18c9272 100644 --- a/src/g_hexen/a_fighteraxe.cpp +++ b/src/g_hexen/a_fighteraxe.cpp @@ -220,6 +220,7 @@ FState AAxeBlood::States[] = }; IMPLEMENT_ACTOR (AAxeBlood, Hexen, -1, 0) + PROP_Mass (5) PROP_RadiusFixed (2) PROP_HeightFixed (4) PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF) diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index 8aa965bce..668458c35 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -65,6 +65,7 @@ FState AFWeapHammer::States[] = IMPLEMENT_ACTOR (AFWeapHammer, Hexen, 123, 28) PROP_Flags (MF_SPECIAL) + PROP_Flags5 (MF5_BLOODSPLATTER) PROP_SpawnState (S_HAMM) PROP_Weapon_SelectionOrder (900) diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 719ce05ee..24ca2d09a 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -208,6 +208,7 @@ FState AFWeapFist::States[] = }; IMPLEMENT_ACTOR (AFWeapFist, Hexen, -1, 0) + PROP_Flags5 (MF5_BLOODSPLATTER) PROP_Weapon_SelectionOrder (3400) PROP_Weapon_Flags (WIF_BOT_MELEE) PROP_Weapon_UpState (S_PUNCHUP) diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp index 261dc3c32..79a223c40 100644 --- a/src/g_hexen/a_magecone.cpp +++ b/src/g_hexen/a_magecone.cpp @@ -62,6 +62,7 @@ FState AMWeapFrost::States[] = IMPLEMENT_ACTOR (AMWeapFrost, Hexen, 53, 36) PROP_Flags (MF_SPECIAL) + PROP_Flags5 (MF5_BLOODSPLATTER) PROP_SpawnState (S_COS1) PROP_Weapon_SelectionOrder (1700) diff --git a/src/g_level.cpp b/src/g_level.cpp index 2945cc36f..4ecc92dfa 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -982,6 +982,7 @@ static void ParseMapInfoLower (MapInfoHandler *handlers, // name "Episode name as text" // picname "Picture to display the episode name" // key "Shortcut key for the menu" +// noskillmenu // remove static void ParseEpisodeInfo () @@ -993,6 +994,7 @@ static void ParseEpisodeInfo () bool remove = false; char key = 0; bool addedgfx = false; + bool noskill = false; // Get map name SC_MustGetString (); @@ -1032,6 +1034,10 @@ static void ParseEpisodeInfo () SC_MustGetString (); key = sc_String[0]; } + else if (SC_Compare("noskillmenu")) + { + noskill = true; + } else { SC_UnGet (); @@ -1059,6 +1065,8 @@ static void ParseEpisodeInfo () sizeof(EpisodeMaps[0])*(EpiDef.numitems - i - 1)); memmove (&EpisodeMenu[i], &EpisodeMenu[i+1], sizeof(EpisodeMenu[0])*(EpiDef.numitems - i - 1)); + memmove (&EpisodeNoSkill[i], &EpisodeNoSkill[i+1], + sizeof(EpisodeNoSkill[0])*(EpiDef.numitems - i - 1)); } EpiDef.numitems--; } @@ -1090,6 +1098,7 @@ static void ParseEpisodeInfo () EpisodeMenu[i].name = pic; EpisodeMenu[i].alphaKey = tolower(key); EpisodeMenu[i].fulltext = !picisgfx; + EpisodeNoSkill[i] = noskill; strncpy (EpisodeMaps[i], map, 8); if (picisgfx) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 9019a49d3..14ea9cd55 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -1073,6 +1073,40 @@ void APowerTargeter::PositionAccuracy () player->psprites[ps_targetright].sx = (160-3)*FRACUNIT + ((100 - player->accuracy) << FRACBITS); } +// Frightener Powerup -------------------------------- + +IMPLEMENT_STATELESS_ACTOR (APowerFrightener, Any, -1, 0) + PROP_Powerup_EffectTics (60*TICRATE) +END_DEFAULTS + +//=========================================================================== +// +// APowerFrightener :: InitEffect +// +//=========================================================================== + +void APowerFrightener::InitEffect () +{ + if (Owner->player == NULL) + return; + + Owner->player->cheats |= CF_FRIGHTENING; +} + +//=========================================================================== +// +// APowerFrightener :: EndEffect +// +//=========================================================================== + +void APowerFrightener::EndEffect () +{ + if (Owner->player == NULL) + return; + + Owner->player->cheats &= ~CF_FRIGHTENING; +} + // Scanner powerup ---------------------------------------------------------- IMPLEMENT_STATELESS_ACTOR (APowerScanner, Any, -1, 0) diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index cabaacf71..52fe798ee 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -185,6 +185,15 @@ protected: void Travelled (); }; +class APowerFrightener : public APowerup +{ + DECLARE_STATELESS_ACTOR (APowerFrightener, APowerup) +protected: + void InitEffect (); + void EndEffect (); +}; + + class player_s; #endif //__A_ARTIFACTS_H__ diff --git a/src/g_shared/a_sharedmisc.cpp b/src/g_shared/a_sharedmisc.cpp index 214b0d1b4..b17d1aee3 100644 --- a/src/g_shared/a_sharedmisc.cpp +++ b/src/g_shared/a_sharedmisc.cpp @@ -50,12 +50,7 @@ FState ABlood::States[] = S_NORMAL (BLUD, 'B', 8, NULL , &States[S_DBLOOD+2]), S_NORMAL (BLUD, 'A', 8, NULL , NULL), -#define S_HBLOOD (S_DBLOOD+3) - S_NORMAL (BLOD, 'C', 8, NULL , &States[S_HBLOOD+1]), - S_NORMAL (BLOD, 'B', 8, NULL , &States[S_HBLOOD+2]), - S_NORMAL (BLOD, 'A', 8, NULL , NULL), - -#define S_SBLOOD (S_HBLOOD+3) +#define S_SBLOOD (S_DBLOOD+3) S_NORMAL (SPRY, 'A', 3, NULL , &States[S_SBLOOD+1]), S_NORMAL (SPRY, 'B', 3, NULL , &States[S_SBLOOD+2]), S_NORMAL (SPRY, 'C', 3, NULL , &States[S_SBLOOD+3]), @@ -68,16 +63,10 @@ FState ABlood::States[] = IMPLEMENT_ACTOR (ABlood, Any, -1, 130) PROP_Flags (MF_NOBLOCKMAP) PROP_Flags2 (MF2_NOTELEPORT) + PROP_SpawnState(S_DBLOOD) PROP_Mass (5) END_DEFAULTS -AT_GAME_SET (Blood) -{ - ABlood *def = GetDefault(); - - def->SpawnState = &ABlood::States[gameinfo.gametype == GAME_Doom ? S_DBLOOD : S_HBLOOD]; -} - void ABlood::SetDamage (int damage) { if (gameinfo.gametype == GAME_Doom) @@ -99,15 +88,15 @@ void ABlood::SetDamage (int damage) } else if (damage >= 10) { - SetState (&States[S_HBLOOD]); + SetState (&States[S_DBLOOD]); } else if (damage >= 7) { - SetState (&States[S_HBLOOD+1]); + SetState (&States[S_DBLOOD+1]); } else { - SetState (&States[S_HBLOOD+2]); + SetState (&States[S_DBLOOD+2]); } } } diff --git a/src/infodefaults.cpp b/src/infodefaults.cpp index 732d8bcd4..c74326b73 100644 --- a/src/infodefaults.cpp +++ b/src/infodefaults.cpp @@ -372,4 +372,9 @@ void FActorInfo::ApplyDefaults (BYTE *defaults) { ((AActor *)defaults)->flags3 |= MF3_ISMONSTER; } + // Any default projectile in Raven's games produces blood splatter + if (gameinfo.gametype & GAME_Raven && ((AActor *)defaults)->flags & MF_MISSILE) + { + ((AActor *)defaults)->flags5 |= MF5_BLOODSPLATTER; + } } diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 7f9167f86..7c3a8000d 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -313,6 +313,7 @@ oldmenuitem_t EpisodeMenu[MAX_EPISODES] = }; char EpisodeMaps[MAX_EPISODES][8]; +bool EpisodeNoSkill[MAX_EPISODES]; oldmenu_t EpiDef = { @@ -1500,7 +1501,11 @@ void M_NewGame(int choice) { if (EpiDef.numitems <= 1) { - if (gameinfo.gametype & (GAME_Doom|GAME_Strife)) + if (EpisodeNoSkill[0]) + { + M_ChooseSkill(2); + } + else if (gameinfo.gametype & (GAME_Doom|GAME_Strife)) { M_SetupNextMenu (&NewDef); } @@ -1621,6 +1626,12 @@ void M_Episode (int choice) return; } + if (EpisodeNoSkill[choice]) + { + M_ChooseSkill(2); + return; + } + epi = choice; if (gameinfo.gametype & (GAME_Doom|GAME_Strife)) M_SetupNextMenu (&NewDef); @@ -1685,10 +1696,14 @@ static void SCClass (int option) { M_SetupNextMenu (&EpiDef); } - else + else if (!EpisodeNoSkill[0]) { M_SetupNextMenu (&HexenSkillMenu); } + else + { + M_ChooseSkill(2); + } } diff --git a/src/m_menu.h b/src/m_menu.h index 23108bd3d..30886d194 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -222,6 +222,7 @@ extern int CurrentItem; #define MAX_EPISODES 8 extern oldmenuitem_t EpisodeMenu[MAX_EPISODES]; +extern bool EpisodeNoSkill[MAX_EPISODES]; extern char EpisodeMaps[MAX_EPISODES][8]; extern oldmenu_t EpiDef; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 93863d3b1..ffa9983a6 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1913,6 +1913,8 @@ void DLevelScript::DoSetFont (int fontnum) #define APROP_Ambush 10 #define APROP_Invulnerable 11 #define APROP_JumpZ 12 // [GRB] +#define APROP_ChaseGoal 13 +#define APROP_Frightened 14 #define APROP_SeeSound 5 // Sounds can only be set, not gotten #define APROP_AttackSound 6 #define APROP_PainSound 7 @@ -1960,6 +1962,8 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) case APROP_Invulnerable:if (value) actor->flags2 |= MF2_INVULNERABLE; else actor->flags2 &= ~MF2_INVULNERABLE; break; case APROP_JumpZ: if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) static_cast(actor)->JumpZ = value; break; // [GRB] + case APROP_ChaseGoal: if (value) actor->flags5 |= MF5_CHASEGOAL; else actor->flags5 &= ~MF5_CHASEGOAL; break; + case APROP_Frightened: if (value) actor->flags4 |= MF4_FRIGHTENED; else actor->flags4 &= ~MF4_FRIGHTENED; break; case APROP_SeeSound: actor->SeeSound = S_FindSound (FBehavior::StaticLookupString (value)); break; case APROP_AttackSound: actor->AttackSound = S_FindSound (FBehavior::StaticLookupString (value)); break; case APROP_PainSound: actor->PainSound = S_FindSound (FBehavior::StaticLookupString (value)); break; @@ -1997,6 +2001,8 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_Alpha: return actor->alpha; case APROP_RenderStyle: return actor->RenderStyle; case APROP_Ambush: return !!(actor->flags & MF_AMBUSH); + case APROP_ChaseGoal: return !!(actor->flags5 & MF5_CHASEGOAL); + case APROP_Frightened: return !!(actor->flags4 & MF4_FRIGHTENED); case APROP_JumpZ: if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) { return static_cast(actor)->JumpZ; // [GRB] diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index c17a2551e..ae4cb0766 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -89,6 +89,7 @@ dirtype_t diags[4] = fixed_t xspeed[8] = {FRACUNIT,46341,0,-46341,-FRACUNIT,-46341,0,46341}; fixed_t yspeed[8] = {0,46341,FRACUNIT,46341,0,-46341,-FRACUNIT,-46341}; +void P_RandomChaseDir (AActor *actor); // @@ -576,22 +577,9 @@ void P_DoNewChaseDir (AActor *actor, fixed_t deltax, fixed_t deltay) int tdir; dirtype_t olddir, turnaround; - if (actor->target == NULL) - I_Error ("P_NewChaseDir: called with no target"); - olddir = (dirtype_t)actor->movedir; turnaround = opposite[olddir]; - - // [RH] Make monsters run away from frightening players - if ((actor->target->player != NULL && - (actor->target->player->cheats & CF_FRIGHTENING)) || - actor->flags4 & MF4_FRIGHTENED) - { - deltax = -deltax; - deltay = -deltay; - } - if (deltax>10*FRACUNIT) d[1]= DI_EAST; else if (deltax<-10*FRACUNIT) @@ -702,6 +690,7 @@ void P_DoNewChaseDir (AActor *actor, fixed_t deltax, fixed_t deltay) struct avoiddropoff_t { + AActor * thing; fixed_t deltax; fixed_t deltay; fixed_t floorx; @@ -724,13 +713,13 @@ static BOOL PIT_AvoidDropoff(line_t *line) angle_t angle; // The monster must contact one of the two floors, - // and the other must be a tall dropoff (more than 24). + // and the other must be a tall dropoff. - if (back == a.floorz && front < a.floorz - FRACUNIT*24) + if (back == a.floorz && front < a.floorz - a.thing->MaxDropOffHeight) { angle = R_PointToAngle2(0,0,line->dx,line->dy); // front side dropoff } - else if (front == a.floorz && back < a.floorz - FRACUNIT*24) + else if (front == a.floorz && back < a.floorz - a.thing->MaxDropOffHeight) { angle = R_PointToAngle2(line->dx,line->dy,0,0); // back side dropoff } @@ -754,8 +743,33 @@ static BOOL PIT_AvoidDropoff(line_t *line) void P_NewChaseDir(AActor * actor) { - fixed_t deltax = actor->target->x - actor->x; - fixed_t deltay = actor->target->y - actor->y; + fixed_t deltax; + fixed_t deltay; + + if ((actor->flags5&MF5_CHASEGOAL || actor->goal == actor->target) && actor->goal!=NULL) + { + deltax = actor->goal->x - actor->x; + deltay = actor->goal->y - actor->y; + } + else if (actor->target != NULL) + { + deltax = actor->target->x - actor->x; + deltay = actor->target->y - actor->y; + + if ((actor->target->player != NULL && (actor->target->player->cheats & CF_FRIGHTENING)) || + (actor->flags4 & MF4_FRIGHTENED)) + { + deltax = -deltax; + deltay = -deltay; + } + } + else + { + // Don't abort if this happens. + Printf ("P_NewChaseDir: called with no target\n"); + P_RandomChaseDir(actor); + return; + } // Try to move away from a dropoff if (actor->floorz - actor->dropoffz > actor->MaxDropOffHeight && @@ -763,6 +777,7 @@ void P_NewChaseDir(AActor * actor) !(actor->flags2 & MF2_ONMOBJ) && !(actor->flags & MF_FLOAT) && !(compatflags & COMPATF_DROPOFF)) { + a.thing = actor; a.deltax = a.deltay = 0; a.floorx = actor->x; a.floory = actor->y; @@ -1510,6 +1525,8 @@ void A_Look (AActor *actor) actor->special = 0; actor->goal = iterator.Next (); actor->reactiontime = actor->args[2] * TICRATE + level.maptime; + if (actor->args[3] == 0) actor->flags5 &=~ MF5_CHASEGOAL; + else actor->flags5 |= MF5_CHASEGOAL; } actor->threshold = 0; // any shot will wake up @@ -1859,9 +1876,14 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } // [RH] Don't attack if just moving toward goal - if (actor->target == actor->goal) + if (actor->target == actor->goal || (actor->flags5&MF5_CHASEGOAL && actor->goal != NULL)) { - if (actor->CheckMeleeRange ()) + AActor * savedtarget = actor->target; + actor->target = actor->goal; + bool result = actor->CheckMeleeRange(); + actor->target = savedtarget; + + if (result) { // reached the goal TActorIterator iterator (actor->goal->args[0]); @@ -1877,27 +1899,31 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi } angle_t lastgoalang = actor->goal->angle; - actor->goal = iterator.Next (); - if (actor->goal != NULL) + int delay; + AActor * newgoal = iterator.Next (); + if (newgoal != NULL && actor->goal == actor->target) { - actor->reactiontime = actor->goal->args[1] * TICRATE + level.maptime; + delay = newgoal->args[1]; + actor->reactiontime = delay * TICRATE + level.maptime; } else { + delay = 0; actor->reactiontime = actor->GetDefault()->reactiontime; actor->angle = lastgoalang; // Look in direction of last goal } - actor->target = NULL; + if (actor->target == actor->goal) actor->target = NULL; actor->flags |= MF_JUSTATTACKED; - if (actor->goal != NULL && actor->goal->args[1] != 0) + if (newgoal != NULL && delay != 0) { actor->flags4 |= MF4_INCOMBAT; actor->SetState (actor->SpawnState); } actor->flags &= ~MF_INCHASE; + actor->goal = newgoal; return; } - goto nomissile; + if (actor->goal == actor->target) goto nomissile; } // Strafe (Hexen's class bosses) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 66ed4f536..74cff859e 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1310,7 +1310,7 @@ FUNC(LS_Thing_SpawnFacing) } FUNC(LS_Thing_SetGoal) -// Thing_SetGoal (tid, goal, delay) +// Thing_SetGoal (tid, goal, delay, chasegoal) { TActorIterator selfiterator (arg0); TActorIterator goaliterator (arg1); @@ -1324,8 +1324,12 @@ FUNC(LS_Thing_SetGoal) if (self->flags & MF_SHOOTABLE) { self->goal = goal; - if (!self->target) + if (arg3 == 0) self->flags5 &=~ MF5_CHASEGOAL; + else self->flags |= MF5_CHASEGOAL; + if (self->target == NULL) + { self->reactiontime = arg2 * TICRATE; + } } } diff --git a/src/p_map.cpp b/src/p_map.cpp index 9e13ec0b9..60e4e6e23 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -1049,7 +1049,7 @@ BOOL PIT_CheckThing (AActor *thing) if (damage > 0) { P_DamageMobj (thing, tmthing, tmthing->target, damage, tmthing->DamageType); - if (gameinfo.gametype != GAME_Doom && + if ((tmthing->flags5 & MF5_BLOODSPLATTER) && !(thing->flags & MF_NOBLOOD) && !(thing->flags2 & MF2_REFLECTIVE) && !(thing->flags2 & (MF2_INVULNERABLE|MF2_DORMANT)) && @@ -2746,9 +2746,11 @@ void P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } else { - bool axeBlood; + bool bloodsplatter = (t1->flags5 & MF5_BLOODSPLATTER) || + (t1->player != NULL && t1->player->ReadyWeapon != NULL && + (t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD)); - axeBlood = (t1->player != NULL && + bool axeBlood = (t1->player != NULL && t1->player->ReadyWeapon != NULL && (t1->player->ReadyWeapon->WeaponFlags & WIF_AXEBLOOD)); @@ -2767,7 +2769,7 @@ void P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, } if (!(GetDefaultByType(pufftype)->flags3&MF3_BLOODLESSIMPACT)) { - if ((gameinfo.gametype & (GAME_DoomStrife)) && !axeBlood && + if (!bloodsplatter && !axeBlood && !(trace.Actor->flags & MF_NOBLOOD) && !(trace.Actor->flags2 & (MF2_INVULNERABLE|MF2_DORMANT))) { @@ -2776,7 +2778,7 @@ void P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, if (damage) { - if ((gameinfo.gametype&GAME_Raven) || axeBlood) + if (bloodsplatter || axeBlood) { if (!(trace.Actor->flags&MF_NOBLOOD) && !(trace.Actor->flags2&(MF2_INVULNERABLE|MF2_DORMANT))) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 7f7efde0e..72c165fa9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3925,12 +3925,12 @@ class ABloodSplatter : public AActor FState ABloodSplatter::States[] = { #define S_BLOODSPLATTER 0 - S_NORMAL (BLOD, 'C', 8, NULL, &States[S_BLOODSPLATTER+1]), - S_NORMAL (BLOD, 'B', 8, NULL, &States[S_BLOODSPLATTER+2]), - S_NORMAL (BLOD, 'A', 8, NULL, NULL), + S_NORMAL (BLUD, 'C', 8, NULL, &States[S_BLOODSPLATTER+1]), + S_NORMAL (BLUD, 'B', 8, NULL, &States[S_BLOODSPLATTER+2]), + S_NORMAL (BLUD, 'A', 8, NULL, NULL), #define S_BLOODSPLATTERX (S_BLOODSPLATTER+3) - S_NORMAL (BLOD, 'A', 6, NULL, NULL) + S_NORMAL (BLUD, 'A', 6, NULL, NULL) }; IMPLEMENT_ACTOR (ABloodSplatter, Raven, -1, 0) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index aec9d6bbe..bf64184e1 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -26,6 +26,7 @@ #include "p_effect.h" #include "a_doomglobal.h" #include "templates.h" +#include "thingdef.h" // MACROS ------------------------------------------------------------------ @@ -743,6 +744,16 @@ void A_Light2 (AActor *actor) } } +void A_Light (AActor *actor) +{ + int index=CheckIndex(1, &CallingState); + + if (actor->player != NULL && index > 0) + { + actor->player->extralight = clamp(EvalExpressionI (StateParameters[index], actor), 0, 20); + } +} + //------------------------------------------------------------------------ // // PROC P_SetupPsprites diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 904035dc7..d7a9a64f4 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -591,9 +591,14 @@ static void S_ClearSoundData() void S_ParseSndInfo () { + static bool termdone=false; int lump; - atterm (S_ClearSoundData); + if (!termdone) + { + termdone=true; + atterm (S_ClearSoundData); + } S_ClearSoundData(); // remove old sound data first! CurrentPitchMask = 0; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index cff5119ba..d39be3f2e 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -279,11 +279,16 @@ void S_AddLocalSndInfo(int lump); void S_Init () { + static bool termdone=false; int i; int curvelump; Printf ("S_Init\n"); - atterm (S_Shutdown); + if (!termdone) + { + termdone=true; + atterm (S_Shutdown); + } // remove old data (S_Init can be called multiple times!) LastLocalSndInfo = LastLocalSndSeq = ""; diff --git a/src/thingdef.cpp b/src/thingdef.cpp index 5248297e0..0a6640753 100644 --- a/src/thingdef.cpp +++ b/src/thingdef.cpp @@ -215,6 +215,7 @@ static flagdef ActorFlags[]= DEFINE_FLAG(MF5, BOUNCEONACTORS, AActor, flags5), DEFINE_FLAG(MF5, EXPLODEONWATER, AActor, flags5), DEFINE_FLAG(MF5, NODAMAGE, AActor, flags5), + DEFINE_FLAG(MF5, BLOODSPLATTER, AActor, flags5), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), @@ -496,6 +497,7 @@ ACTOR(TakeFromTarget) ACTOR(JumpIfInTargetInventory) ACTOR(CountdownArg) ACTOR(CustomMeleeAttack) +ACTOR(Light) #include "d_dehackedactions.h" @@ -622,6 +624,7 @@ AFuncDesc AFTable[]= // Only selected original weapon functions will be available. // All the attack pointers are somewhat tricky due to the way the flash state is handled + FUNC(A_Light, "X") FUNC(A_Light0, NULL) FUNC(A_Light1, NULL) FUNC(A_Light2, NULL) @@ -2962,6 +2965,7 @@ static void ActorProjectile (AActor *defaults, Baggage &bag) // sets the standard flags for a projectile defaults->flags|=MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE; defaults->flags2|=MF2_IMPACT|MF2_PCROSS|MF2_NOTELEPORT; + if (gameinfo.gametype&GAME_Raven) defaults->flags5|=MF5_BLOODSPLATTER; } //========================================================================== diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 09c44b232..416a4807f 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -1310,6 +1310,16 @@ void FWadCollection::RenameSprites (int startlump) } } } + + // When not playing Doom rename all BLOD sprites to BLUD so that + // the same blood states can be used everywhere + if (gameinfo.gametype != GAME_Doom) + { + if (*(DWORD *)LumpInfo[i].name == MAKE_ID('B', 'L', 'O', 'D')) + { + *(DWORD *)LumpInfo[i].name = MAKE_ID('B', 'L', 'U', 'D'); + } + } } }