diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 4a17236ac..fb1f23ac3 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,18 @@ -May 27, 2009 +May 30, 2009 (Changes by Graf Zahl) +- Added 'EndTitle' nextmap option which goes to the regular title loop after + the game has finished. +- Added NOBOSSRIP flag. Note: we are now at flags6! +- Added SetSkyScrollSpeed(int skyplane, fixed speed) ACS function. +- Added THRUACTORS flag that disables all actor<->actor collision detection. +- Added DONTSEEKINVISIBLE flag for missiles that can't home in on invisible + targets. +- Added SFX_TRANSFERPITCH flag to A_SpawnItemEx. +- Added Ultimate Freedoom IWAD detection. +- Added GetAirSupply and SetAirSupply functions to ACS. +- Fixed: The *surface sound was not played when drowning was switched off + by setting the level's air supply to 0. + +May 27, 2009 - Fixed: The mouse wheel generated no events in GUI mode if you weren't fullscreen. (e.g. You could no longer scroll the console with the mouse buffer.) diff --git a/src/actor.h b/src/actor.h index 1fc6f6394..6069539e7 100644 --- a/src/actor.h +++ b/src/actor.h @@ -155,7 +155,7 @@ enum MF2_DONTREFLECT = 0x00000001, // this projectile cannot be reflected MF2_WINDTHRUST = 0x00000002, // gets pushed around by the wind specials - //MF2_BOUNCE1 = 0x00000004, + MF2_DONTSEEKINVISIBLE=0x00000004, // For seeker missiles: Don't home in on invisible/shadow targets MF2_BLASTED = 0x00000008, // actor will temporarily take damage from impact MF2_FLY = 0x00000010, // fly mode is active MF2_FLOORCLIP = 0x00000020, // if feet are allowed to be clipped @@ -176,7 +176,7 @@ enum MF2_NODMGTHRUST = 0x00020000, // does not thrust target when damaging MF2_TELESTOMP = 0x00040000, // mobj can stomp another MF2_FLOATBOB = 0x00080000, // use float bobbing z movement - //MF2_BOUNCE2 = 0x00100000, + MF2_THRUACTORS = 0x00100000, // performs no actor<->actor collision checks MF2_IMPACT = 0x00200000, // an MF_MISSILE mobj can activate SPAC_IMPACT MF2_PUSHWALL = 0x00400000, // mobj can push walls MF2_MCROSS = 0x00800000, // can activate monster cross lines @@ -304,6 +304,8 @@ enum MF5_PAINLESS = 0x40000000, // Actor always inflicts painless damage. MF5_MOVEWITHSECTOR = 0x80000000, // P_ChangeSector() will still process this actor if it has MF_NOBLOCKMAP + MF6_NOBOSSRIP = 0x00000001, // For rippermissiles: Don't rip through bosses. + // --- mobj.renderflags --- @@ -646,6 +648,8 @@ public: // Calculate amount of missile damage virtual int GetMissileDamage(int mask, int add); + bool CanSeek(AActor *target) const; + // info for drawing // NOTE: The first member variable *must* be x. fixed_t x,y,z; @@ -683,6 +687,7 @@ public: DWORD flags3; // [RH] Hexen/Heretic actor-dependant behavior made flaggable DWORD flags4; // [RH] Even more flags! DWORD flags5; // OMG! We need another one. + DWORD flags6; // Shit! Where did all the flags go? int special1; // Special info int special2; // Special info int health; diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 16032457a..1f5529532 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -71,7 +71,8 @@ const IWADInfo IWADInfos[NUM_IWAD_TYPES] = { "Strife: Teaser (Old Version)", NULL, MAKERGB(224,173,153), MAKERGB(0,107,101), GAME_Strife, "mapinfo/strife.txt", GI_MAPxx | GI_SHAREWARE }, { "Strife: Teaser (New Version)", NULL, MAKERGB(224,173,153), MAKERGB(0,107,101), GAME_Strife, "mapinfo/strife.txt", GI_MAPxx | GI_SHAREWARE | GI_TEASER2 }, { "Freedoom", "Freedoom", MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx }, - { "Freedoom \"Demo\"", "Freedoom1",MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom1.txt" }, + { "Ultimate Freedoom", "Freedoom1",MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom1.txt" }, + { "Freedoom \"Demo\"", NULL, MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom1.txt" }, { "FreeDM", "FreeDM", MAKERGB(50,84,67), MAKERGB(198,220,209), GAME_Doom, "mapinfo/doom2.txt", GI_MAPxx }, { "Chex(R) Quest", "Chex1", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex.txt" }, { "Chex(R) Quest 3", "Chex3", MAKERGB(255,255,0), MAKERGB(0,192,0), GAME_Chex, "mapinfo/chex3.txt" }, @@ -98,6 +99,7 @@ static const char *IWADNames[] = "strife0.wad", "freedoom.wad", // Freedoom.wad is distributed as Doom2.wad, but this allows to have both in the same directory. "freedoom1.wad", + "freedoomu.wad", "freedm.wad", "chex.wad", "chex3.wad", @@ -117,6 +119,7 @@ static const char *IWADNames[] = "STRIFE0.WAD", "FREEDOOM.WAD", "FREEDOOM1.WAD", + "FREEDOOMU.WAD", "FREEDM.WAD", "CHEX.WAD", "CHEX3.WAD", @@ -211,59 +214,7 @@ static EIWADType ScanIWAD (const char *iwad) } } } -#if 0 - else if (header.Magic == ZIP_ID) - { // Using a zip as an IWAD replacement requires that the key lumps be in the global scope. - // This is because most of them will be "Custom IWADs" so all that we really should need - // to find is GAMEINFO, but why limit ourselves? - header.NumLumps = 0; - FileReader *reader = new FileReader(f); - DWORD centraldir = Zip_FindCentralDir(reader); - delete reader; - if (fseek(f, centraldir, SEEK_SET) == 0) - { - // First locate directory - FZipEndOfCentralDirectory directory; - if (0 != fread(&directory, sizeof(directory), 1, f) && LittleLong(directory.Magic) == 0x06054b50) - { - header.NumLumps += LittleLong(directory.NumEntries); - if (fseek(f, LittleLong(directory.DirectoryOffset), SEEK_SET) == 0) - { - // Scan directory for lumps in the global scope with key names. - do - { - FZipCentralDirectoryInfo entry; - if (0 == fread(&entry, sizeof(entry), 1, f)) - break; - if (LittleLong(entry.Magic) == 0x02014b50) - { - // Now determine the lump's short name - char* fullname = new char[LittleLong(entry.NameLength)]; - if (0 == fread(fullname, LittleLong(entry.NameLength), 1, f)) - { - delete[] fullname; - break; - } - FString name = fullname; - delete[] fullname; - - if(name.LastIndexOf('/') != -1) - continue; - name.Truncate(name.LastIndexOf('.')); - - for (size_t j = 0; j < NUM_CHECKLUMPS; j++) - if (strnicmp (name, checklumps[j], 8) == 0) - lumpsfound[j]++; - } - else - break; - } - while(true); - } - } - } - } -#endif + fclose (f); } @@ -369,7 +320,14 @@ static EIWADType ScanIWAD (const char *iwad) { if (lumpsfound[Check_FreeDoom]) { - return IWAD_FreeDoom1; + if (!lumpsfound[Check_e2m1]) + { + return IWAD_FreeDoom1; + } + else + { + return IWAD_FreeDoomU; + } } for (i = Check_e2m1; i < NUM_CHECKLUMPS; i++) { diff --git a/src/d_main.h b/src/d_main.h index 3ef536ab4..a577a5d4f 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -74,6 +74,7 @@ enum EIWADType IWAD_StrifeTeaser, IWAD_StrifeTeaser2, IWAD_FreeDoom, + IWAD_FreeDoomU, IWAD_FreeDoom1, IWAD_FreeDM, IWAD_ChexQuest, diff --git a/src/f_finale.cpp b/src/f_finale.cpp index 23da56625..5e1fa04cd 100644 --- a/src/f_finale.cpp +++ b/src/f_finale.cpp @@ -49,6 +49,7 @@ #include "g_level.h" #include "d_event.h" #include "v_palette.h" +#include "d_main.h" static void FadePic (); static void GetFinaleText (const char *msgLumpName); @@ -1277,6 +1278,9 @@ void F_Drawer (void) case END_Demon: F_DemonScroll (); break; + case END_TitleScreen: + D_StartTitle (); + break; } break; diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 6f021d754..397f0ce58 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -73,7 +73,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer) // adjust direction dest = self->tracer; - if (!dest || dest->health <= 0 || self->Speed == 0 || (dest->flags5 & MF5_CANTSEEK)) + if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest)) return; // change angle diff --git a/src/g_level.h b/src/g_level.h index 6bb7260d1..850b59220 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -414,7 +414,8 @@ enum EndTypes END_Underwater, END_Chess, END_Strife, - END_BuyStrife + END_BuyStrife, + END_TitleScreen }; struct EndSequence diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index e95d59a38..d0237cfc0 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -892,6 +892,11 @@ void FMapInfoParser::ParseNextMap(char *mapname) newSeq.EndType = END_BuyStrife; useseq = true; } + else if (sc.Compare("endtitle")) + { + newSeq.EndType = END_TitleScreen; + useseq = true; + } else { strncpy (mapname, sc.String, 8); diff --git a/src/g_strife/a_spectral.cpp b/src/g_strife/a_spectral.cpp index 92b8305fc..10efceffc 100644 --- a/src/g_strife/a_spectral.cpp +++ b/src/g_strife/a_spectral.cpp @@ -91,7 +91,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Tracer2) dest = self->tracer; - if (!dest || dest->health <= 0 || self->Speed == 0 || (dest->flags5 & MF5_CANTSEEK)) + if (!dest || dest->health <= 0 || self->Speed == 0 || !self->CanSeek(dest)) return; // change angle diff --git a/src/p_acs.cpp b/src/p_acs.cpp index dca81de06..f02a2f5e1 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2796,6 +2796,9 @@ enum EACSFunctions ACSF_SetActivatorToTarget, ACSF_GetActorViewHeight, ACSF_GetChar, + ACSF_GetAirSupply, + ACSF_SetAirSupply, + ACSF_SetSkyScrollSpeed, }; int DLevelScript::SideFromID(int id, int side) @@ -2907,6 +2910,37 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) } } + case ACSF_GetAirSupply: + { + if (args[0] < 0 || args[0] >= MAXPLAYERS || !playeringame[args[0]]) + { + return 0; + } + else + { + return players[args[0]].air_finished - level.time; + } + } + + case ACSF_SetAirSupply: + { + if (args[0] < 0 || args[0] >= MAXPLAYERS || !playeringame[args[0]]) + { + return 0; + } + else + { + players[args[0]].air_finished = args[1] + level.time; + return 1; + } + } + + case ACSF_SetSkyScrollSpeed: + { + if (args[0] == 1) level.skyspeed1 = FIXED2FLOAT(args[1]); + else if (args[0] == 2) level.skyspeed2 = FIXED2FLOAT(args[1]); + return 1; + } default: break; diff --git a/src/p_map.cpp b/src/p_map.cpp index 2746fb982..3669d61f0 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -752,6 +752,9 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) if (thing == tm.thing) return true; + if ((thing->flags2 | tm.thing->flags2) & MF2_THRUACTORS) + return true; + if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)) ) return true; // can't hit thing @@ -967,32 +970,35 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm) } if (tm.DoRipping && !(thing->flags5 & MF5_DONTRIP)) { - if (tm.LastRipped != thing) + if (!(tm.thing->flags6 & MF6_NOBOSSRIP) || !(thing->flags2 & MF2_BOSS)) { - tm.LastRipped = thing; - if (!(thing->flags & MF_NOBLOOD) && - !(thing->flags2 & MF2_REFLECTIVE) && - !(tm.thing->flags3 & MF3_BLOODLESSIMPACT) && - !(thing->flags2 & (MF2_INVULNERABLE|MF2_DORMANT))) - { // Ok to spawn blood - P_RipperBlood (tm.thing, thing); - } - S_Sound (tm.thing, CHAN_BODY, "misc/ripslop", 1, ATTN_IDLE); - damage = tm.thing->GetMissileDamage (3, 2); - P_DamageMobj (thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); - if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) + if (tm.LastRipped != thing) { - P_TraceBleed (damage, thing, tm.thing); - } - if (thing->flags2 & MF2_PUSHABLE - && !(tm.thing->flags2 & MF2_CANNOTPUSH)) - { // Push thing - thing->momx += tm.thing->momx>>2; - thing->momy += tm.thing->momy>>2; + tm.LastRipped = thing; + if (!(thing->flags & MF_NOBLOOD) && + !(thing->flags2 & MF2_REFLECTIVE) && + !(tm.thing->flags3 & MF3_BLOODLESSIMPACT) && + !(thing->flags2 & (MF2_INVULNERABLE|MF2_DORMANT))) + { // Ok to spawn blood + P_RipperBlood (tm.thing, thing); + } + S_Sound (tm.thing, CHAN_BODY, "misc/ripslop", 1, ATTN_IDLE); + damage = tm.thing->GetMissileDamage (3, 2); + P_DamageMobj (thing, tm.thing, tm.thing->target, damage, tm.thing->DamageType); + if (!(tm.thing->flags3 & MF3_BLOODLESSIMPACT)) + { + P_TraceBleed (damage, thing, tm.thing); + } + if (thing->flags2 & MF2_PUSHABLE + && !(tm.thing->flags2 & MF2_CANNOTPUSH)) + { // Push thing + thing->momx += tm.thing->momx>>2; + thing->momy += tm.thing->momy>>2; + } } + spechit.Clear (); + return true; } - spechit.Clear (); - return true; } // Do damage damage = tm.thing->GetMissileDamage ((tm.thing->flags4 & MF4_STRIFEDAMAGE) ? 3 : 7, 1); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index bc7f90ed1..9eb2286de 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -233,6 +233,7 @@ void AActor::Serialize (FArchive &arc) << flags3 << flags4 << flags5 + << flags6 << special1 << special2 << health @@ -1403,6 +1404,26 @@ int P_FaceMobj (AActor *source, AActor *target, angle_t *delta) } } +//---------------------------------------------------------------------------- +// +// CanSeek +// +// Checks if a seeker missile can home in on its target +// +//---------------------------------------------------------------------------- + +bool AActor::CanSeek(AActor *target) const +{ + if (target->flags5 & MF5_CANTSEEK) return false; + if ((flags2 & MF2_DONTSEEKINVISIBLE) && + ((target->flags & MF_SHADOW) || + target->renderflags & RF_INVISIBLE || + target->RenderStyle.IsVisible(target->alpha) + ) + ) return false; + return true; +} + //---------------------------------------------------------------------------- // // FUNC P_SeekerMissile @@ -1421,7 +1442,7 @@ bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax) AActor *target; target = actor->tracer; - if (target == NULL || actor->Speed == 0 || (target->flags5 & MF5_CANTSEEK)) + if (target == NULL || actor->Speed == 0 || !actor->CanSeek(target)) { return false; } diff --git a/src/p_user.cpp b/src/p_user.cpp index e1149b002..6d8f7ace4 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -965,7 +965,8 @@ bool APlayerPawn::ResetAirSupply (bool playgasp) { S_Sound (this, CHAN_VOICE, "*gasp", 1, ATTN_NORM); } - player->air_finished = level.time + level.airsupply; + if (level.airsupply> 0) player->air_finished = level.time + level.airsupply; + else player->air_finished = INT_MAX; return wasdrowning; } @@ -2330,7 +2331,7 @@ void P_PlayerThink (player_t *player) } // Handle air supply - if (level.airsupply > 0) + //if (level.airsupply > 0) { if (player->mo->waterlevel < 3 || (player->mo->flags2 & MF2_INVULNERABLE) || diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d25af05dc..aad3b29ba 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1296,6 +1296,7 @@ enum SIX_Flags SIXF_TELEFRAG=64, // 128 is used by Skulltag! SIXF_TRANSFERAMBUSHFLAG=256, + SIXF_TRANSFERPITCH=512, }; @@ -1311,6 +1312,7 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) } mo->angle=self->angle; + if (flags & SIXF_TRANSFERPITCH) mo->pitch = self->pitch; while (originator && isMissile(originator)) originator = originator->target; if (flags & SIXF_TELEFRAG) diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index b5e623c22..c6b03fee4 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -94,6 +94,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF, ICECORPSE, AActor, flags), DEFINE_FLAG(MF2, DONTREFLECT, AActor, flags2), DEFINE_FLAG(MF2, WINDTHRUST, AActor, flags2), + DEFINE_FLAG(MF2, DONTSEEKINVISIBLE, AActor, flags2), DEFINE_FLAG(MF2, BLASTED, AActor, flags2), DEFINE_FLAG(MF2, FLOORCLIP, AActor, flags2), DEFINE_FLAG(MF2, SPAWNFLOAT, AActor, flags2), @@ -109,6 +110,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF2, DONTTRANSLATE, AActor, flags2), DEFINE_FLAG(MF2, TELESTOMP, AActor, flags2), DEFINE_FLAG(MF2, FLOATBOB, AActor, flags2), + DEFINE_FLAG(MF2, THRUACTORS, AActor, flags2), DEFINE_FLAG2(MF2_IMPACT, ACTIVATEIMPACT, AActor, flags2), DEFINE_FLAG2(MF2_PUSHWALL, CANPUSHWALLS, AActor, flags2), DEFINE_FLAG2(MF2_MCROSS, ACTIVATEMCROSS, AActor, flags2), @@ -207,6 +209,8 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF5, PAINLESS, AActor, flags5), DEFINE_FLAG(MF5, MOVEWITHSECTOR, AActor, flags5), + DEFINE_FLAG(MF6, NOBOSSRIP, AActor, flags6), + // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), DEFINE_FLAG2(FX_ROCKET, ROCKETTRAIL, AActor, effects), diff --git a/src/version.h b/src/version.h index 6c379af2e..999d2446a 100644 --- a/src/version.h +++ b/src/version.h @@ -75,7 +75,7 @@ // SAVESIG should match SAVEVER. // MINSAVEVER is the minimum level snapshot version that can be loaded. -#define MINSAVEVER 1599 +#define MINSAVEVER 1619 #if SVN_REVISION_NUMBER < MINSAVEVER // Never write a savegame with a version lower than what we need diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index f131e64d5..97f5c3068 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -15,6 +15,7 @@ const int SXF_NOCHECKPOSITION = 32; const int SXF_TELEFRAG=64; const int SXF_CLIENTSPAWN=128; // only used by Skulltag const int SXF_TRANSFERAMBUSHFLAG=256; +const int SXF_TRANSFERPITCH=512; // Flags for A_Chase const int CHF_FASTCHASE = 1;