diff --git a/gzdoom.vcproj b/gzdoom.vcproj index 14b44a90..09fe322b 100644 --- a/gzdoom.vcproj +++ b/gzdoom.vcproj @@ -2312,10 +2312,6 @@ - - @@ -2436,6 +2432,14 @@ + + + + diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index fef3fa99..6c2fde91 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -1,5 +1,5 @@ =============================================================================== -Universal Doom Map Format ZDoom extensions v1.10 - 25.04.2010 +Universal Doom Map Format ZDoom extensions v1.15 - 14.12.2010 Copyright (c) 2008 Christoph Oelckers. @@ -84,6 +84,12 @@ field to 'strifeally', even for the 'Doom' namespace. In addition to the standard fields, ZDoom defines the following: Note: All fields default to false unless mentioned otherwise. + vertex + { + zfloor = ; // Floor height at this vertex. Only applies to triangular sectors + zceiling = ; // Ceiling height at this vertex. Only applies to triangular sectors + } + linedef { alpha = ; // Translucency of this line, default is 1.0 @@ -153,6 +159,8 @@ Note: All fields default to false unless mentioned otherwise. // relative to the owning sector's light level. lightceilingabsolute = ; // true = 'lightceiling' is an absolute value. Default is // relative to the owning sector's light level. + alphafloor = ; // translucency of floor plane (only has meaning with Sector_SetPortal) Default is 1.0. + alphaceiling = ; // translucency of ceiling plane (only has meaning with Sector_SetPortal) Default is 1.0. gravity = ; // Sector's gravity. Default is 1.0. lightcolor = ; // Sector'S light color as RRGGBB value, default = 0xffffff. fadecolor = ; // Sector'S fog color as RRGGBB value, default = 0x000000. @@ -281,6 +289,9 @@ Added 'hidden' sector property. 1.14 19.09.2010 Added 'countsecret' actor property. +1.15 14.12.2010 +Added vertex floor and ceiling height properties + =============================================================================== EOF =============================================================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 14fe2473..31b92c8c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -396,8 +396,7 @@ endif( SSE_MATTERS ) if( CMAKE_COMPILER_IS_GNUCXX ) if( PROFILE ) - set( CMAKE_C_FLinclude( FindFluidSynth.cmake ) -AGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) + set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" ) set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" ) set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" ) @@ -727,7 +726,6 @@ add_executable( zdoom WIN32 p_xlat.cpp parsecontext.cpp po_man.cpp - r_anim.cpp r_bsp.cpp r_data.cpp r_draw.cpp @@ -911,6 +909,8 @@ add_executable( zdoom WIN32 sound/music_timidity_mididevice.cpp sound/music_win_mididevice.cpp sound/music_pseudo_mididevice.cpp + textures/animations.cpp + textures/anim_switches.cpp textures/automaptexture.cpp textures/bitmap.cpp textures/buildtexture.cpp diff --git a/src/actor.h b/src/actor.h index 635198b4..35d40112 100644 --- a/src/actor.h +++ b/src/actor.h @@ -529,7 +529,12 @@ struct FDropItem class FDropItemPtrArray : public TArray { public: - ~FDropItemPtrArray(); + ~FDropItemPtrArray() + { + Clear(); + } + + void Clear(); }; extern FDropItemPtrArray DropItemList; diff --git a/src/am_map.cpp b/src/am_map.cpp index 45cb3f98..7c709019 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -64,6 +64,12 @@ #include "po_man.h" #include "a_keys.h" +//============================================================================= +// +// Automap colors +// +//============================================================================= + struct AMColor { int Index; @@ -85,7 +91,7 @@ struct AMColor static AMColor Background, YourColor, WallColor, TSWallColor, FDWallColor, CDWallColor, ThingColor, ThingColor_Item, ThingColor_CountItem, ThingColor_Monster, ThingColor_Friend, - SecretWallColor, GridColor, XHairColor, + SpecialWallColor, SecretWallColor, GridColor, XHairColor, NotSeenColor, LockedColor, AlmostBackground, @@ -119,6 +125,12 @@ static BYTE RavenPaletteVals[11*3] = 0, 0, 0, 0, 0, 0, }; +//============================================================================= +// +// globals +// +//============================================================================= + #define MAPBITS 12 #define MapDiv SafeDivScale12 #define MapMul MulScale12 @@ -155,6 +167,7 @@ CVAR (Color, am_backcolor, 0x6c5440, CVAR_ARCHIVE); CVAR (Color, am_yourcolor, 0xfce8d8, CVAR_ARCHIVE); CVAR (Color, am_wallcolor, 0x2c1808, CVAR_ARCHIVE); CVAR (Color, am_secretwallcolor, 0x000000, CVAR_ARCHIVE); +CVAR (Color, am_specialwallcolor, 0xffffff, CVAR_ARCHIVE); CVAR (Color, am_tswallcolor, 0x888888, CVAR_ARCHIVE); CVAR (Color, am_fdwallcolor, 0x887058, CVAR_ARCHIVE); CVAR (Color, am_cdwallcolor, 0x4c3820, CVAR_ARCHIVE); @@ -165,6 +178,7 @@ CVAR (Color, am_notseencolor, 0x6c6c6c, CVAR_ARCHIVE); CVAR (Color, am_lockedcolor, 0x007800, CVAR_ARCHIVE); CVAR (Color, am_ovyourcolor, 0xfce8d8, CVAR_ARCHIVE); CVAR (Color, am_ovwallcolor, 0x00ff00, CVAR_ARCHIVE); +CVAR (Color, am_ovspecialwallcolor, 0xffffff, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovotherwallscolor, 0x008844, CVAR_ARCHIVE); CVAR (Color, am_ovunseencolor, 0x00226e, CVAR_ARCHIVE); @@ -176,6 +190,7 @@ CVAR (Color, am_ovsecretsectorcolor,0x00ffff, CVAR_ARCHIVE); CVAR (Int, am_map_secrets, 1, CVAR_ARCHIVE); CVAR (Bool, am_drawmapback, true, CVAR_ARCHIVE); CVAR (Bool, am_showkeys, true, CVAR_ARCHIVE); +CVAR (Bool, am_showtriggerlines, false, CVAR_ARCHIVE); CVAR (Color, am_thingcolor_friend, 0xfcfcfc, CVAR_ARCHIVE); CVAR (Color, am_thingcolor_monster, 0xfcfcfc, CVAR_ARCHIVE); CVAR (Color, am_thingcolor_item, 0xfcfcfc, CVAR_ARCHIVE); @@ -287,72 +302,28 @@ struct islope_t // A line drawing of the player pointing right, // starting from the middle. // -#define R ((8*PLAYERRADIUS)/7) -mline_t player_arrow[] = { - { { -R+R/8, 0 }, { R, 0 } }, // ----- - { { R, 0 }, { R-R/2, R/4 } }, // -----> - { { R, 0 }, { R-R/2, -R/4 } }, - { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >----> - { { -R+R/8, 0 }, { -R-R/8, -R/4 } }, - { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>---> - { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } } -}; -#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t)) - -mline_t player_arrow_raven[] = { - { { -R+R/4, 0 }, { 0, 0} }, // center line. - { { -R+R/4, R/8 }, { R, 0} }, // blade - { { -R+R/4, -R/8 }, { R, 0 } }, - { { -R+R/4, -R/4 }, { -R+R/4, R/4 } }, // crosspiece - { { -R+R/8, -R/4 }, { -R+R/8, R/4 } }, - { { -R+R/8, -R/4 }, { -R+R/4, -R/4} }, //crosspiece connectors - { { -R+R/8, R/4 }, { -R+R/4, R/4} }, - { { -R-R/4, R/8 }, { -R-R/4, -R/8 } }, //pommel - { { -R-R/4, R/8 }, { -R+R/8, R/8 } }, - { { -R-R/4, -R/8}, { -R+R/8, -R/8 } } -}; -#define NUMPLYRLINES_RAVEN (sizeof(player_arrow_raven)/sizeof(mline_t)) - -mline_t cheat_player_arrow[] = { - { { -R+R/8, 0 }, { R, 0 } }, // ----- - { { R, 0 }, { R-R/2, R/6 } }, // -----> - { { R, 0 }, { R-R/2, -R/6 } }, - { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >-----> - { { -R+R/8, 0 }, { -R-R/8, -R/6 } }, - { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>-----> - { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } }, - { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d---> - { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } }, - { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } }, - { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd--> - { { -R/6, -R/6 }, { 0, -R/6 } }, - { { 0, -R/6 }, { 0, R/4 } }, - { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt-> - { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } }, - { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } } -}; -#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t)) - -#undef R +static TArray MapArrow; +static TArray CheatMapArrow; +static TArray CheatKey; #define R (MAPUNIT) // [RH] Avoid lots of warnings without compiler-specific #pragmas #define L(a,b,c,d) { {(fixed_t)((a)*R),(fixed_t)((b)*R)}, {(fixed_t)((c)*R),(fixed_t)((d)*R)} } -mline_t triangle_guy[] = { +static mline_t triangle_guy[] = { L (-.867,-.5, .867,-.5), L (.867,-.5, 0,1), L (0,1, -.867,-.5) }; #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t)) -mline_t thintriangle_guy[] = { +static mline_t thintriangle_guy[] = { L (-.5,-.7, 1,0), L (1,0, -.5,.7), L (-.5,.7, -.5,-.7) }; #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t)) -mline_t square_guy[] = { +static mline_t square_guy[] = { L (0,1,1,0), L (1,0,0,-1), L (0,-1,-1,0), @@ -361,26 +332,6 @@ mline_t square_guy[] = { #define NUMSQUAREGUYLINES (sizeof(square_guy)/sizeof(mline_t)) #undef R -#define R (MAPUNIT) - -mline_t key_guy[] = { - L (-2, 0, -1.7, -0.5), - L (-1.7, -0.5, -1.5, -0.7), - L (-1.5, -0.7, -0.8, -0.5), - L (-0.8, -0.5, -0.6, 0), - L (-0.6, 0, -0.8, 0.5), - L (-1.5, 0.7, -0.8, 0.5), - L (-1.7, 0.5, -1.5, 0.7), - L (-2, 0, -1.7, 0.5), - L (-0.6, 0, 2, 0), - L (1.7, 0, 1.7, -1), - L (1.5, 0, 1.5, -1), - L (1.3, 0, 1.3, -1) -}; -#define NUMKEYGUYLINES (sizeof(key_guy)/sizeof(mline_t)) - -#undef L -#undef R @@ -396,8 +347,6 @@ CUSTOM_CVAR (Int, am_cheat, 0, 0) static int grid = 0; -static int leveljuststarted = 1; // kluge until AM_LevelInit() is called - bool automapactive = false; // location of window on screen @@ -449,8 +398,6 @@ static FTextureID marknums[10]; // numbers used for marking by the automap static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are static int markpointnum = 0; // next point to be assigned -static int followplayer = 1; // specifies whether to follow the player around - static FTextureID mapback; // the automap background static fixed_t mapystart=0; // y-value for the start of the map bitmap...used in the parallax stuff. static fixed_t mapxstart=0; //x-value for the bitmap. @@ -476,11 +423,14 @@ void AM_restoreScaleAndLoc (); void AM_minOutWindowScale (); +CVAR(Bool, am_followplayer, true, CVAR_ARCHIVE) + + CCMD(am_togglefollow) { - followplayer = !followplayer; + am_followplayer = !am_followplayer; f_oldloc.x = FIXED_MAX; - Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF")); + Printf ("%s\n", GStrings(am_followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF")); } CCMD(am_togglegrid) @@ -545,6 +495,76 @@ void AM_getIslope (mline_t *ml, islope_t *is) } */ + +void AM_ParseArrow(TArray &Arrow, const char *lumpname) +{ + const int R = ((8*PLAYERRADIUS)/7); + FScanner sc; + int lump = Wads.CheckNumForFullName(lumpname, true); + if (lump >= 0) + { + sc.OpenLumpNum(lump); + sc.SetCMode(true); + while (sc.GetToken()) + { + mline_t line; + sc.TokenMustBe('('); + sc.MustGetFloat(); + line.a.x = xs_RoundToInt(sc.Float*R); + sc.MustGetToken(','); + sc.MustGetFloat(); + line.a.y = xs_RoundToInt(sc.Float*R); + sc.MustGetToken(')'); + sc.MustGetToken(','); + sc.MustGetToken('('); + sc.MustGetFloat(); + line.b.x = xs_RoundToInt(sc.Float*R); + sc.MustGetToken(','); + sc.MustGetFloat(); + line.b.y = xs_RoundToInt(sc.Float*R); + sc.MustGetToken(')'); + Arrow.Push(line); + } + } +} + +void AM_StaticInit() +{ + MapArrow.Clear(); + CheatMapArrow.Clear(); + CheatKey.Clear(); + + if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow); + if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow); + AM_ParseArrow(CheatKey, "maparrows/key.txt"); + if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined"); + + char namebuf[9]; + + for (int i = 0; i < 10; i++) + { + mysnprintf (namebuf, countof(namebuf), "AMMNUM%d", i); + marknums[i] = TexMan.CheckForTexture (namebuf, FTexture::TEX_MiscPatch); + } + markpointnum = 0; + mapback.SetInvalid(); + + static DWORD *lastpal = NULL; + //static int lastback = -1; + DWORD *palette; + + palette = (DWORD *)GPalette.BaseColors; + + int i, j; + + for (i = j = 0; i < 11; i++, j += 3) + { + DoomColors[i].FromRGB(DoomPaletteVals[j], DoomPaletteVals[j+1], DoomPaletteVals[j+2]); + StrifeColors[i].FromRGB(StrifePaletteVals[j], StrifePaletteVals[j+1], StrifePaletteVals[j+2]); + RavenColors[i].FromRGB(RavenPaletteVals[j], RavenPaletteVals[j+1], RavenPaletteVals[j+2]); + } +} + //============================================================================= // // called by the coordinate drawer @@ -599,7 +619,7 @@ void AM_restoreScaleAndLoc () { m_w = old_m_w; m_h = old_m_h; - if (!followplayer) + if (!am_followplayer) { m_x = old_m_x; m_y = old_m_y; @@ -796,7 +816,7 @@ void AM_changeWindowLoc () { if (0 != (m_paninc.x | m_paninc.y)) { - followplayer = 0; + am_followplayer = false; f_oldloc.x = FIXED_MAX; } @@ -876,28 +896,11 @@ void AM_initVariables () static void AM_initColors (bool overlayed) { - static DWORD *lastpal = NULL; - //static int lastback = -1; - DWORD *palette; - - palette = (DWORD *)GPalette.BaseColors; - - if (lastpal != palette) - { - int i, j; - - for (i = j = 0; i < 11; i++, j += 3) - { - DoomColors[i].FromRGB(DoomPaletteVals[j], DoomPaletteVals[j+1], DoomPaletteVals[j+2]); - StrifeColors[i].FromRGB(StrifePaletteVals[j], StrifePaletteVals[j+1], StrifePaletteVals[j+2]); - RavenColors[i].FromRGB(RavenPaletteVals[j], RavenPaletteVals[j+1], RavenPaletteVals[j+2]); - } - } - if (overlayed) { YourColor.FromCVar (am_ovyourcolor); WallColor.FromCVar (am_ovwallcolor); + SpecialWallColor.FromCVar(am_ovspecialwallcolor); SecretWallColor = WallColor; SecretSectorColor.FromCVar (am_ovsecretsectorcolor); ThingColor_Item.FromCVar (am_ovthingcolor_item); @@ -920,6 +923,7 @@ static void AM_initColors (bool overlayed) Background.FromCVar (am_backcolor); YourColor.FromCVar (am_yourcolor); SecretWallColor.FromCVar (am_secretwallcolor); + SpecialWallColor.FromCVar (am_specialwallcolor); WallColor.FromCVar (am_wallcolor); TSWallColor.FromCVar (am_tswallcolor); FDWallColor.FromCVar (am_fdwallcolor); @@ -961,6 +965,7 @@ static void AM_initColors (bool overlayed) AlmostBackground = DoomColors[2]; SecretSectorColor = SecretWallColor = + SpecialWallColor = WallColor = DoomColors[3]; TSWallColor = DoomColors[4]; FDWallColor = DoomColors[5]; @@ -982,6 +987,7 @@ static void AM_initColors (bool overlayed) AlmostBackground = DoomColors[2]; SecretSectorColor = SecretWallColor = + SpecialWallColor = WallColor = StrifeColors[3]; TSWallColor = StrifeColors[4]; FDWallColor = StrifeColors[5]; @@ -1003,6 +1009,7 @@ static void AM_initColors (bool overlayed) AlmostBackground = DoomColors[2]; SecretSectorColor = SecretWallColor = + SpecialWallColor = WallColor = RavenColors[3]; TSWallColor = RavenColors[4]; FDWallColor = RavenColors[5]; @@ -1018,30 +1025,6 @@ static void AM_initColors (bool overlayed) break; } - - lastpal = palette; -} - -//============================================================================= -// -// -// -//============================================================================= - -void AM_loadPics () -{ - int i; - char namebuf[9]; - - for (i = 0; i < 10; i++) - { - mysnprintf (namebuf, countof(namebuf), "AMMNUM%d", i); - marknums[i] = TexMan.CheckForTexture (namebuf, FTexture::TEX_MiscPatch); - } - - const char *autopage = level.info->mapbg[0] == 0? "AUTOPAGE" : (const char*)&level.info->mapbg[0]; - - mapback = TexMan.CheckForTexture(autopage, FTexture::TEX_MiscPatch); } //============================================================================= @@ -1066,7 +1049,8 @@ bool AM_clearMarks () void AM_LevelInit () { - leveljuststarted = 0; + const char *autopage = level.info->mapbg[0] == 0? "AUTOPAGE" : (const char*)&level.info->mapbg[0]; + mapback = TexMan.CheckForTexture(autopage, FTexture::TEX_MiscPatch); AM_clearMarks(); @@ -1104,7 +1088,6 @@ void AM_Start () if (!stopped) AM_Stop(); stopped = false; AM_initVariables(); - AM_loadPics(); } @@ -1216,7 +1199,7 @@ bool AM_Responder (event_t *ev, bool last) { if (automapactive && (ev->type == EV_KeyDown || ev->type == EV_KeyUp)) { - if (followplayer) + if (am_followplayer) { // check for am_pan* and ignore in follow mode const char *defbind = AutomapBindings.GetBind(ev->data1); @@ -1329,7 +1312,7 @@ void AM_Ticker () amclock++; - if (followplayer) + if (am_followplayer) { AM_doFollowPlayer(); } @@ -1549,7 +1532,7 @@ void AM_drawGrid (const AMColor &color) // [RH] Calculate a minimum for how long the grid lines should be so that // they cover the screen at any rotation. - minlen = (fixed_t)sqrtf ((float)m_w*(float)m_w + (float)m_h*(float)m_h); + minlen = (fixed_t)sqrt ((double)m_w*(double)m_w + (double)m_h*(double)m_h); extx = (minlen - m_w) / 2; exty = (minlen - m_h) / 2; @@ -1861,14 +1844,16 @@ void AM_drawWalls (bool allmap) else if (lines[i].special == Door_LockedRaise || lines[i].special == ACS_LockedExecute || lines[i].special == ACS_LockedExecuteDoor || - (lines[i].special == Generic_Door && lines[i].args[4] !=0 )) + (lines[i].special == Door_Animated && lines[i].args[3] != 0) || + (lines[i].special == Generic_Door && lines[i].args[4] != 0)) { if (am_colorset == 0 || am_colorset == 3) // Raven games show door colors { int P_GetMapColorForLock(int lock); int lock; - if (lines[i].special==Door_LockedRaise) lock=lines[i].args[3]; + if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated) + lock=lines[i].args[3]; else lock=lines[i].args[4]; int color = P_GetMapColorForLock(lock); @@ -1885,6 +1870,17 @@ void AM_drawWalls (bool allmap) AM_drawMline (&l, LockedColor); // locked special } } + else if (am_showtriggerlines && am_colorset == 0 && lines[i].special != 0 + && lines[i].special != Door_Open + && lines[i].special != Door_Close + && lines[i].special != Door_CloseWaitOpen + && lines[i].special != Door_Raise + && lines[i].special != Door_Animated + && lines[i].special != Generic_Door + && (lines[i].activation & SPAC_PlayerActivate)) + { + AM_drawMline(&l, SpecialWallColor); // wall with special non-door action the player can do + } else if (lines[i].backsector == NULL) { AM_drawMline(&l, WallColor); // one-sided wall @@ -2047,20 +2043,15 @@ void AM_drawPlayers () angle = players[consoleplayer].camera->angle; } - if (gameinfo.gametype & GAME_Raven) + if (am_cheat != 0 && CheatMapArrow.Size() > 0) { - arrow = player_arrow_raven; - numarrowlines = NUMPLYRLINES_RAVEN; - } - else if (am_cheat != 0) - { - arrow = cheat_player_arrow; - numarrowlines = NUMCHEATPLYRLINES; + arrow = &CheatMapArrow[0]; + numarrowlines = CheatMapArrow.Size(); } else { - arrow = player_arrow; - numarrowlines = NUMPLYRLINES; + arrow = &MapArrow[0]; + numarrowlines = MapArrow.Size(); } AM_drawLineCharacter(arrow, numarrowlines, 0, angle, YourColor, pt.x, pt.y); return; @@ -2113,9 +2104,7 @@ void AM_drawPlayers () angle -= players[consoleplayer].camera->angle - ANG90; } - AM_drawLineCharacter - (player_arrow, NUMPLYRLINES, 0, angle, - color, pt.x, pt.y); + AM_drawLineCharacter(&MapArrow[0], MapArrow.Size(), 0, angle, color, pt.x, pt.y); } } } @@ -2171,7 +2160,7 @@ void AM_drawThings () if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); else color = ThingColor_CountItem; - AM_drawLineCharacter(key_guy, NUMKEYGUYLINES, 16<x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel); } +//----------------------------------------------------------------------------- +// +// Print secret info (submitted by Karl Murks) +// +//----------------------------------------------------------------------------- +static void PrintSecretString(const char *string, bool thislevel) +{ + const char *colstr = thislevel? TEXTCOLOR_YELLOW : TEXTCOLOR_CYAN; + if (string != NULL) + { + if (*string == '$') + { + if (string[1] == 'S' || string[1] == 's') + { + long secnum = strtol(string+2, (char**)&string, 10); + if (*string == ';') string++; + if (thislevel && secnum >= 0 && secnum < numsectors) + { + if (sectors[secnum].secretsector) + { + if ((sectors[secnum].special & SECRET_MASK)) colstr = TEXTCOLOR_RED; + else colstr = TEXTCOLOR_GREEN; + } + else colstr = TEXTCOLOR_ORANGE; + } + } + else if (string[1] == 'T' || string[1] == 't') + { + long tid = strtol(string+2, (char**)&string, 10); + if (*string == ';') string++; + FActorIterator it(tid); + AActor *actor; + bool foundone = false; + if (thislevel) + { + while ((actor = it.Next())) + { + if (!actor->IsKindOf(PClass::FindClass("SecretTrigger"))) continue; + foundone = true; + break; + } + } + if (foundone) colstr = TEXTCOLOR_YELLOW; + else colstr = TEXTCOLOR_RED; + } + } + FBrokenLines *brok = V_BreakLines(ConFont, screen->GetWidth()*95/100, string); + + for (int k = 0; brok[k].Width >= 0; k++) + { + Printf("%s%s\n", colstr, brok[k].Text.GetChars()); + } + V_FreeBrokenLines(brok); + } +} + +//============================================================================ +// +// Print secret hints +// +//============================================================================ + +CCMD(secret) +{ + const char *mapname = argv.argc() < 2? level.mapname : argv[1]; + bool thislevel = !stricmp(mapname, level.mapname); + bool foundsome = false; + + int lumpno=Wads.CheckNumForName("SECRETS"); + if (lumpno < 0) return; + + FWadLump lump = Wads.OpenLumpNum(lumpno); + FString maphdr; + maphdr.Format("[%s]", mapname); + + FString linebuild; + char readbuffer[1024]; + bool inlevel = false; + + while (lump.Gets(readbuffer, 1024)) + { + if (!inlevel) + { + if (readbuffer[0] == '[') + { + inlevel = !strnicmp(readbuffer, maphdr, maphdr.Len()); + if (!foundsome) + { + FString levelname; + level_info_t *info = FindLevelInfo(mapname); + levelname.Format("%s - %s\n", mapname, info->LevelName.GetChars()); + size_t llen = levelname.Len() - 1; + for(size_t ii=0; iiIsLocked () || screen->Accel2D) + if (ConsoleDrawing || screen == NULL || screen->IsLocked () || screen->Accel2D || ConFont == NULL) { return; } @@ -297,32 +297,28 @@ void DequeueConsoleText () EnqueuedTextTail = &EnqueuedText; } +void C_InitConback() +{ + conback = TexMan.CheckForTexture ("CONBACK", FTexture::TEX_MiscPatch); + + if (!conback.isValid()) + { + conback = TexMan.GetTexture (gameinfo.titlePage, FTexture::TEX_MiscPatch); + conshade = MAKEARGB(175,0,0,0); + conline = true; + } + else + { + conshade = 0; + conline = false; + } +} + void C_InitConsole (int width, int height, bool ingame) { - if ( (vidactive = ingame) ) - { - if (!gotconback) - { - conback = TexMan.CheckForTexture ("CONBACK", FTexture::TEX_MiscPatch); - - if (!conback.isValid()) - { - conback = TexMan.GetTexture (gameinfo.titlePage, FTexture::TEX_MiscPatch); - conshade = MAKEARGB(175,0,0,0); - conline = true; - } - else - { - conshade = 0; - conline = false; - } - - gotconback = true; - } - } - int cwidth, cheight; + vidactive = ingame; if (ConFont != NULL) { cwidth = ConFont->GetCharWidth ('M'); diff --git a/src/c_console.h b/src/c_console.h index e1434c05..8560d677 100644 --- a/src/c_console.h +++ b/src/c_console.h @@ -53,6 +53,7 @@ extern int ConBottom; // Initialize the console void C_InitConsole (int width, int height, bool ingame); void C_DeinitConsole (); +void C_InitConback(); // Adjust the console for a new screen mode void C_NewModeAdjust (void); diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 7b538763..51413c37 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -221,7 +221,16 @@ int FBaseCVar::ToInt (UCVarValue value, ECVarType type) #else case CVAR_Float: res = (int)value.Float; break; #endif - case CVAR_String: res = strtol (value.String, NULL, 0); break; + case CVAR_String: + { + if (stricmp (value.String, "true") == 0) + res = 1; + else if (stricmp (value.String, "false") == 0) + res = 0; + else + res = strtol (value.String, NULL, 0); + break; + } case CVAR_GUID: res = 0; break; default: res = 0; break; } @@ -444,7 +453,12 @@ UCVarValue FBaseCVar::FromString (const char *value, ECVarType type) break; case CVAR_Int: - ret.Int = strtol (value, NULL, 0); + if (stricmp (value, "true") == 0) + ret.Int = 1; + else if (stricmp (value, "false") == 0) + ret.Int = 0; + else + ret.Int = strtol (value, NULL, 0); break; case CVAR_Float: @@ -600,6 +614,11 @@ void FBaseCVar::EnableCallbacks () } } +void FBaseCVar::DisableCallbacks () +{ + m_UseCallback = false; +} + // // Boolean cvar implementation // diff --git a/src/c_cvars.h b/src/c_cvars.h index 3b685948..d0ac84fe 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -117,6 +117,7 @@ public: static void EnableNoSet (); // enable the honoring of CVAR_NOSET static void EnableCallbacks (); + static void DisableCallbacks (); static void ResetColors (); // recalc color cvars' indices after screen change static void ListVars (const char *filter, bool plain); diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 413b8d64..1a2b3158 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -1211,6 +1211,30 @@ void C_ArchiveAliases (FConfigFile *f) } } +void C_ClearAliases () +{ + int bucket; + FConsoleCommand *alias; + + for (bucket = 0; bucket < FConsoleCommand::HASH_SIZE; bucket++) + { + alias = Commands[bucket]; + while (alias) + { + FConsoleCommand *next = alias->m_Next; + if (alias->IsAlias()) + static_cast(alias)->SafeDelete(); + alias = next; + } + } +} + +CCMD(clearaliases) +{ + C_ClearAliases(); +} + + // This is called only by the ini parser. void C_SetAlias (const char *name, const char *cmd) { diff --git a/src/c_dispatch.h b/src/c_dispatch.h index dbce9753..5aa3f987 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -58,6 +58,7 @@ int C_ExecFile (const char *cmd, bool usePullin); void C_ArchiveAliases (FConfigFile *f); void C_SetAlias (const char *name, const char *cmd); +void C_ClearAliases (); // build a single string out of multiple strings FString BuildString (int argc, char **argv); diff --git a/src/compatibility.cpp b/src/compatibility.cpp index ab1c98ca..718bfece 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -89,6 +89,7 @@ static FCompatOption Options[] = { "setslopeoverflow", 0, BCOMPATF_SETSLOPEOVERFLOW }, { "resetplayerspeed", 0, BCOMPATF_RESETPLAYERSPEED }, { "vileghosts", 0, BCOMPATF_VILEGHOSTS }, + { "ignoreteleporttags", 0, BCOMPATF_BADTELEPORTERS }, // list copied from g_mapinfo.cpp { "shorttex", COMPATF_SHORTTEX, 0 }, @@ -141,6 +142,9 @@ void ParseCompatibility() int i, x; unsigned int j; + BCompatMap.Clear(); + CompatParams.Clear(); + // The contents of this file are not cumulative, as it should not // be present in user-distributed maps. FScanner sc(Wads.GetNumForFullName("compatibility.txt")); @@ -279,7 +283,6 @@ void CheckCompatibility(MapData *map) ib_compatflags = 0; ii_compatparams = -1; } - else { map->GetChecksum(md5.Bytes); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 225f24ca..e5fd308b 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2880,6 +2880,8 @@ void FinishDehPatch () // Now that all Dehacked patches have been processed, it's okay to free StateMap. StateMap.Clear(); StateMap.ShrinkToFit(); + TouchedActors.Clear(); + TouchedActors.ShrinkToFit(); } void ModifyDropAmount(AInventory *inv, int dropamount); diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 93ea1083..0999a77e 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -227,13 +227,14 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize) { sc.MustGetString(); FString wadname = sc.String; -#ifdef _WIN32 +#if defined(_WIN32) || defined(__APPLE__) // Turns out Mac OS X is case insensitive. mIWadNames.Push(wadname); #else // check for lowercase, uppercased first letter and full uppercase on Linux etc. wadname.ToLower(); mIWadNames.Push(wadname); - wadname[0] = toupper(wadname[0]); + wadname.LockBuffer()[0] = toupper(wadname[0]); + wadname.UnlockBuffer(); mIWadNames.Push(wadname); wadname.ToUpper(); mIWadNames.Push(wadname); @@ -331,7 +332,7 @@ int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads) { FString iwad; - iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i]); + iwad.Format ("%s%s%s", doomwaddir, slash, mIWadNames[i].GetChars()); FixPathSeperator (iwad); if (FileExists (iwad)) { @@ -547,6 +548,7 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, exit (0); // zdoom.pk3 must always be the first file loaded and the IWAD second. + wadfiles.Clear(); D_AddFile (wadfiles, zdoom_wad); if (mIWads[wads[pickwad].Type].preload >= 0) diff --git a/src/d_main.cpp b/src/d_main.cpp index 75103e95..f0a8a0c4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -122,6 +122,7 @@ extern void M_SetDefaultMode (); extern void R_ExecuteSetViewSize (); extern void G_NewInit (); extern void SetupPlayerClasses (); +extern void HUD_InitHud(); const FIWADInfo *D_FindIWAD(TArray &wadfiles, const char *iwad, const char *basewad); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -131,6 +132,7 @@ void D_ProcessEvents (); void G_BuildTiccmd (ticcmd_t* cmd); void D_DoAdvanceDemo (); void D_AddWildFile (TArray &wadfiles, const char *pattern); +void D_LoadWadSettings (); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- @@ -221,6 +223,8 @@ FTexture *Page; FTexture *Advisory; bool nospriterename; FStartupInfo DoomStartupInfo; +FString lastIWAD; +int restart = 0; cycle_t FrameCycles; @@ -712,10 +716,12 @@ void D_Display () } else { + unsigned int nowtime = I_FPSTime(); + TexMan.UpdateAnimations(nowtime); + R_UpdateSky(nowtime); switch (gamestate) { case GS_FULLCONSOLE: - R_UpdateAnimations(I_FPSTime()); screen->SetBlendingRect(0,0,0,0); hw2d = screen->Begin2D(false); C_DrawConsole (false); @@ -780,7 +786,6 @@ void D_Display () break; case GS_INTERMISSION: - R_UpdateAnimations(I_FPSTime()); screen->SetBlendingRect(0,0,0,0); hw2d = screen->Begin2D(false); WI_Drawer (); @@ -788,7 +793,6 @@ void D_Display () break; case GS_FINALE: - R_UpdateAnimations(I_FPSTime()); screen->SetBlendingRect(0,0,0,0); hw2d = screen->Begin2D(false); F_Drawer (); @@ -796,7 +800,6 @@ void D_Display () break; case GS_DEMOSCREEN: - R_UpdateAnimations(I_FPSTime()); screen->SetBlendingRect(0,0,0,0); hw2d = screen->Begin2D(false); D_PageDrawer (); @@ -889,7 +892,7 @@ void D_Display () // // D_ErrorCleanup () // -// Cleanup after a recoverable error. +// Cleanup after a recoverable error or a restart //========================================================================== void D_ErrorCleanup () @@ -927,6 +930,7 @@ void D_DoomLoop () // Clamp the timer to TICRATE until the playloop has been entered. r_NoInterpolate = true; + Page = Advisory = NULL; vid_cursor.Callback(); @@ -1563,80 +1567,6 @@ bool ConsiderPatches (const char *arg) return argc > 0; } -//========================================================================== -// -// D_LoadWadSettings -// -// Parses any loaded KEYCONF lumps. These are restricted console scripts -// that can only execute the alias, defaultbind, addkeysection, -// addmenukey, weaponsection, and addslotdefault commands. -// -//========================================================================== - -void D_LoadWadSettings () -{ - char cmd[4096]; - int lump, lastlump = 0; - - ParsingKeyConf = true; - - while ((lump = Wads.FindLump ("KEYCONF", &lastlump)) != -1) - { - FMemLump data = Wads.ReadLump (lump); - const char *eof = (char *)data.GetMem() + Wads.LumpLength (lump); - const char *conf = (char *)data.GetMem(); - - while (conf < eof) - { - size_t i; - - // Fetch a line to execute - for (i = 0; conf + i < eof && conf[i] != '\n'; ++i) - { - cmd[i] = conf[i]; - } - cmd[i] = 0; - conf += i; - if (*conf == '\n') - { - conf++; - } - - // Comments begin with // - char *stop = cmd + i - 1; - char *comment = cmd; - int inQuote = 0; - - if (*stop == '\r') - *stop-- = 0; - - while (comment < stop) - { - if (*comment == '\"') - { - inQuote ^= 1; - } - else if (!inQuote && *comment == '/' && *(comment + 1) == '/') - { - break; - } - comment++; - } - if (comment == cmd) - { // Comment at line beginning - continue; - } - else if (comment < stop) - { // Comment in middle of line - *comment = 0; - } - - AddCommandString (cmd); - } - } - ParsingKeyConf = false; -} - //========================================================================== // // D_MultiExec @@ -1723,7 +1653,8 @@ static FString ParseGameInfo(TArray &pwads, const char *fn, const char } else if (!nextKey.CompareNoCase("NOSPRITERENAME")) { - nospriterename = true; + sc.MustGetString(); + nospriterename = sc.Compare("true"); } else if (!nextKey.CompareNoCase("STARTUPTITLE")) { @@ -1809,7 +1740,7 @@ static FString CheckGameInfo(TArray & pwads) static void SetMapxxFlag() { - int lump_name = Wads.CheckNumForName("MAP01", FWadCollection::IWAD_FILENUM); + int lump_name = Wads.CheckNumForName("MAP01", ns_global, FWadCollection::IWAD_FILENUM); int lump_wad = Wads.CheckNumForFullName("maps/map01.wad", FWadCollection::IWAD_FILENUM); int lump_map = Wads.CheckNumForFullName("maps/map01.map", FWadCollection::IWAD_FILENUM); @@ -1818,20 +1749,12 @@ static void SetMapxxFlag() //========================================================================== // -// D_DoomMain +// Initialize // //========================================================================== -void D_DoomMain (void) +static void D_DoomInit() { - int p, flags; - const char *v; - const char *wad; - DArgs *execFiles; - TArray pwads; - FString *args; - int argcount; - // Set the FPU precision to 53 significant bits. This is the default // for Visual C++, but not for GCC, so some slight math variances // might crop up if we leave it alone. @@ -1859,7 +1782,6 @@ void D_DoomMain (void) Args->CollectFiles("-playdemo", ".lmp"); Args->CollectFiles("-file", NULL); // anything left goes after -file - PClass::StaticInit (); atterm (C_DeinitConsole); gamestate = GS_STARTUP; @@ -1872,30 +1794,16 @@ void D_DoomMain (void) Printf ("M_LoadDefaults: Load system defaults.\n"); M_LoadDefaults (); // load before initing other systems - // [RH] Make sure zdoom.pk3 is always loaded, - // as it contains magic stuff we need. +} - wad = BaseFileSearch (BASEWAD, NULL, true); - if (wad == NULL) - { - I_FatalError ("Cannot find " BASEWAD); - } - FString basewad = wad; - - // Load zdoom.pk3 alone so that we can get access to the internal gameinfos before - // the IWAD is known. - - GetCmdLineFiles(pwads); - FString iwad = CheckGameInfo(pwads); - - FIWadManager *iwad_man = new FIWadManager; - const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad); - gameinfo.gametype = iwad_info->gametype; - gameinfo.flags = iwad_info->flags; - gameinfo.ConfigName = iwad_info->Configname; - - GameConfig->DoGameSetup (gameinfo.ConfigName); +//========================================================================== +// +// AddAutoloadFiles +// +//========================================================================== +static void AddAutoloadFiles(const char *gamesection) +{ if (!(gameinfo.flags & GI_SHAREWARE) && !Args->CheckParm("-noautoload")) { FString file; @@ -1905,7 +1813,7 @@ void D_DoomMain (void) // voices. I never got around to writing the utility to do it, though. // And I probably never will now. But I know at least one person uses // it for something else, so this gets to stay here. - wad = BaseFileSearch ("zvox.wad", NULL); + const char *wad = BaseFileSearch ("zvox.wad", NULL); if (wad) D_AddFile (allwads, wad); @@ -1932,66 +1840,28 @@ void D_DoomMain (void) D_AddConfigWads (allwads, file); // Add IWAD-specific wads - if (iwad_info->Autoname != NULL) + if (gamesection != NULL) { - file = iwad_info->Autoname; + file = gamesection; file += ".Autoload"; D_AddConfigWads(allwads, file); } } +} - // Run automatically executed files - execFiles = new DArgs; - GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName); - D_MultiExec (execFiles, true); +//========================================================================== +// +// CheckCmdLine +// +//========================================================================== - // Run .cfg files at the start of the command line. - execFiles = Args->GatherFiles ("-exec"); - D_MultiExec (execFiles, true); +static void CheckCmdLine() +{ + int flags = dmflags; + int p; + const char *v; - C_ExecCmdLineParams (); // [RH] do all +set commands on the command line - - CopyFiles(allwads, pwads); - - // Since this function will never leave we must delete this array here manually. - pwads.Clear(); - pwads.ShrinkToFit(); - - Printf ("W_Init: Init WADfiles.\n"); - Wads.InitMultipleFiles (allwads); - allwads.Clear(); - allwads.ShrinkToFit(); - SetMapxxFlag(); - - // [RH] Initialize localizable strings. - GStrings.LoadStrings (false); - - V_InitFontColors (); - - // [RH] Moved these up here so that we can do most of our - // startup output in a fullscreen console. - - CT_Init (); - - Printf ("I_Init: Setting up machine state.\n"); - I_Init (); - - Printf ("V_Init: allocate screen.\n"); - V_Init (); - - // Base systems have been inited; enable cvar callbacks - FBaseCVar::EnableCallbacks (); - - Printf ("S_Init: Setting up sound.\n"); - S_Init (); - - Printf ("ST_Init: Init startup screen.\n"); - StartScreen = FStartupScreen::CreateInstance (R_GuesstimateNumTextures() + 5); - - ParseCompatibility(); - - Printf ("P_Init: Checking cmd-line parameters...\n"); - flags = dmflags; + Printf ("Checking cmd-line parameters...\n"); if (Args->CheckParm ("-nomonsters")) flags |= DF_NO_MONSTERS; if (Args->CheckParm ("-respawn")) flags |= DF_MONSTERS_RESPAWN; if (Args->CheckParm ("-fast")) flags |= DF_FAST_MONSTERS; @@ -2126,199 +1996,404 @@ void D_DoomMain (void) temp.Format ("Warp to map %s, Skill %d ", startmap.GetChars(), gameskill + 1); StartScreen->AppendStatusLine(temp); } +} - // [RH] Load sound environments - S_ParseReverbDef (); +//========================================================================== +// +// D_DoomMain +// +//========================================================================== - // [RH] Parse through all loaded mapinfo lumps - Printf ("G_ParseMapInfo: Load map definitions.\n"); - G_ParseMapInfo (iwad_info->MapInfo); - ReadStatistics(); +void D_DoomMain (void) +{ + int p; + const char *v; + const char *wad; + DArgs *execFiles; + TArray pwads; + FString *args; + int argcount; - // [RH] Parse any SNDINFO lumps - Printf ("S_InitData: Load sound definitions.\n"); - S_InitData (); + D_DoomInit(); + PClass::StaticInit (); - Printf ("Texman.Init: Init texture manager.\n"); - TexMan.Init(); + // [RH] Make sure zdoom.pk3 is always loaded, + // as it contains magic stuff we need. - // [CW] Parse any TEAMINFO lumps. - Printf ("ParseTeamInfo: Load team definitions.\n"); - TeamLibrary.ParseTeamInfo (); - - FActorInfo::StaticInit (); - - // [GRB] Initialize player class list - SetupPlayerClasses (); - - - // [RH] Load custom key and weapon settings from WADs - D_LoadWadSettings (); - - // [GRB] Check if someone used clearplayerclasses but not addplayerclass - if (PlayerClasses.Size () == 0) + wad = BaseFileSearch (BASEWAD, NULL, true); + if (wad == NULL) { - I_FatalError ("No player classes defined"); + I_FatalError ("Cannot find " BASEWAD); } + FString basewad = wad; - StartScreen->Progress (); - Printf ("R_Init: Init %s refresh subsystem.\n", gameinfo.ConfigName.GetChars()); - StartScreen->LoadingStatus ("Loading graphics", 0x3f); - R_Init (); + // reinit from here - Printf ("DecalLibrary: Load decals.\n"); - DecalLibrary.Clear (); - DecalLibrary.ReadAllDecals (); - - // [RH] Add any .deh and .bex files on the command line. - // If there are none, try adding any in the config file. - // Note that the command line overrides defaults from the config. - - if ((ConsiderPatches("-deh") | ConsiderPatches("-bex")) == 0 && - gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked")) + do { - const char *key; - const char *value; - - while (GameConfig->NextInSection (key, value)) + if (restart) { - if (stricmp (key, "Path") == 0 && FileExists (value)) - { - Printf ("Applying patch %s\n", value); - D_LoadDehFile(value); - } + C_InitConsole(SCREENWIDTH, SCREENHEIGHT, false); } - } + nospriterename = false; - // Load embedded Dehacked patches - D_LoadDehLumps(); + // Load zdoom.pk3 alone so that we can get access to the internal gameinfos before + // the IWAD is known. - // Create replacements for dehacked pickups - FinishDehPatch(); + GetCmdLineFiles(pwads); + FString iwad = CheckGameInfo(pwads); - FActorInfo::StaticSetActorNums (); + // The IWAD selection dialogue dpes not show in fullscreen so if the + // restart is initiated without a defined IWAD assume for now that it's not going to change. + if (iwad.Len() == 0) iwad = lastIWAD; - // [RH] User-configurable startup strings. Because BOOM does. - static const char *startupString[5] = { - "STARTUP1", "STARTUP2", "STARTUP3", "STARTUP4", "STARTUP5" - }; - for (p = 0; p < 5; ++p) - { - const char *str = GStrings[startupString[p]]; - if (str != NULL && str[0] != '\0') - { - Printf ("%s\n", str); - } - } + FIWadManager *iwad_man = new FIWadManager; + const FIWADInfo *iwad_info = iwad_man->FindIWAD(allwads, iwad, basewad); + gameinfo.gametype = iwad_info->gametype; + gameinfo.flags = iwad_info->flags; + gameinfo.ConfigName = iwad_info->Configname; + lastIWAD = iwad; - //Added by MC: - argcount = Args->CheckParmList("-bots", &args); - for (p = 0; p < argcount; ++p) - { - bglobal.getspawned.Push(args[p]); - } - bglobal.spawn_tries = 0; - bglobal.wanted_botnum = bglobal.getspawned.Size(); + FBaseCVar::DisableCallbacks(); + GameConfig->DoGameSetup (gameinfo.ConfigName); - Printf ("M_Init: Init menus.\n"); - M_Init (); + AddAutoloadFiles(iwad_info->Autoname); - Printf ("P_Init: Init Playloop state.\n"); - StartScreen->LoadingStatus ("Init game engine", 0x3f); - P_Init (); + // Run automatically executed files + execFiles = new DArgs; + GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName); + D_MultiExec (execFiles, true); - P_SetupWeapons_ntohton(); + // Run .cfg files at the start of the command line. + execFiles = Args->GatherFiles ("-exec"); + D_MultiExec (execFiles, true); - //SBarInfo support. - SBarInfo::Load(); + C_ExecCmdLineParams (); // [RH] do all +set commands on the command line - Printf ("D_CheckNetGame: Checking network game status.\n"); - StartScreen->LoadingStatus ("Checking network game status.", 0x3f); - D_CheckNetGame (); + CopyFiles(allwads, pwads); - // [RH] Lock any cvars that should be locked now that we're - // about to begin the game. - FBaseCVar::EnableNoSet (); + // Since this function will never leave we must delete this array here manually. + pwads.Clear(); + pwads.ShrinkToFit(); - delete iwad_man; // now we won't need this anymore - - // [RH] Run any saved commands from the command line or autoexec.cfg now. - gamestate = GS_FULLCONSOLE; - Net_NewMakeTic (); - DThinker::RunThinkers (); - gamestate = GS_STARTUP; - - // start the apropriate game based on parms - v = Args->CheckValue ("-record"); - - if (v) - { - G_RecordDemo (v); - autostart = true; - } - - delete StartScreen; - StartScreen = NULL; - - if (Args->CheckParm("-norun")) - { - throw CNoRunExit(); - } - - V_Init2(); - - v = Args->CheckValue("-playdemo"); - if (v != NULL) - { - singledemo = true; // quit after one demo - G_DeferedPlayDemo (v); - D_DoomLoop (); // never returns - } - - v = Args->CheckValue ("-timedemo"); - if (v) - { - G_TimeDemo (v); - D_DoomLoop (); // never returns - } + Printf ("W_Init: Init WADfiles.\n"); + Wads.InitMultipleFiles (allwads); + allwads.Clear(); + allwads.ShrinkToFit(); + SetMapxxFlag(); - v = Args->CheckValue ("-loadgame"); - if (v) - { - FString file(v); - FixPathSeperator (file); - DefaultExtension (file, ".zds"); - G_LoadGame (file); - } + // [RH] Initialize localizable strings. + GStrings.LoadStrings (false); - if (gameaction != ga_loadgame) - { - if (autostart || netgame) + V_InitFontColors (); + + // [RH] Moved these up here so that we can do most of our + // startup output in a fullscreen console. + + CT_Init (); + + if (!restart) { - // Do not do any screenwipes when autostarting a game. - if (!Args->CheckParm("-warpwipe")) + Printf ("I_Init: Setting up machine state.\n"); + I_Init (); + } + + Printf ("V_Init: allocate screen.\n"); + V_Init (!!restart); + + // Base systems have been inited; enable cvar callbacks + FBaseCVar::EnableCallbacks (); + + Printf ("S_Init: Setting up sound.\n"); + S_Init (); + + Printf ("ST_Init: Init startup screen.\n"); + if (!restart) StartScreen = FStartupScreen::CreateInstance (TexMan.GuesstimateNumTextures() + 5); + else StartScreen = new FStartupScreen(0); + + ParseCompatibility(); + + CheckCmdLine(); + + // [RH] Load sound environments + S_ParseReverbDef (); + + // [RH] Parse through all loaded mapinfo lumps + Printf ("G_ParseMapInfo: Load map definitions.\n"); + G_ParseMapInfo (iwad_info->MapInfo); + ReadStatistics(); + + // [RH] Parse any SNDINFO lumps + Printf ("S_InitData: Load sound definitions.\n"); + S_InitData (); + + Printf ("Texman.Init: Init texture manager.\n"); + TexMan.Init(); + C_InitConback(); + + // [CW] Parse any TEAMINFO lumps. + Printf ("ParseTeamInfo: Load team definitions.\n"); + TeamLibrary.ParseTeamInfo (); + + FActorInfo::StaticInit (); + + // [GRB] Initialize player class list + SetupPlayerClasses (); + + + // [RH] Load custom key and weapon settings from WADs + D_LoadWadSettings (); + + // [GRB] Check if someone used clearplayerclasses but not addplayerclass + if (PlayerClasses.Size () == 0) + { + I_FatalError ("No player classes defined"); + } + + StartScreen->Progress (); + + Printf ("R_Init: Init %s refresh subsystem.\n", gameinfo.ConfigName.GetChars()); + StartScreen->LoadingStatus ("Loading graphics", 0x3f); + R_Init (); + + Printf ("DecalLibrary: Load decals.\n"); + DecalLibrary.ReadAllDecals (); + + // [RH] Add any .deh and .bex files on the command line. + // If there are none, try adding any in the config file. + // Note that the command line overrides defaults from the config. + + if ((ConsiderPatches("-deh") | ConsiderPatches("-bex")) == 0 && + gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked")) + { + const char *key; + const char *value; + + while (GameConfig->NextInSection (key, value)) { - NoWipe = TICRATE; + if (stricmp (key, "Path") == 0 && FileExists (value)) + { + Printf ("Applying patch %s\n", value); + D_LoadDehFile(value); + } } - CheckWarpTransMap (startmap, true); - if (demorecording) - G_BeginRecording (startmap); - G_InitNew (startmap, false); + } + + // Load embedded Dehacked patches + D_LoadDehLumps(); + + // Create replacements for dehacked pickups + FinishDehPatch(); + + FActorInfo::StaticSetActorNums (); + + //Added by MC: + bglobal.getspawned.Clear(); + argcount = Args->CheckParmList("-bots", &args); + for (p = 0; p < argcount; ++p) + { + bglobal.getspawned.Push(args[p]); + } + bglobal.spawn_tries = 0; + bglobal.wanted_botnum = bglobal.getspawned.Size(); + + Printf ("M_Init: Init menus.\n"); + M_Init (); + + Printf ("P_Init: Init Playloop state.\n"); + StartScreen->LoadingStatus ("Init game engine", 0x3f); + AM_StaticInit(); + P_Init (); + + P_SetupWeapons_ntohton(); + + //SBarInfo support. + SBarInfo::Load(); + HUD_InitHud(); + + // [RH] User-configurable startup strings. Because BOOM does. + static const char *startupString[5] = { + "STARTUP1", "STARTUP2", "STARTUP3", "STARTUP4", "STARTUP5" + }; + for (p = 0; p < 5; ++p) + { + const char *str = GStrings[startupString[p]]; + if (str != NULL && str[0] != '\0') + { + Printf ("%s\n", str); + } + } + + if (!restart) + { + Printf ("D_CheckNetGame: Checking network game status.\n"); + StartScreen->LoadingStatus ("Checking network game status.", 0x3f); + D_CheckNetGame (); + } + + // [RH] Lock any cvars that should be locked now that we're + // about to begin the game. + FBaseCVar::EnableNoSet (); + + delete iwad_man; // now we won't need this anymore + + // [RH] Run any saved commands from the command line or autoexec.cfg now. + gamestate = GS_FULLCONSOLE; + Net_NewMakeTic (); + DThinker::RunThinkers (); + gamestate = GS_STARTUP; + + if (!restart) + { + // start the apropriate game based on parms + v = Args->CheckValue ("-record"); + + if (v) + { + G_RecordDemo (v); + autostart = true; + } + + delete StartScreen; + StartScreen = NULL; + + if (Args->CheckParm("-norun")) + { + throw CNoRunExit(); + } + + V_Init2(); + + v = Args->CheckValue("-playdemo"); + if (v != NULL) + { + singledemo = true; // quit after one demo + G_DeferedPlayDemo (v); + D_DoomLoop (); // never returns + } + + v = Args->CheckValue ("-timedemo"); + if (v) + { + G_TimeDemo (v); + D_DoomLoop (); // never returns + } + + v = Args->CheckValue ("-loadgame"); + if (v) + { + FString file(v); + FixPathSeperator (file); + DefaultExtension (file, ".zds"); + G_LoadGame (file); + } + + if (gameaction != ga_loadgame) + { + if (autostart || netgame) + { + // Do not do any screenwipes when autostarting a game. + if (!Args->CheckParm("-warpwipe")) + { + NoWipe = TICRATE; + } + CheckWarpTransMap (startmap, true); + if (demorecording) + G_BeginRecording (startmap); + G_InitNew (startmap, false); + } + else + { + D_StartTitle (); // start up intro loop + } + } + else if (demorecording) + { + G_BeginRecording (NULL); + } + + atterm (D_QuitNetGame); // killough } else { + // let the renderer reinitialize some stuff if needed + screen->GameRestart(); + // These calls from inside V_Init2 are still necessary + C_NewModeAdjust(); + M_InitVideoModesMenu(); D_StartTitle (); // start up intro loop + setmodeneeded = false; // This may be set to true here, but isn't needed for a restart + } + + try + { + D_DoomLoop (); // never returns + } + catch (CRestartException &) + { + // Music and sound should be stopped first + S_StopMusic(true); + S_StopAllChannels (); + + M_ClearMenus(); // close menu if open + F_EndFinale(); // If an intermission is active, end it now + + // clean up game state + ST_Clear(); + D_ErrorCleanup (); + P_FreeLevelData(); + P_FreeExtraLevelData(); + + M_SaveDefaults(NULL); // save config before the restart + + // delete all data that cannot be left until reinitialization + V_ClearFonts(); // must clear global font pointers + R_DeinitTranslationTables(); // some tables are initialized from outside the translation code. + gameinfo.~gameinfo_t(); + new (&gameinfo) gameinfo_t; // Reset gameinfo + S_Shutdown(); // free all channels and delete playlist + C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here + + GC::FullGC(); // perform one final garbage collection before deleting the class data + PClass::ClearRuntimeData(); // clear all runtime generated class data + restart++; } } - else if (demorecording) - { - G_BeginRecording (NULL); - } - - atterm (D_QuitNetGame); // killough + while (1); +} - D_DoomLoop (); // never returns +//========================================================================== +// +// restart the game +// +//========================================================================== + +CCMD(restart) +{ + // remove command line args that would get in the way during restart + Args->RemoveArgs("-iwad"); + Args->RemoveArgs("-deh"); + Args->RemoveArgs("-bex"); + Args->RemoveArgs("-playdemo"); + Args->RemoveArgs("-file"); + Args->RemoveArgs("-altdeath"); + Args->RemoveArgs("-deathmatch"); + Args->RemoveArgs("-skill"); + Args->RemoveArgs("-savedir"); + Args->RemoveArgs("-xlat"); + Args->RemoveArgs("-oldsprites"); + + if (argv.argc() > 1) + { + for(int i=1;iAppendArg(argv[i]); + } + } + + // initiate the restart + throw CRestartException(); } //========================================================================== @@ -2368,6 +2443,14 @@ void FStartupScreen::AppendStatusLine(const char *status) { } + +void FStartupScreen::Progress(void) {} +void FStartupScreen::NetInit(char const *,int) {} +void FStartupScreen::NetProgress(int) {} +void FStartupScreen::NetMessage(char const *,...) {} +void FStartupScreen::NetDone(void) {} +bool FStartupScreen::NetLoop(bool (*)(void *),void *) { return false; } + //========================================================================== // // STAT fps diff --git a/src/d_main.h b/src/d_main.h index 415a6b94..7dd75a10 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -36,6 +36,12 @@ struct event_t; // calls all startup code, parses command line options. // If not overrided by user input, calls N_AdvanceDemo. // + +struct CRestartException +{ + char dummy; +}; + void D_DoomMain (void); diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 51467369..def80065 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -835,11 +835,9 @@ FArchive &operator<< (FArchive &arc, userinfo_t &info) { arc.Read (&info.netname, sizeof(info.netname)); } - arc << info.team << info.aimdist << info.color << info.skin << info.gender << info.neverswitch; - if (SaveVersion >= 2193) - { - arc << info.colorset; - } + arc << info.team << info.aimdist << info.color + << info.skin << info.gender << info.neverswitch + << info.colorset; return arc; } diff --git a/src/decallib.cpp b/src/decallib.cpp index bfcc1ac1..6bbf0f74 100644 --- a/src/decallib.cpp +++ b/src/decallib.cpp @@ -347,6 +347,16 @@ void FDecalLib::ReadAllDecals () int lump, lastlump = 0; unsigned int i; + for(unsigned i=0;iSymbols; if (arc.IsStoring()) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f232d81f..03a8d2de 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -80,6 +80,24 @@ void PClass::StaticInit () } } +void PClass::ClearRuntimeData () +{ + StaticShutdown(); + + m_RuntimeActors.Clear(); + m_Types.Clear(); + memset(TypeHash, 0, sizeof(TypeHash)); + bShutdown = false; + + // Immediately reinitialize the internal classes + FAutoSegIterator probe(CRegHead, CRegTail); + + while (*++probe != NULL) + { + ((ClassReg *)*probe)->RegisterClass (); + } +} + void PClass::StaticShutdown () { TArray uniqueFPs(64); @@ -105,6 +123,8 @@ void PClass::StaticShutdown () uniqueFPs.Push(const_cast(type->FlatPointers)); } } + type->FlatPointers = NULL; + // For runtime classes, this call will also delete the PClass. PClass::StaticFreeData (type); } diff --git a/src/dobjtype.h b/src/dobjtype.h index e0192990..256e52ad 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -125,6 +125,7 @@ struct PClass static void StaticInit (); static void StaticShutdown (); static void StaticFreeData (PClass *type); + static void ClearRuntimeData(); // Per-class information ------------------------------------- FName TypeName; // this class's name diff --git a/src/doomdef.h b/src/doomdef.h index 9ad019db..748f2df4 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -341,6 +341,8 @@ enum BCOMPATF_SETSLOPEOVERFLOW = 1 << 0, // SetSlope things can overflow BCOMPATF_RESETPLAYERSPEED = 1 << 1, // Set player speed to 1.0 when changing maps BCOMPATF_VILEGHOSTS = 1 << 2, // Monsters' radius and height aren't restored properly when resurrected. + BCOMPATF_BADTELEPORTERS = 1 << 3, // Ignore tags on Teleport specials + BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior }; // phares 3/20/98: diff --git a/src/farchive.h b/src/farchive.h index 533b3920..7ee05fdc 100644 --- a/src/farchive.h +++ b/src/farchive.h @@ -291,7 +291,11 @@ template<> inline FArchive &operator<< (FArchive &arc, FFont* &font) } struct FStrifeDialogueNode; +struct FSwitchDef; +struct FDoorAnimation; template<> FArchive &operator<< (FArchive &arc, FStrifeDialogueNode *&node); +template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &sw); +template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &da); diff --git a/src/g_game.cpp b/src/g_game.cpp index 1153a9e7..1d735ee0 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -180,8 +180,6 @@ wbstartstruct_t wminfo; // parms for world map / intermission short consistancy[MAXPLAYERS][BACKUPTICS]; -BYTE* savebuffer; - #define MAXPLMOVE (forwardmove[1]) @@ -240,9 +238,9 @@ CUSTOM_CVAR (Float, turbo, 100.f, 0) { self = 10.f; } - else if (self > 256.f) + else if (self > 255.f) { - self = 256.f; + self = 255.f; } else { @@ -1906,6 +1904,7 @@ FString G_BuildSaveName (const char *prefix, int slot) } CVAR (Int, autosavenum, 0, CVAR_NOSET|CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +static int nextautosave = -1; CVAR (Int, disableautosave, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR (Int, autosavecount, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { @@ -1926,10 +1925,25 @@ void G_DoAutoSave () const char *readableTime; int count = autosavecount != 0 ? autosavecount : 1; - num.Int = (autosavenum + 1) % count; + if (nextautosave == -1) + { + nextautosave = (autosavenum + 1) % count; + } + + num.Int = nextautosave; autosavenum.ForceSet (num, CVAR_Int); - file = G_BuildSaveName ("auto", num.Int); + file = G_BuildSaveName ("auto", nextautosave); + + if (!(level.flags2 & LEVEL2_NOAUTOSAVEHINT)) + { + nextautosave = (nextautosave + 1) % count; + } + else + { + // This flag can only be used once per level + level.flags2 &= ~LEVEL2_NOAUTOSAVEHINT; + } readableTime = myasctime (); strcpy (description, "Autosave "); @@ -2575,6 +2589,7 @@ bool G_CheckDemoStatus (void) C_RestoreCVars (); // [RH] Restore cvars demo might have changed M_Free (demobuffer); + demobuffer = NULL; P_SetupWeapons_ntohton(); demoplayback = false; diff --git a/src/g_game.h b/src/g_game.h index 20fdae89..a9f5f0af 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -85,6 +85,8 @@ void G_AddViewAngle (int yaw); class AActor; extern AActor *bodyque[BODYQUESIZE]; extern int bodyqueslot; +class AInventory; +extern const AInventory *SendItemUse, *SendItemDrop; #endif diff --git a/src/g_heretic/a_hereticweaps.cpp b/src/g_heretic/a_hereticweaps.cpp index ad011508..f6c9df7f 100644 --- a/src/g_heretic/a_hereticweaps.cpp +++ b/src/g_heretic/a_hereticweaps.cpp @@ -462,8 +462,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_MacePL1Check) self->velx = FixedMul(7*FRACUNIT, finecosine[angle]); self->vely = FixedMul(7*FRACUNIT, finesine[angle]); #else - double velscale = sqrtf ((float)self->velx * (float)self->velx + - (float)self->vely * (float)self->vely); + double velscale = sqrt ((double)self->velx * (double)self->velx + + (double)self->vely * (double)self->vely); velscale = 458752 / velscale; self->velx = (int)(self->velx * velscale); self->vely = (int)(self->vely * velscale); @@ -1045,6 +1045,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm) x = self->x + ((pr_storm()&127) - 64) * FRACUNIT; y = self->y + ((pr_storm()&127) - 64) * FRACUNIT; mo = Spawn (x, y, ONCEILINGZ, ALLOW_REPLACE); +#ifdef _3DFLOORS + // We used bouncecount to store the 3D floor index in A_HideInCeiling + if (!mo) return; + fixed_t newz; + if (self->bouncecount >= 0 + && (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size()) + newz = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(x, y);// - 40 * FRACUNIT; + else + newz = self->Sector->ceilingplane.ZatPoint(x, y); + int moceiling = P_Find3DFloor(NULL, x, y, newz, false, false, newz); + if (moceiling >= 0) + mo->z = newz - mo->height; +#endif mo->Translation = multiplayer ? TRANSLATION(TRANSLATION_PlayersExtra,self->special2) : 0; mo->target = self->target; @@ -1084,6 +1097,23 @@ DEFINE_ACTION_FUNCTION(AActor, A_RainImpact) DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling) { +#ifdef _3DFLOORS + // We use bouncecount to store the 3D floor index + fixed_t foo; + for (unsigned int i=0; i< self->Sector->e->XFloor.ffloors.Size(); i++) + { + F3DFloor * rover = self->Sector->e->XFloor.ffloors[i]; + if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; + + if ((foo = rover->bottom.plane->ZatPoint(self->x, self->y)) >= (self->z + self->height)) + { + self->z = foo + 4*FRACUNIT; + self->bouncecount = i; + return; + } + } + self->bouncecount = -1; +#endif self->z = self->ceilingz + 4*FRACUNIT; } diff --git a/src/g_hub.cpp b/src/g_hub.cpp index 162aacd1..22c6ff6f 100644 --- a/src/g_hub.cpp +++ b/src/g_hub.cpp @@ -76,7 +76,7 @@ struct FHubInfo }; -TArray hubdata; +static TArray hubdata; void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs) { @@ -182,3 +182,8 @@ void G_ReadHubInfo (PNGHandle *png) G_SerializeHub(arc); } } + +void G_ClearHubInfo() +{ + hubdata.Clear(); +} \ No newline at end of file diff --git a/src/g_level.cpp b/src/g_level.cpp index 7008572a..a962d519 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -119,7 +119,6 @@ bool savegamerestore; extern int mousex, mousey; extern bool sendpause, sendsave, sendturn180, SendLand; -extern const AInventory *SendItemUse, *SendItemDrop; void *statcopy; // for statistics driver @@ -309,6 +308,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel) bool wantFast; int i; + G_ClearHubInfo(); if (!savegamerestore) { G_ClearSnapshots (); @@ -742,12 +742,7 @@ void G_DoCompleted (void) { // Reset world variables for the new hub. P_ClearACSVars(false); } - // With hub statistics the time should be per hub. - // Additionally there is a global time counter now so nothing is missed by changing it - //else if (mode == FINISH_NoHub) - { // Reset time to zero if not entering/staying in a hub. - level.time = 0; - } + level.time = 0; level.maptime = 0; } diff --git a/src/g_level.h b/src/g_level.h index d7add35b..34c2bf5f 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -212,6 +212,7 @@ enum ELevelFlags LEVEL2_NOSTATISTICS = 0x10000000, // This level should not have statistics collected LEVEL2_ENDGAME = 0x20000000, // This is an epilogue level that cannot be quit. + LEVEL2_NOAUTOSAVEHINT = 0x40000000, // tell the game that an autosave for this level does not need to be kept }; @@ -514,6 +515,7 @@ void G_UnSnapshotLevel (bool keepPlayers); struct PNGHandle; void G_ReadSnapshots (PNGHandle *png); void G_WriteSnapshots (FILE *file); +void G_ClearHubInfo(); enum ESkillProperty { diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index e15de22a..b4183ef2 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1238,6 +1238,7 @@ MapFlagHandlers[] = { "resethealth", MITYPE_SETFLAG2, LEVEL2_RESETHEALTH, 0 }, { "endofgame", MITYPE_SETFLAG2, LEVEL2_ENDGAME, 0 }, { "nostatistics", MITYPE_SETFLAG2, LEVEL2_NOSTATISTICS, 0 }, + { "noautosavehint", MITYPE_SETFLAG2, LEVEL2_NOAUTOSAVEHINT, 0 }, { "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX}, @@ -1626,7 +1627,13 @@ void FMapInfoParser::ParseEpisodeInfo () } else { - FEpisode *epi = &AllEpisodes[AllEpisodes.Reserve(1)]; + // Only allocate a new entry if this doesn't replace an existing episode. + if (i >= AllEpisodes.Size()) + { + i = AllEpisodes.Reserve(1); + } + + FEpisode *epi = &AllEpisodes[i]; epi->mEpisodeMap = map; epi->mEpisodeName = name; @@ -1787,6 +1794,25 @@ void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults, level_i } +//========================================================================== +// +// +// +//========================================================================== + +void DeinitIntermissions(); + +static void ClearMapinfo() +{ + wadclusterinfos.Clear(); + wadlevelinfos.Clear(); + ClearEpisodes(); + AllSkills.Clear(); + DefaultSkill = -1; + DeinitIntermissions(); + level.info = NULL; +} + //========================================================================== // // G_ParseMapInfo @@ -1800,7 +1826,8 @@ void G_ParseMapInfo (const char *basemapinfo) int lump, lastlump = 0; level_info_t gamedefaults; - atterm(ClearEpisodes); + ClearMapinfo(); + atterm(ClearMapinfo); // Parse the default MAPINFO for the current game. This lump *MUST* come from zdoom.pk3. if (basemapinfo != NULL) diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index c4f0f9d6..0370e226 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -36,8 +36,6 @@ static FRandom pr_torch ("Torch"); #define TIMEFREEZE_TICS ( 12 * TICRATE ) */ -EXTERN_CVAR (Bool, r_drawfuzz); - IMPLEMENT_CLASS (APowerup) // Powerup-Giver ------------------------------------------------------------- diff --git a/src/g_shared/a_camera.cpp b/src/g_shared/a_camera.cpp index 99da16ae..c75ccbe8 100644 --- a/src/g_shared/a_camera.cpp +++ b/src/g_shared/a_camera.cpp @@ -143,12 +143,21 @@ void AAimingCamera::PostBeginPlay () tracer = iterator.Next (); if (tracer == NULL) { - Printf ("AimingCamera %d: Can't find thing %d\n", tid, args[3]); + //Printf ("AimingCamera %d: Can't find TID %d\n", tid, args[3]); + } + else + { // Don't try for a new target upon losing this one. + args[3] = 0; } } void AAimingCamera::Tick () { + if (tracer == NULL && args[3] != 0) + { // Recheck, in case something with this TID was created since the last time. + TActorIterator iterator (args[3]); + tracer = iterator.Next (); + } if (tracer != NULL) { angle_t delta; diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index d992bec9..1c15bd91 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -414,7 +414,7 @@ static void GetWallStuff (side_t *wall, vertex_t *&v1, fixed_t &ldx, fixed_t &ld static fixed_t Length (fixed_t dx, fixed_t dy) { - return (fixed_t)sqrtf ((float)dx*(float)dx+(float)dy*(float)dy); + return (fixed_t)sqrt ((double)dx*(double)dx+(double)dy*(double)dy); } static side_t *NextWall (const side_t *wall) diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 524daee7..f15da2f3 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -16,6 +16,7 @@ #include "a_specialspot.h" #include "thingdef/thingdef.h" #include "g_level.h" +#include "g_game.h" #include "doomstat.h" static FRandom pr_restore ("RestorePos"); @@ -183,6 +184,7 @@ bool P_GiveBody (AActor *actor, int num) int max; player_t *player = actor->player; + num = clamp(num, -65536, 65536); // prevent overflows for bad values if (player != NULL) { max = static_cast(actor)->GetMaxHealth() + player->stamina; @@ -627,7 +629,7 @@ AInventory *AInventory::CreateTossable () { return NULL; } - if ((ItemFlags & IF_UNDROPPABLE) || Owner == NULL || Amount <= 0) + if ((ItemFlags & (IF_UNDROPPABLE|IF_UNTOSSABLE)) || Owner == NULL || Amount <= 0) { return NULL; } @@ -1033,6 +1035,10 @@ void AInventory::Destroy () } Inventory = NULL; Super::Destroy (); + + // Although contrived it can theoretically happen that these variables still got a pointer to this item + if (SendItemUse == this) SendItemUse = NULL; + if (SendItemDrop == this) SendItemDrop = NULL; } //=========================================================================== diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 3afcbf5b..23cac960 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -116,10 +116,10 @@ enum IF_PICKUPGOOD = 1<<2, // HandlePickup wants normal pickup FX to happen IF_QUIET = 1<<3, // Don't give feedback when picking up IF_AUTOACTIVATE = 1<<4, // Automatically activate item on pickup - IF_UNDROPPABLE = 1<<5, // The player cannot manually drop the item + IF_UNDROPPABLE = 1<<5, // Item cannot be removed unless done explicitly with RemoveInventory IF_INVBAR = 1<<6, // Item appears in the inventory bar IF_HUBPOWER = 1<<7, // Powerup is kept when moving in a hub -// IF_INTERHUBSTRIP = 1<<8, // Item is removed when travelling between hubs + IF_UNTOSSABLE = 1<<8, // The player cannot manually drop the item IF_ADDITIVETIME = 1<<9, // when picked up while another item is active, time is added instead of replaced. IF_ALWAYSPICKUP = 1<<10, // For IF_AUTOACTIVATE, MaxAmount=0 items: Always "pick up", even if it doesn't do anything IF_FANCYPICKUPSOUND = 1<<11, // Play pickup sound in "surround" mode diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index c5360533..725f1204 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -55,16 +55,8 @@ void DEarthquake::Serialize (FArchive &arc) { Super::Serialize (arc); arc << m_Spot << m_Intensity << m_Countdown - << m_TremorRadius << m_DamageRadius; - - if (SaveVersion >= 1912) - { - arc << m_QuakeSFX; - } - else - { - m_QuakeSFX = "world/quake"; - } + << m_TremorRadius << m_DamageRadius + << m_QuakeSFX; } //========================================================================== diff --git a/src/g_shared/a_sharedglobal.h b/src/g_shared/a_sharedglobal.h index c152bf44..84932145 100644 --- a/src/g_shared/a_sharedglobal.h +++ b/src/g_shared/a_sharedglobal.h @@ -97,7 +97,6 @@ public: bool bInSkybox; bool bAlways; TObjPtr Mate; - fixed_t PlaneAlpha; }; class AStackPoint : public ASkyViewpoint diff --git a/src/g_shared/a_skies.cpp b/src/g_shared/a_skies.cpp index 0454498e..bb13eac0 100644 --- a/src/g_shared/a_skies.cpp +++ b/src/g_shared/a_skies.cpp @@ -69,7 +69,7 @@ void ASkyViewpoint::BeginPlay () void ASkyViewpoint::Serialize (FArchive &arc) { Super::Serialize (arc); - arc << bInSkybox << bAlways << Mate << PlaneAlpha; + arc << bInSkybox << bAlways << Mate; } void ASkyViewpoint::Destroy () diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 295e0e4e..71dc6667 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -381,7 +381,9 @@ DBaseStatusBar *CreateCustomStatusBar(int script=0); // Crosshair stuff ---------------------------------------------------------- +void ST_FormatMapName(FString &mapname, const char *mapnamecolor = ""); void ST_LoadCrosshair(bool alwaysload=false); +void ST_Clear(); extern FTexture *CrosshairImage; #endif /* __SBAR_H__ */ diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index e48a047b..02b72167 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -335,6 +335,7 @@ bool FMugShot::SetState(const char *state_name, bool wait_till_done, bool reset) // //=========================================================================== +CVAR(Bool,st_oldouch,false,CVAR_ARCHIVE) int FMugShot::UpdateState(player_t *player, StateFlags stateflags) { int i; @@ -357,9 +358,10 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) } } + bool ouch = (!st_oldouch && FaceHealth - player->health > ST_MUCHPAIN) || (st_oldouch && player->health - FaceHealth > ST_MUCHPAIN); if (player->damagecount && // Now go in if pain is disabled but we think ouch will be shown (and ouch is not disabled!) - (!(stateflags & DISABLEPAIN) || (((FaceHealth != -1 && FaceHealth - player->health > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH)))) + (!(stateflags & DISABLEPAIN) || (((FaceHealth != -1 && ouch) || bOuchActive) && !(stateflags & DISABLEOUCH)))) { int damage_angle = 1; if (player->attacker && player->attacker != player->mo) @@ -391,7 +393,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) } } bool use_ouch = false; - if (((FaceHealth != -1 && FaceHealth - player->health > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH)) + if (((FaceHealth != -1 && ouch) || bOuchActive) && !(stateflags & DISABLEOUCH)) { use_ouch = true; full_state_name = "ouch."; @@ -418,7 +420,7 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) else { bool use_ouch = false; - if (((FaceHealth != -1 && player->health - FaceHealth > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH)) + if (((FaceHealth != -1 && ouch) || bOuchActive) && !(stateflags & DISABLEOUCH)) { use_ouch = true; full_state_name = "ouch."; diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index f31fb491..c469bb73 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -423,6 +423,8 @@ static void FreeSBarInfoScript() void SBarInfo::Load() { + FreeSBarInfoScript(); + MugShotStates.Clear(); if(gameinfo.statusbar.IsNotEmpty()) { int lump = Wads.CheckNumForFullName(gameinfo.statusbar, true); @@ -1153,8 +1155,8 @@ public: if((offsetflags & SBarInfoCommand::CENTER) == SBarInfoCommand::CENTER) { - dx -= (texture->GetScaledWidthDouble()/2.0)-texture->LeftOffset; - dy -= (texture->GetScaledHeightDouble()/2.0)-texture->TopOffset; + dx -= (texture->GetScaledWidthDouble()/2.0)-texture->GetScaledLeftOffsetDouble(); + dy -= (texture->GetScaledHeightDouble()/2.0)-texture->GetScaledTopOffsetDouble(); } dx += xOffset; @@ -1188,7 +1190,7 @@ public: } if(clearDontDraw) - screen->Clear(static_cast(MAX(dx, dcx)), static_cast(MAX(dy, dcy)), static_cast(dcr), static_cast(dcb), GPalette.BlackIndex, 0); + screen->Clear(static_cast(MAX(dx, dcx)), static_cast(MAX(dy, dcy)), static_cast(MIN(dcr,w+MAX(dx, dcx))), static_cast(MIN(dcb,MAX(dy, dcy)+h)), GPalette.BlackIndex, 0); else { if(alphaMap) diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 3b612368..c63b009e 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2660,6 +2660,58 @@ class CommandPlayerClass : public SBarInfoCommandFlowControl //////////////////////////////////////////////////////////////////////////////// +class CommandPlayerType : public SBarInfoCommandFlowControl +{ + public: + CommandPlayerType(SBarInfo *script) : SBarInfoCommandFlowControl(script) + { + } + + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_Identifier); + do + { + bool foundClass = false; + const PClass *cls = PClass::FindClass(sc.String); + if (cls != NULL) + { + foundClass = true; + classes.Push(cls); + } + /* + if(!foundClass) + sc.ScriptError("Unkown PlayerClass '%s'.", sc.String); + */ + if(!sc.CheckToken(',')) + break; + } + while(sc.CheckToken(TK_Identifier)); + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + + if(statusBar->CPlayer->cls == NULL) + return; //No class so we can not continue + + for(unsigned int i = 0;i < classes.Size();i++) + { + if (statusBar->CPlayer->cls->IsDescendantOf(classes[i])) + { + SetTruth(true, block, statusBar); + return; + } + } + SetTruth(false, block, statusBar); + } + protected: + TArray classes; +}; + +//////////////////////////////////////////////////////////////////////////////// + class CommandHasWeaponPiece : public SBarInfoCommandFlowControl { public: @@ -2730,7 +2782,7 @@ class CommandDrawGem : public SBarInfoCommand SBarInfoCoordinate drawY = y; if(wiggle && drawValue != goalValue) // Should only wiggle when the value doesn't equal what is being drawn. drawY += chainWiggle; - int chainWidth = chainImg->GetWidth(); + int chainWidth = chainImg->GetScaledWidth(); int offset = (int) (((double) (chainWidth-leftPadding-rightPadding)/100)*drawValue); statusBar->DrawGraphic(chainImg, x+(offset%chainSize), drawY, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); if(gemImg != NULL) @@ -3082,7 +3134,7 @@ static const char *SBarInfoCommandNames[] = "drawmugshot", "drawselectedinventory", "drawinventorybar", "drawbar", "drawgem", "drawshader", "drawstring", "drawkeybar", - "gamemode", "playerclass", "aspectratio", + "gamemode", "playerclass", "playertype", "aspectratio", "isselected", "usesammo", "usessecondaryammo", "hasweaponpiece", "inventorybarnotvisible", "weaponammo", "ininventory", "alpha", @@ -3095,7 +3147,7 @@ enum SBarInfoCommands SBARINFO_DRAWMUGSHOT, SBARINFO_DRAWSELECTEDINVENTORY, SBARINFO_DRAWINVENTORYBAR, SBARINFO_DRAWBAR, SBARINFO_DRAWGEM, SBARINFO_DRAWSHADER, SBARINFO_DRAWSTRING, SBARINFO_DRAWKEYBAR, - SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_ASPECTRATIO, + SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_PLAYERTYPE, SBARINFO_ASPECTRATIO, SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO, SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE, SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, SBARINFO_ALPHA, @@ -3126,6 +3178,7 @@ SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc) case SBARINFO_ASPECTRATIO: return new CommandAspectRatio(script); case SBARINFO_ISSELECTED: return new CommandIsSelected(script); case SBARINFO_PLAYERCLASS: return new CommandPlayerClass(script); + case SBARINFO_PLAYERTYPE: return new CommandPlayerType(script); case SBARINFO_HASWEAPONPIECE: return new CommandHasWeaponPiece(script); case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script); case SBARINFO_ININVENTORY: return new CommandInInventory(script); diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 31dc116a..72e780f5 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -124,16 +124,16 @@ void SetHUDIcon(PClass *cls, FTextureID tex) //--------------------------------------------------------------------------- static void DrawImageToBox(FTexture * tex, int x, int y, int w, int h, int trans=0xc000) { - float scale1, scale2; + double scale1, scale2; if (tex) { int texwidth=tex->GetWidth(); int texheight=tex->GetHeight(); - if (wGetChar(text[i], &width); if (texc != NULL) { - int offset = texc->TopOffset - tex_zero->TopOffset + tex_zero->GetHeight(); + double offset = texc->GetScaledTopOffsetDouble() + - tex_zero->GetScaledTopOffsetDouble() + + tex_zero->GetScaledHeightDouble(); + screen->DrawChar(font, color, x, y, text[i], DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, - DTA_LeftOffset, width/2, DTA_TopOffset, offset, + DTA_LeftOffset, width/2, DTA_TopOffsetF, offset, /*DTA_CenterBottomOffset, 1,*/ TAG_DONE); } x += zerowidth; @@ -280,16 +283,42 @@ static void DrawHealth(int health, int x, int y) //=========================================================================== // // Draw Armor. -// very similar to drawhealth. +// very similar to drawhealth, but adapted to handle Hexen armor too // //=========================================================================== -static void DrawArmor(AInventory * armor, int x, int y) +static void DrawArmor(ABasicArmor * barmor, AHexenArmor * harmor, int x, int y) { - if (armor) - { - int ap=armor->Amount; + int ap = 0; + int bestslot = 4; + if (harmor) + { + int ac = (harmor->Slots[0] + harmor->Slots[1] + harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]); + ac >>= FRACBITS; + ap += ac; + + if (ac) + { + // Find the part of armor that protects the most + bestslot = 0; + for (int i = 1; i < 4; ++i) + { + if (harmor->Slots[i] > harmor->Slots[bestslot]) + { + bestslot = i; + } + } + } + } + + if (barmor) + { + ap += barmor->Amount; + } + + if (ap) + { // decide on color int fontcolor = ap < hud_armor_red ? CR_RED : @@ -298,11 +327,23 @@ static void DrawArmor(AInventory * armor, int x, int y) CR_BLUE; - if (ap) + // Use the sprite of one of the predefined Hexen armor bonuses. + // This is not a very generic approach, but it is not possible + // to truly create new types of Hexen armor bonus items anyway. + if (harmor && bestslot < 4) { - DrawImageToBox(TexMan[armor->Icon], x, y, 31, 17); - DrawHudNumber(HudFont, fontcolor, ap, x + 33, y + 17); + char icon[] = "AR_1A0"; + switch (bestslot) + { + case 1: icon[3] = '2'; break; + case 2: icon[3] = '3'; break; + case 3: icon[3] = '4'; break; + default: break; + } + DrawImageToBox(TexMan.FindTexture(icon, FTexture::TEX_Sprite), x, y, 31, 17); } + else if (barmor) DrawImageToBox(TexMan[barmor->Icon], x, y, 31, 17); + DrawHudNumber(HudFont, fontcolor, ap, x + 33, y + 17); } } @@ -766,14 +807,11 @@ static void DrawCoordinates(player_t * CPlayer) // draw the overlay // //--------------------------------------------------------------------------- -void HUD_InitHud(); void DrawHUD() { player_t * CPlayer = StatusBar->CPlayer; - if (HudFont==NULL) HUD_InitHud(); - players[consoleplayer].inventorytics = 0; if (hud_althudscale && SCREENWIDTH>640) { @@ -815,9 +853,8 @@ void DrawHUD() DrawFrags(CPlayer, 5, hudheight-70); } DrawHealth(CPlayer->health, 5, hudheight-45); - // Yes, that doesn't work properly for Hexen but frankly, I have no - // idea how to make a meaningful value out of Hexen's armor system! - DrawArmor(CPlayer->mo->FindInventory(RUNTIME_CLASS(ABasicArmor)), 5, hudheight-20); + DrawArmor(CPlayer->mo->FindInventory(), + CPlayer->mo->FindInventory(), 5, hudheight-20); i=DrawKeys(CPlayer, hudwidth-4, hudheight-10); i=DrawAmmo(CPlayer, hudwidth-5, i); DrawWeapons(CPlayer, hudwidth-5, i); @@ -830,10 +867,9 @@ void DrawHUD() } else { + FString mapname; char printstr[256]; int seconds; - cluster_info_t *thiscluster = FindClusterInfo (level.cluster); - bool hub = !!(thiscluster->flags&CLUSTER_HUB); int length=8*SmallFont->GetCharWidth('0'); int fonth=SmallFont->GetHeight()+1; int bottom=hudheight-1; @@ -862,8 +898,8 @@ void DrawHUD() } } - mysnprintf(printstr, countof(printstr), "%s: %s", level.mapname, level.LevelName.GetChars()); - screen->DrawText(SmallFont, hudcolor_titl, 1, hudheight-fonth-1, printstr, + ST_FormatMapName(mapname); + screen->DrawText(SmallFont, hudcolor_titl, 1, hudheight-fonth-1, mapname, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, TAG_DONE); diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index beb459cd..3091d63e 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -95,12 +95,16 @@ CUSTOM_CVAR (Bool, st_scale, true, CVAR_ARCHIVE) } } -CVAR (Int, crosshair, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, crosshairforce, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -CVAR (Bool, crosshairhealth, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -CVAR (Bool, crosshairscale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); -CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); +CVAR (Int, crosshair, 0, CVAR_ARCHIVE) +CVAR (Bool, crosshairforce, false, CVAR_ARCHIVE) +CVAR (Color, crosshaircolor, 0xff0000, CVAR_ARCHIVE); +CVAR (Bool, crosshairhealth, true, CVAR_ARCHIVE); +CVAR (Bool, crosshairscale, false, CVAR_ARCHIVE); +CVAR (Bool, crosshairgrow, false, CVAR_ARCHIVE); +CUSTOM_CVAR(Int, am_showmaplabel, 2, CVAR_ARCHIVE) +{ + if (self < 0 || self > 2) self = 2; +} CVAR (Bool, idmypos, false, 0); @@ -118,6 +122,30 @@ BYTE DBaseStatusBar::DamageToAlpha[114] = 230, 231, 232, 233, 234, 235, 235, 236, 237 }; +//--------------------------------------------------------------------------- +// +// Format the map name, include the map label if wanted +// +//--------------------------------------------------------------------------- + +void ST_FormatMapName(FString &mapname, const char *mapnamecolor) +{ + cluster_info_t *cluster = FindClusterInfo (level.cluster); + bool ishub = (cluster != NULL && (cluster->flags & CLUSTER_HUB)); + + if (am_showmaplabel == 1 || (am_showmaplabel == 2 && !ishub)) + { + mapname << level.mapname << ": "; + } + mapname << mapnamecolor << level.LevelName; +} + +//--------------------------------------------------------------------------- +// +// Load crosshair definitions +// +//--------------------------------------------------------------------------- + void ST_LoadCrosshair(bool alwaysload) { int num = 0; @@ -169,6 +197,23 @@ void ST_LoadCrosshair(bool alwaysload) CrosshairImage = TexMan[TexMan.CheckForTexture(name, FTexture::TEX_MiscPatch)]; } +//--------------------------------------------------------------------------- +// +// ST_Clear +// +//--------------------------------------------------------------------------- + +void ST_Clear() +{ + if (StatusBar != NULL) + { + StatusBar->Destroy(); + StatusBar = NULL; + } + CrosshairImage = NULL; + CrosshairNum = 0; +} + //--------------------------------------------------------------------------- // // Constructor @@ -208,6 +253,7 @@ void DBaseStatusBar::Destroy () msg->Destroy(); msg = next; } + Messages = NULL; Super::Destroy(); } @@ -1270,18 +1316,9 @@ void DBaseStatusBar::Draw (EHudState state) y -= 8; } } - cluster_info_t *cluster = FindClusterInfo (level.cluster); - if (cluster == NULL || !(cluster->flags & CLUSTER_HUB)) - { - mysnprintf (line, countof(line), "%s: ", level.mapname); - } - else - { - *line = 0; - } FString mapname; - mapname.Format("%s%c%c%s", line, TEXTCOLOR_ESCAPE, CR_GREY + 'A', level.LevelName.GetChars()); + ST_FormatMapName(mapname, TEXTCOLOR_GREY); screen->DrawText (SmallFont, highlight, (SCREENWIDTH - SmallFont->StringWidth (mapname)*CleanXfac)/2, y, mapname, DTA_CleanNoMove, true, TAG_DONE); diff --git a/src/gi.cpp b/src/gi.cpp index 18f8a667..0e010724 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -77,7 +77,7 @@ static gameborder_t StrifeBorder = // Custom GAMEINFO ------------------------------------------------------------ -const char* GameInfoBoarders[] = +const char* GameInfoBorders[] = { "DoomBorder", "HereticBorder", @@ -163,6 +163,28 @@ const char* GameInfoBoarders[] = } \ } +#define GAMEINFOKEY_FONT(key, variable) \ + else if(nextKey.CompareNoCase(variable) == 0) \ + { \ + sc.MustGetToken(TK_StringConst); \ + gameinfo.key.fontname = sc.String; \ + if (sc.CheckToken(',')) { \ + sc.MustGetToken(TK_StringConst); \ + gameinfo.key.color = sc.String; \ + } else { \ + gameinfo.key.color = NAME_None; \ + } \ + } + +#define GAMEINFOKEY_PATCH(key, variable) \ + else if(nextKey.CompareNoCase(variable) == 0) \ + { \ + sc.MustGetToken(TK_StringConst); \ + gameinfo.key.fontname = sc.String; \ + gameinfo.key.color = NAME_Null; \ + } + + void FMapInfoParser::ParseGameInfo() { sc.MustGetToken('{'); @@ -197,7 +219,7 @@ void FMapInfoParser::ParseGameInfo() { if(sc.CheckToken(TK_Identifier)) { - switch(sc.MustMatchString(GameInfoBoarders)) + switch(sc.MustMatchString(GameInfoBorders)) { default: gameinfo.border = &DoomBorder; @@ -247,6 +269,17 @@ void FMapInfoParser::ParseGameInfo() gameinfo.ArmorIcon2[8] = 0; } } + else if(nextKey.CompareNoCase("maparrow") == 0) + { + sc.MustGetToken(TK_StringConst); + gameinfo.mMapArrow = sc.String; + if (sc.CheckToken(',')) + { + sc.MustGetToken(TK_StringConst); + gameinfo.mCheatMapArrow = sc.String; + } + else gameinfo.mCheatMapArrow = ""; + } // Insert valid keys here. GAMEINFOKEY_CSTRING(titlePage, "titlePage", 8) GAMEINFOKEY_STRINGARRAY(creditPages, "creditPage", 8) @@ -300,6 +333,11 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_INT(TextScreenX, "textscreenx") GAMEINFOKEY_INT(TextScreenY, "textscreeny") GAMEINFOKEY_STRING(DefaultEndSequence, "defaultendsequence") + GAMEINFOKEY_FONT(mStatscreenMapNameFont, "statscreen_mapnamefont") + GAMEINFOKEY_FONT(mStatscreenFinishedFont, "statscreen_finishedfont") + GAMEINFOKEY_FONT(mStatscreenEnteringFont, "statscreen_enteringfont") + GAMEINFOKEY_PATCH(mStatscreenFinishedFont, "statscreen_finishedpatch") + GAMEINFOKEY_PATCH(mStatscreenEnteringFont, "statscreen_enteringpatch") else { diff --git a/src/gi.h b/src/gi.h index 7559a2c4..647db1a9 100644 --- a/src/gi.h +++ b/src/gi.h @@ -46,7 +46,7 @@ #define GI_COMPATSTAIRS 0x00000020 // same for stairbuilding #define GI_COMPATPOLY1 0x00000040 // Hexen's MAP36 needs old polyobject drawing #define GI_COMPATPOLY2 0x00000080 // so does HEXDD's MAP47 -#define GI_NOTEXTCOLOR 0x00000100 +#define GI_NOTEXTCOLOR 0x00000100 // Chex Quest 3 would have everything green #include "gametype.h" @@ -66,6 +66,12 @@ struct gameborder_t char br[8]; }; +struct FGIFont +{ + FName fontname; + FName color; +}; + struct gameinfo_t { int flags; @@ -129,6 +135,10 @@ struct gameinfo_t int TextScreenX; int TextScreenY; FName DefaultEndSequence; + FString mMapArrow, mCheatMapArrow; + FGIFont mStatscreenMapNameFont; + FGIFont mStatscreenFinishedFont; + FGIFont mStatscreenEnteringFont; const char *GetFinalePage(unsigned int num) const; }; diff --git a/src/gl/data/gl_data.cpp b/src/gl/data/gl_data.cpp index b4647ee6..721a8d4e 100644 --- a/src/gl/data/gl_data.cpp +++ b/src/gl/data/gl_data.cpp @@ -153,8 +153,8 @@ static int LS_Sector_SetPlaneReflection (line_t *ln, AActor *it, bool backSide, while ((secnum = P_FindSectorFromTag (arg0, secnum)) >= 0) { sector_t * s = §ors[secnum]; - if (s->floorplane.a==0 && s->floorplane.b==0) s->floor_reflect = arg1/255.f; - if (s->ceilingplane.a==0 && s->ceilingplane.b==0) sectors[secnum].ceiling_reflect = arg2/255.f; + if (s->floorplane.a==0 && s->floorplane.b==0) s->reflect[sector_t::floor] = arg1/255.f; + if (s->ceilingplane.a==0 && s->ceilingplane.b==0) sectors[secnum].reflect[sector_t::ceiling] = arg2/255.f; } return true; diff --git a/src/gl/data/gl_data.h b/src/gl/data/gl_data.h index f2b02468..4bf611f8 100644 --- a/src/gl/data/gl_data.h +++ b/src/gl/data/gl_data.h @@ -23,30 +23,28 @@ struct GLRenderSettings extern GLRenderSettings glset; #include "r_defs.h" +#include "a_sharedglobal.h" void gl_RecalcVertexHeights(vertex_t * v); FTextureID gl_GetSpriteFrame(unsigned sprite, int frame, int rot, angle_t ang, bool *mirror); class AStackPoint; +struct GLSectorStackPortal; struct FPortal { - TArray Shape; // forms the smallest convex outline around the portal area - TArray ClipAngles; fixed_t xDisplacement; fixed_t yDisplacement; int plane; - AStackPoint *origin; + GLSectorStackPortal *glportal; // for quick access to the render data. This is only valid during BSP traversal! - int PointOnShapeLineSide(fixed_t x, fixed_t y, int shapeindex); - void AddVertexToShape(vertex_t *vertex); - void AddSectorToPortal(sector_t *sector); - void UpdateClipAngles(); + GLSectorStackPortal *GetGLPortal(); }; -extern TArray portals; +extern TArray portals; +extern TArray currentmapsection; void gl_InitPortals(); - +void gl_BuildPortalCoverage(FPortalCoverage *coverage, subsector_t *subsector, FPortal *portal); #endif diff --git a/src/gl/data/gl_portaldata.cpp b/src/gl/data/gl_portaldata.cpp index 239ff0b4..2d614e4e 100644 --- a/src/gl/data/gl_portaldata.cpp +++ b/src/gl/data/gl_portaldata.cpp @@ -57,25 +57,48 @@ #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/scene/gl_clipper.h" +#include "gl/scene/gl_portal.h" #include "gl/dynlights/gl_dynlight.h" #include "gl/dynlights/gl_glow.h" #include "gl/utility/gl_clock.h" #include "gl/gl_functions.h" -TArray portals; - -//========================================================================== -// -// -// -//========================================================================== - -int FPortal::PointOnShapeLineSide(fixed_t x, fixed_t y, int shapeindex) +struct FPortalID { - int shapeindex2 = (shapeindex+1)%Shape.Size(); + fixed_t mXDisplacement; + fixed_t mYDisplacement; - return DMulScale32(y - Shape[shapeindex]->y, Shape[shapeindex2]->x - Shape[shapeindex]->x, - Shape[shapeindex]->x - x, Shape[shapeindex2]->y - Shape[shapeindex]->y); + // for the hash code + operator intptr_t() const { return (mXDisplacement >> 8) + (mYDisplacement << 8); } + bool operator != (const FPortalID &other) const + { + return mXDisplacement != other.mXDisplacement || + mYDisplacement != other.mYDisplacement; + } +}; + +struct FPortalSector +{ + sector_t *mSub; + int mPlane; +}; + +typedef TArray FPortalSectors; + +typedef TMap FPortalMap; + +TArray portals; + +//========================================================================== +// +// +// +//========================================================================== + +GLSectorStackPortal *FPortal::GetGLPortal() +{ + if (glportal == NULL) glportal = new GLSectorStackPortal(this); + return glportal; } //========================================================================== @@ -84,123 +107,241 @@ int FPortal::PointOnShapeLineSide(fixed_t x, fixed_t y, int shapeindex) // //========================================================================== -void FPortal::AddVertexToShape(vertex_t *vertex) +struct FCoverageVertex { - for(unsigned i=0;ix == Shape[i]->x && vertex->y == Shape[i]->y) return; + return x != other.x || y != other.y; + } +}; + +struct FCoverageLine +{ + FCoverageVertex v[2]; +}; + +struct FCoverageBuilder +{ + subsector_t *target; + FPortal *portal; + TArray collect; + FCoverageVertex center; + + //========================================================================== + // + // + // + //========================================================================== + + FCoverageBuilder(subsector_t *sub, FPortal *port) + { + target = sub; + portal = port; } - if (Shape.Size() < 2) + //========================================================================== + // + // GetIntersection + // + // adapted from P_InterceptVector + // + //========================================================================== + + bool GetIntersection(FCoverageVertex *v1, FCoverageVertex *v2, node_t *bsp, FCoverageVertex *v) { - Shape.Push(vertex); + double frac; + double num; + double den; + + double v2x = (double)v1->x; + double v2y = (double)v1->y; + double v2dx = (double)(v2->x - v1->x); + double v2dy = (double)(v2->y - v1->y); + double v1x = (double)bsp->x; + double v1y = (double)bsp->y; + double v1dx = (double)bsp->dx; + double v1dy = (double)bsp->dy; + + den = v1dy*v2dx - v1dx*v2dy; + + if (den == 0) + return false; // parallel + + num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx; + frac = num / den; + + if (frac < 0. || frac > 1.) return false; + + v->x = xs_RoundToInt(v2x + frac * v2dx); + v->y = xs_RoundToInt(v2y + frac * v2dy); + return true; } - else if (Shape.Size() == 2) - { - // Special case: We need to check if the vertex is on an extension of the line between the first two vertices. - int pos = PointOnShapeLineSide(vertex->x, vertex->y, 0); - if (pos == 0) - { - fixed_t distv1 = P_AproxDistance(vertex->x - Shape[0]->x, vertex->y - Shape[0]->y); - fixed_t distv2 = P_AproxDistance(vertex->x - Shape[1]->x, vertex->y - Shape[1]->y); - fixed_t distvv = P_AproxDistance(Shape[0]->x - Shape[1]->x, Shape[0]->y - Shape[1]->y); + //========================================================================== + // + // + // + //========================================================================== - if (distv1 > distvv) - { - Shape[1] = vertex; - } - else if (distv2 > distvv) - { - Shape[0] = vertex; - } - return; - } - else if (pos > 0) - { - Shape.Insert(1, vertex); - } - else - { - Shape.Push(vertex); - } + double PartitionDistance(FCoverageVertex *vt, node_t *node) + { + return fabs(double(-node->dy) * (vt->x - node->x) + double(node->dx) * (vt->y - node->y)) / node->len; } - else - { - for(unsigned i=0; ix, vertex->y, i); - if (startlinepos >= 0) - { - int previouslinepos = PointOnShapeLineSide(vertex->x, vertex->y, (i+Shape.Size()-1)%Shape.Size()); - if (previouslinepos < 0) // we found the first line for which the vertex lies in front + //========================================================================== + // + // + // + //========================================================================== + + int PointOnSide(FCoverageVertex *vt, node_t *node) + { + return R_PointOnSide(vt->x, vt->y, node); + } + + //========================================================================== + // + // adapted from polyobject splitter + // + //========================================================================== + + void CollectNode(void *node, TArray &shape) + { + static TArray lists[2]; + const double COVERAGE_EPSILON = 6.; // same epsilon as the node builder + + if (!((size_t)node & 1)) // Keep going until found a subsector + { + node_t *bsp = (node_t *)node; + + int centerside = R_PointOnSide(center.x, center.y, bsp); + + lists[0].Clear(); + lists[1].Clear(); + for(unsigned i=0;ix, vertex->y, nextpoint) >= 0); - - int removecount = (nextpoint - i + Shape.Size()) % Shape.Size() - 1; - - if (removecount == 0) - { - if (startlinepos > 0) - { - Shape.Insert(i+1, vertex); - } - } - else if (nextpoint > i || nextpoint == 0) - { - // The easy case: It doesn't wrap around - Shape.Delete(i+1, removecount-1); - Shape[i+1] = vertex; + lists[centerside].Push(vl); } else { - // It does wrap around. - Shape.Delete(i+1, removecount); - Shape.Delete(1, nextpoint-1); - Shape[0] = vertex; + int side = PointOnSide(v2, bsp); + lists[side].Push(vl); + } + } + else if (dist_v2 <= COVERAGE_EPSILON) + { + int side = PointOnSide(v1, bsp); + lists[side].Push(vl); + } + else + { + int side1 = PointOnSide(v1, bsp); + int side2 = PointOnSide(v2, bsp); + + if(side1 != side2) + { + // if the partition line crosses this seg, we must split it. + + FCoverageVertex vert; + + if (GetIntersection(v1, v2, bsp, &vert)) + { + lists[0].Push(vl); + lists[1].Push(vl); + lists[side1].Last().v[1] = vert; + lists[side2].Last().v[0] = vert; + } + else + { + // should never happen + lists[side1].Push(vl); + } + } + else + { + // both points on the same side. + lists[side1].Push(vl); } - return; } } + if (lists[1].Size() == 0) + { + CollectNode(bsp->children[0], shape); + } + else if (lists[0].Size() == 0) + { + CollectNode(bsp->children[1], shape); + } + else + { + // copy the static arrays into local ones + TArray locallists[2]; + + for(int l=0;l<2;l++) + { + for (unsigned i=0;ichildren[0], locallists[0]); + CollectNode(bsp->children[1], locallists[1]); + } + } + else + { + // we reached a subsector so we can link the node with this subsector + subsector_t *sub = (subsector_t *)((BYTE *)node - 1); + collect.Push(int(sub-subsectors)); } } -} +}; //========================================================================== // -// +// Calculate portal coverage for a single subsector // //========================================================================== -void FPortal::AddSectorToPortal(sector_t *sector) +void gl_BuildPortalCoverage(FPortalCoverage *coverage, subsector_t *subsector, FPortal *portal) { - for(int i=0; ilinecount; i++) - { - AddVertexToShape(sector->lines[i]->v1); - // This is necessary to handle unclosed sectors - AddVertexToShape(sector->lines[i]->v2); - } -} + TArray shape; + double centerx=0, centery=0; -//========================================================================== -// -// -// -//========================================================================== - -void FPortal::UpdateClipAngles() -{ - for(unsigned int i=0; inumlines); + for(unsigned i=0; inumlines; i++) { - ClipAngles[i] = R_PointToPseudoAngle(viewx, viewy, Shape[i]->x, Shape[i]->y); + centerx += (shape[i].x = subsector->firstline[i].v1->x + portal->xDisplacement); + centery += (shape[i].y = subsector->firstline[i].v1->y + portal->yDisplacement); } + + FCoverageBuilder build(subsector, portal); + build.center.x = xs_CRoundToInt(centerx / subsector->numlines); + build.center.y = xs_CRoundToInt(centery / subsector->numlines); + + build.CollectNode(nodes + numnodes - 1, shape); + coverage->subsectors = new DWORD[build.collect.Size()]; + coverage->sscount = build.collect.Size(); + memcpy(coverage->subsectors, &build.collect[0], build.collect.Size() * sizeof(DWORD)); } //========================================================================== @@ -209,68 +350,124 @@ void FPortal::UpdateClipAngles() // //========================================================================== -void gl_InitPortals() +static void CollectPortalSectors(FPortalMap &collection) { - TThinkerIterator it; - AStackPoint *pt; - - portals.Clear(); - while ((pt = it.Next())) + for (int i=0;ispecial1 = -1; - for(int i=0;iCeilingSkyBox != NULL && sec->CeilingSkyBox->bAlways && sec->CeilingSkyBox->Mate != NULL) { - if (sectors[i].linecount == 0) - { - continue; - } - else if (sectors[i].FloorSkyBox == pt) - { - plane = 1; - } - else if (sectors[i].CeilingSkyBox == pt) - { - plane = 2; - } - else continue; + FPortalID id = { sec->CeilingSkyBox->x - sec->CeilingSkyBox->Mate->x, + sec->CeilingSkyBox->y - sec->CeilingSkyBox->Mate->y}; - // we only process portals that actually are in use. - if (portal == NULL) - { - pt->special1 = portals.Size(); // Link portal thing to render data - portal = &portals[portals.Reserve(1)]; - portal->origin = pt; - portal->plane = 0; - portal->xDisplacement = pt->x - pt->Mate->x; - portal->yDisplacement = pt->y - pt->Mate->y; - } - portal->AddSectorToPortal(§ors[i]); - portal->plane|=plane; + FPortalSectors &sss = collection[id]; + FPortalSector ss = { sec, sector_t::ceiling }; + sss.Push(ss); } - if (portal != NULL) + + if (sec->FloorSkyBox != NULL && sec->FloorSkyBox->bAlways && sec->FloorSkyBox->Mate != NULL) { - // if the first vertex is duplicated at the end it'll save time in a time critical function - // because that code does not need to check for wraparounds anymire. - portal->Shape.Resize(portal->Shape.Size()+1); - portal->Shape[portal->Shape.Size()-1] = portal->Shape[0]; - portal->Shape.ShrinkToFit(); - portal->ClipAngles.Resize(portal->Shape.Size()); + FPortalID id = { sec->FloorSkyBox->x - sec->FloorSkyBox->Mate->x, + sec->FloorSkyBox->y - sec->FloorSkyBox->Mate->y }; + + FPortalSectors &sss = collection[id]; + FPortalSector ss = { sec, sector_t::floor }; + sss.Push(ss); } } } +void gl_InitPortals() +{ + FPortalMap collection; + + if (numnodes == 0) return; + + for(int i=0;idx; + double fdy = (double)no->dy; + no->len = (float)sqrt(fdx * fdx + fdy * fdy); + } + + CollectPortalSectors(collection); + portals.Clear(); + + FPortalMap::Iterator it(collection); + FPortalMap::Pair *pair; + int c = 0; + int planeflags = 0; + while (it.NextPair(pair)) + { + for(unsigned i=0;iValue.Size(); i++) + { + if (pair->Value[i].mPlane == sector_t::floor) planeflags |= 1; + else if (pair->Value[i].mPlane == sector_t::ceiling) planeflags |= 2; + } + for (int i=1;i<=2;i<<=1) + { + // For now, add separate portals for floor and ceiling. They can be merged once + // proper plane clipping is in. + if (planeflags & i) + { + FPortal *portal = new FPortal; + portal->xDisplacement = pair->Key.mXDisplacement; + portal->yDisplacement = pair->Key.mYDisplacement; + portal->plane = (i==1? sector_t::floor : sector_t::ceiling); /**/ + portals.Push(portal); + for(unsigned j=0;jValue.Size(); j++) + { + sector_t *sec = pair->Value[j].mSub; + int plane = pair->Value[j].mPlane; + if (portal->plane == plane) + { + for(int k=0;ksubsectorcount; k++) + { + subsector_t *sub = sec->subsectors[k]; + gl_BuildPortalCoverage(&sub->portalcoverage[plane], sub, portal); + } + sec->portals[plane] = portal; + } + } + } + } + } +} CCMD(dumpportals) { for(unsigned i=0;ix/65536., portals[i].origin->y/65536., - portals[i].origin->x/65536. - portals[i].origin->Mate->x/65536., portals[i].origin->y/65536. - portals[i].origin->Mate->y/65536.); - for (unsigned j=0;jxDisplacement/65536.; + double ydisp = portals[i]->yDisplacement/65536.; + Printf(PRINT_LOG, "Portal #%d, %s, displacement = (%f,%f)\n", i, portals[i]->plane==0? "floor":"ceiling", + xdisp, ydisp); + Printf(PRINT_LOG, "Coverage:\n"); + for(int j=0;jx + portals[i].xDisplacement)/65536., (portals[i].Shape[j]->y + portals[i].yDisplacement)/65536.); + subsector_t *sub = &subsectors[j]; + FPortal *port = sub->render_sector->portals[portals[i]->plane]; + if (port == portals[i]) + { + Printf(PRINT_LOG, "\tSubsector %d (%d):\n\t\t", j, sub->render_sector->sectornum); + for(unsigned k = 0;k< sub->numlines; k++) + { + Printf(PRINT_LOG, "(%.3f,%.3f), ", sub->firstline[k].v1->x/65536. + xdisp, sub->firstline[k].v1->y/65536. + ydisp); + } + Printf(PRINT_LOG, "\n\t\tCovered by subsectors:\n"); + FPortalCoverage *cov = &sub->portalcoverage[portals[i]->plane]; + for(int l = 0;l< cov->sscount; l++) + { + subsector_t *csub = &subsectors[cov->subsectors[l]]; + Printf(PRINT_LOG, "\t\t\t%5d (%4d): ", cov->subsectors[l], csub->render_sector->sectornum); + for(unsigned m = 0;m< csub->numlines; m++) + { + Printf(PRINT_LOG, "(%.3f,%.3f), ", csub->firstline[m].v1->x/65536., csub->firstline[m].v1->y/65536.); + } + Printf(PRINT_LOG, "\n"); + } + } } } } diff --git a/src/gl/data/gl_setup.cpp b/src/gl/data/gl_setup.cpp index 42c0bf90..55bbe0be 100644 --- a/src/gl/data/gl_setup.cpp +++ b/src/gl/data/gl_setup.cpp @@ -103,6 +103,153 @@ void gl_InitSegs() } } +//========================================================================== +// +// +// +//========================================================================== + +static void DoSetMapSection(subsector_t *sub, int num) +{ + sub->mapsection = num; + + for(DWORD i=0;inumlines;i++) + { + seg_t * seg = sub->firstline + i; + + if (seg->PartnerSeg) + { + subsector_t * sub2 = seg->PartnerSeg->Subsector(); + + if (sub2->mapsection != num) + { + assert(sub2->mapsection == 0); + DoSetMapSection(sub2, num); + } + } + } +} + +//========================================================================== +// +// Merge sections. This is needed in case the map contains errors +// like overlapping lines resulting in abnormal subsectors. +// +// This function ensures that any vertex position can only be in one section. +// +//========================================================================== + +struct cvertex_t +{ + fixed_t x, y; + + operator int () const { return ((x>>16)&0xffff) | y; } + bool operator!= (const cvertex_t &other) const { return x != other.x || y != other.y; } + cvertex_t& operator =(const vertex_t *v) { x = v->x; y = v->y; return *this; } +}; + +typedef TMap FSectionVertexMap; + +static int MergeMapSections(int num) +{ + FSectionVertexMap vmap; + FSectionVertexMap::Pair *pair; + TArray sectmap; + TArray sectvalid; + sectmap.Resize(num); + sectvalid.Resize(num); + for(int i=0;iSubsector()->mapsection; + for(int j=0;j<2;j++) + { + vt = j==0? seg->v1:seg->v2; + vmap[vt] = section; + } + } + + // second step: Check if any seg references more than one mapsection, either by subsector or by vertex + for(DWORD i=0;iSubsector()->mapsection; + for(int j=0;j<2;j++) + { + vt = j==0? seg->v1:seg->v2; + int vsection = vmap[vt]; + + if (vsection != section) + { + // These 2 sections should be merged + for(int k=0;kValue == vsection) pair->Value = section; + } + sectvalid[vsection-1] = false; + } + } + } + for(int i=0;ibox[BOXRIGHT]) box[BOXRIGHT] = x; - if (ybox[BOXTOP]) box[BOXTOP] = y; -} - static void SpreadHackedFlag(subsector_t * sub) { // The subsector pointer hasn't been set yet! @@ -147,27 +280,18 @@ static void SpreadHackedFlag(subsector_t * sub) } +//========================================================================== +// +// +// +//========================================================================== + static void PrepareSectorData() { int i; - size_t /*ii,*/ jj; TArray undetermined; subsector_t * ss; - // look up sector number for each subsector - for (i = 0; i < numsubsectors; i++) - { - ss = &subsectors[i]; - seg_t *seg = ss->firstline; - - M_ClearBox(ss->bbox); - for(jj=0; jjnumlines; jj++) - { - M_AddToBox(ss->bbox,seg->v1->x, seg->v1->y); - seg++; - } - } - // now group the subsectors by sector subsector_t ** subsectorbuffer = new subsector_t * [numsubsectors]; @@ -208,6 +332,7 @@ static void PrepareSectorData() } } } + SetMapSections(); } //========================================================================== @@ -216,6 +341,7 @@ static void PrepareSectorData() // - This will be used to lower the floor of such sectors by one map unit // //========================================================================== + static void PrepareTransparentDoors(sector_t * sector) { bool solidwall=false; @@ -300,12 +426,12 @@ static void PrepareTransparentDoors(sector_t * sector) } } - //========================================================================== // // // //========================================================================== + static void AddToVertex(const sector_t * sec, TArray & list) { int secno = int(sec-sectors); @@ -322,6 +448,7 @@ static void AddToVertex(const sector_t * sec, TArray & list) // Attach sectors to vertices - used to generate vertex height lists // //========================================================================== + static void InitVertexData() { TArray * vt_sectorlists; @@ -391,7 +518,7 @@ static void InitVertexData() //========================================================================== // -// Group segs to sidedefs +// // //========================================================================== @@ -421,6 +548,12 @@ static int STACK_ARGS segcmp(const void *a, const void *b) return xs_RoundToInt(FRACUNIT*(A->sidefrac - B->sidefrac)); } +//========================================================================== +// +// Group segs to sidedefs +// +//========================================================================== + static void PrepareSegs() { int *segcount = new int[numsides]; @@ -503,17 +636,18 @@ static void PrepareSegs() // Initialize the level data for the GL renderer // //========================================================================== +extern int restart; void gl_PreprocessLevel() { int i; - static bool datadone=false; + static int datadone=-1; - if (!datadone) + if (datadone != restart) { - datadone=true; + datadone = restart; gl_InitData(); } @@ -548,6 +682,7 @@ void gl_PreprocessLevel() // Cleans up all the GL data for the last level // //========================================================================== + void gl_CleanLevelData() { // Dynamic lights must be destroyed before the sector information here is deleted. @@ -587,17 +722,42 @@ void gl_CleanLevelData() delete [] sectors[0].subsectors; sectors[0].subsectors = NULL; } - if (gamenodes && gamenodes!=nodes) + for (int i=0;isectornum, int(subsectors[j].firstline->linedef-lines)); + break; + } + } + } +} \ No newline at end of file diff --git a/src/gl/dynlights/gl_dynlight.cpp b/src/gl/dynlights/gl_dynlight.cpp index 00b5dad3..9309f9b0 100644 --- a/src/gl/dynlights/gl_dynlight.cpp +++ b/src/gl/dynlights/gl_dynlight.cpp @@ -66,6 +66,7 @@ EXTERN_CVAR (Float, gl_lights_size); int ScriptDepth; void gl_InitGlow(FScanner &sc); void gl_ParseBrightmap(FScanner &sc, int); +void gl_DestroyUserShaders(); void gl_ParseHardwareShader(FScanner &sc, int deflump); void gl_ParseSkybox(FScanner &sc); void gl_ParseDetailTexture(FScanner &sc); @@ -1315,6 +1316,8 @@ void gl_ParseDefs() const char *defsLump = NULL; atterm( gl_ReleaseLights ); + gl_ReleaseLights(); + gl_DestroyUserShaders(); switch (gameinfo.gametype) { case GAME_Heretic: diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index 88140fe7..aa462b8a 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -258,6 +258,14 @@ void gl_InitModels() lastLump = 0; + for(unsigned i=0;inumlines; + seg_t * seg = sub->firstline; + + while (count--) + { + angle_t startAngle = seg->v2->GetClipAngle(); + angle_t endAngle = seg->v1->GetClipAngle(); + + // Back side, i.e. backface culling - read: endAngle >= startAngle! + if (startAngle-endAngle >= ANGLE_180) + { + clipper.SafeRemoveClipRange(startAngle, endAngle); + } + seg++; + } +} + //========================================================================== // // R_AddLine @@ -76,6 +96,13 @@ static sector_t *currentsector; static void AddLine (seg_t *seg) { +#ifdef _MSC_VER +#ifdef _DEBUG + if (seg->linedef-lines==38) + __asm nop +#endif +#endif + angle_t startAngle, endAngle; sector_t * backsector = NULL; sector_t bs; @@ -367,6 +394,17 @@ static void DoSubsector(subsector_t * sub) sector=sub->sector; if (!sector) return; + // If the mapsections differ this subsector can't possibly be visible from the current view point + if (!(currentmapsection[sub->mapsection>>3] & (1 << (sub->mapsection & 7)))) return; + + if (gl_drawinfo->ss_renderflags[sub-subsectors] & SSRF_SEEN) + { + // This means that we have reached a subsector in a portal that has been marked 'seen' + // from the other side of the portal. This means we must clear the clipper for the + // range this subsector spans before going on. + UnclipSubsector(sub); + } + fakesector=gl_FakeFlat(sector, &fake, false); if (sector->validcount != validcount) @@ -426,6 +464,14 @@ static void DoSubsector(subsector_t * sub) // Due to the way a BSP works such a subsector can never be visible if (!sector->heightsec || sector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || in_area!=area_default) { + if (sector != sub->render_sector) + { + sector = sub->render_sector; + // the planes of this subsector are faked to belong to another sector + // This means we need the heightsec parts and light info of the render sector, not the actual one. + fakesector = gl_FakeFlat(sector, &fake, false); + } + BYTE &srf = gl_drawinfo->sectorrenderflags[sub->render_sector->sectornum]; if (!(srf & SSRF_PROCESSED)) { @@ -434,13 +480,6 @@ static void DoSubsector(subsector_t * sub) SetupFlat.Clock(); //if (!gl_multithreading) { - if (sector != sub->render_sector) - { - sector = sub->render_sector; - // the planes of this subsector are faked to belong to another sector - // This means we need the heightsec parts and light info of the render sector, not the actual one! - fakesector = gl_FakeFlat(sector, &fake, false); - } GLRenderer->ProcessSector(fakesector); } /* @@ -456,6 +495,22 @@ static void DoSubsector(subsector_t * sub) gl_drawinfo->ss_renderflags[sub-subsectors] = (sub->numlines > 2) ? SSRF_PROCESSED|SSRF_RENDERALL : SSRF_PROCESSED; if (sub->hacked & 1) gl_drawinfo->AddHackedSubsector(sub); + + FPortal *portal; + + portal = fakesector->portals[sector_t::ceiling]; + if (portal != NULL) + { + GLSectorStackPortal *glportal = portal->GetGLPortal(); + glportal->AddSubsector(sub); + } + + portal = fakesector->portals[sector_t::floor]; + if (portal != NULL) + { + GLSectorStackPortal *glportal = portal->GetGLPortal(); + glportal->AddSubsector(sub); + } } } } @@ -496,7 +551,8 @@ void gl_RenderBSPNode (void *node) // It is not necessary to use the slower precise version here if (!clipper.CheckBox(bsp->bbox[side])) { - return; + if (!(gl_drawinfo->no_renderflags[bsp-nodes] & SSRF_SEEN)) + return; } node = bsp->children[side]; diff --git a/src/gl/scene/gl_clipper.cpp b/src/gl/scene/gl_clipper.cpp index 1d162044..bde49029 100644 --- a/src/gl/scene/gl_clipper.cpp +++ b/src/gl/scene/gl_clipper.cpp @@ -93,6 +93,14 @@ void Clipper::Clear() ClipNode *node = cliphead; ClipNode *temp; + while (node != NULL) + { + temp = node; + node = node->next; + temp->Free(); + } + node = silhouette; + while (node != NULL) { temp = node; @@ -101,9 +109,32 @@ void Clipper::Clear() } cliphead = NULL; + silhouette = NULL; anglecache++; } +//----------------------------------------------------------------------------- +// +// SetSilhouette +// +//----------------------------------------------------------------------------- + +void Clipper::SetSilhouette() +{ + ClipNode *node = cliphead; + ClipNode *last = NULL; + + while (node != NULL) + { + ClipNode *snode = ClipNode::NewRange(node->start, node->end); + if (silhouette == NULL) silhouette = snode; + snode->prev = last; + if (last != NULL) last->next = snode; + last = snode; + node = node->next; + } +} + //----------------------------------------------------------------------------- // @@ -243,8 +274,42 @@ void Clipper::AddClipRange(angle_t start, angle_t end) void Clipper::RemoveClipRange(angle_t start, angle_t end) { - ClipNode *node, *temp; + ClipNode *node; + + if (silhouette) + { + node = silhouette; + while (node != NULL && node->end <= start) + { + node = node->next; + } + if (node != NULL && node->start <= start) + { + if (node->end >= end) return; + start = node->end; + node = node->next; + } + while (node != NULL && node->start < end) + { + DoRemoveClipRange(start, node->start); + start = node->end; + node = node->next; + } + if (start >= end) return; + } + DoRemoveClipRange(start, end); +} +//----------------------------------------------------------------------------- +// +// RemoveClipRange worker function +// +//----------------------------------------------------------------------------- + +void Clipper::DoRemoveClipRange(angle_t start, angle_t end) +{ + ClipNode *node, *temp; + if (cliphead) { //check to see if range contains any old ranges diff --git a/src/gl/scene/gl_clipper.h b/src/gl/scene/gl_clipper.h index 4ad5c1b9..7139c9d6 100644 --- a/src/gl/scene/gl_clipper.h +++ b/src/gl/scene/gl_clipper.h @@ -51,12 +51,14 @@ class Clipper { ClipNode * clipnodes; ClipNode * cliphead; + ClipNode * silhouette; // will be preserved even when RemoveClipRange is called static angle_t AngleToPseudo(angle_t ang); bool IsRangeVisible(angle_t startangle, angle_t endangle); void RemoveRange(ClipNode * cn); void AddClipRange(angle_t startangle, angle_t endangle); void RemoveClipRange(angle_t startangle, angle_t endangle); + void DoRemoveClipRange(angle_t start, angle_t end); public: @@ -72,6 +74,7 @@ public: void Clear(); + void SetSilhouette(); bool SafeCheckRange(angle_t startAngle, angle_t endAngle) { diff --git a/src/gl/scene/gl_drawinfo.cpp b/src/gl/scene/gl_drawinfo.cpp index 0a1b435b..972dd168 100644 --- a/src/gl/scene/gl_drawinfo.cpp +++ b/src/gl/scene/gl_drawinfo.cpp @@ -44,6 +44,7 @@ #include "r_main.h" #include "gl/system/gl_cvars.h" +#include "gl/data/gl_data.h" #include "gl/scene/gl_drawinfo.h" #include "gl/scene/gl_portal.h" #include "gl/dynlights/gl_lightbuffer.h" @@ -939,9 +940,11 @@ void FDrawInfo::StartScene() sectorrenderflags.Resize(numsectors); ss_renderflags.Resize(numsubsectors); + no_renderflags.Resize(numsubsectors); memset(§orrenderflags[0], 0, numsectors*sizeof(sectorrenderflags[0])); memset(&ss_renderflags[0], 0, numsubsectors*sizeof(ss_renderflags[0])); + memset(&no_renderflags[0], 0, numnodes*sizeof(no_renderflags[0])); next=gl_drawinfo; gl_drawinfo=this; diff --git a/src/gl/scene/gl_drawinfo.h b/src/gl/scene/gl_drawinfo.h index f669b3aa..c598d988 100644 --- a/src/gl/scene/gl_drawinfo.h +++ b/src/gl/scene/gl_drawinfo.h @@ -191,6 +191,7 @@ struct FDrawInfo TArray sectorrenderflags; TArray ss_renderflags; + TArray no_renderflags; TArray MissingUpperTextures; TArray MissingLowerTextures; diff --git a/src/gl/scene/gl_fakeflat.cpp b/src/gl/scene/gl_fakeflat.cpp index 5d00972e..7f683ef8 100644 --- a/src/gl/scene/gl_fakeflat.cpp +++ b/src/gl/scene/gl_fakeflat.cpp @@ -44,6 +44,7 @@ #include "r_sky.h" #include "gl/renderer/gl_renderer.h" #include "gl/scene/gl_clipper.h" +#include "gl/data/gl_data.h" //========================================================================== @@ -70,10 +71,11 @@ bool gl_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto // Lines with stacked sectors must never block! - if (backsector->CeilingSkyBox && backsector->CeilingSkyBox->bAlways) return false; - if (backsector->FloorSkyBox && backsector->FloorSkyBox->bAlways) return false; - if (frontsector->CeilingSkyBox && frontsector->CeilingSkyBox->bAlways) return false; - if (frontsector->FloorSkyBox && frontsector->FloorSkyBox->bAlways) return false; + if (backsector->portals[sector_t::ceiling] != NULL || backsector->portals[sector_t::floor] != NULL || + frontsector->portals[sector_t::ceiling] != NULL || frontsector->portals[sector_t::floor] != NULL) + { + return false; + } // on large levels this distinction can save some time // That's a lot of avoided multiplications if there's a lot to see! @@ -206,7 +208,23 @@ bool CopyPlaneIfValid (secplane_t *dest, const secplane_t *source, const secplan //========================================================================== sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool back) { - if (!sec->heightsec || sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || sec->heightsec==sec) return sec; + if (!sec->heightsec || sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC || sec->heightsec==sec) + { + // check for backsectors with the ceiling lower than the floor. These will create + // visual glitches because upper amd lower textures overlap. + if (back && sec->planes[sector_t::floor].TexZ > sec->planes[sector_t::ceiling].TexZ) + { + if (!(sec->floorplane.a | sec->floorplane.b | sec->ceilingplane.a | sec->ceilingplane.b)) + { + *dest = *sec; + dest->ceilingplane=sec->floorplane; + dest->ceilingplane.FlipVert(); + dest->planes[sector_t::ceiling].TexZ = dest->planes[sector_t::floor].TexZ; + return dest; + } + } + return sec; + } #ifdef _MSC_VER #ifdef _DEBUG @@ -224,8 +242,13 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac int diffTex = (sec->heightsec->MoreFlags & SECF_CLIPFAKEPLANES); sector_t * s = sec->heightsec; - - *dest=*sec; + +#if 0 + *dest=*sec; // This will invoke the copy operator which isn't really needed here. Memcpy is faster. +#else + memcpy(dest, sec, sizeof(sector_t)); +#endif + // Replace floor and ceiling height with control sector's heights. if (diffTex) { @@ -298,6 +321,10 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::vbo_fakefloor]; dest->vboheight[sector_t::ceiling] = s->vboheight[sector_t::floor]; + if (!(s->MoreFlags & SECF_NOFAKELIGHT)) + { + dest->lightlevel = s->lightlevel; + } if (!back) { @@ -323,7 +350,6 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac if (!(s->MoreFlags & SECF_NOFAKELIGHT)) { - dest->lightlevel = s->lightlevel; dest->SetPlaneLight(sector_t::floor, s->GetPlaneLight(sector_t::floor)); dest->SetPlaneLight(sector_t::ceiling, s->GetPlaneLight(sector_t::ceiling)); dest->ChangeFlags(sector_t::floor, -1, s->GetFlags(sector_t::floor)); @@ -346,6 +372,11 @@ sector_t * gl_FakeFlat(sector_t * sec, sector_t * dest, area_t in_area, bool bac dest->vboindex[sector_t::ceiling] = sec->vboindex[sector_t::ceiling]; dest->vboheight[sector_t::ceiling] = sec->vboheight[sector_t::ceiling]; + if (!(s->MoreFlags & SECF_NOFAKELIGHT)) + { + dest->lightlevel = s->lightlevel; + } + if (!back) { dest->SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false); diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index eccae0f4..3174e5ca 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -449,11 +449,6 @@ inline void GLFlat::PutFlat(bool fog) { Colormap.GetFixedColormap(); } - if ((gl.flags&RFL_NOSTENCIL) && !(renderflags&SSRF_RENDER3DPLANES)) - { - renderstyle=STYLE_Translucent; - alpha=1.f; - } if (renderstyle!=STYLE_Translucent || alpha < 1.f - FLT_EPSILON || fog) { int list = (renderflags&SSRF_RENDER3DPLANES) ? GLDL_TRANSLUCENT : GLDL_TRANSLUCENTBORDER; @@ -602,14 +597,20 @@ void GLFlat::ProcessSector(sector_t * frontsector) if (frontsector->floorplane.ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)) <= FIXED2FLOAT(viewz)) { // process the original floor first. - if (frontsector->FloorSkyBox && frontsector->FloorSkyBox->bAlways) gl_drawinfo->AddFloorStack(sector); srf |= SSRF_RENDERFLOOR; lightlevel = GetFloorLight(frontsector); Colormap=frontsector->ColorMap; - stack = frontsector->FloorSkyBox && frontsector->FloorSkyBox->bAlways; - alpha= stack ? frontsector->FloorSkyBox->PlaneAlpha/65536.0f : 1.0f-frontsector->GetFloorReflect(); + if ((stack = (frontsector->portals[sector_t::floor] != NULL))) + { + gl_drawinfo->AddFloorStack(sector); + alpha = frontsector->GetAlpha(sector_t::floor)/65536.0f; + } + else + { + alpha = 1.0f-frontsector->GetReflect(sector_t::floor); + } if (frontsector->VBOHeightcheck(sector_t::floor)) { vboindex = frontsector->vboindex[sector_t::floor]; @@ -644,14 +645,21 @@ void GLFlat::ProcessSector(sector_t * frontsector) if (frontsector->ceilingplane.ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy)) >= FIXED2FLOAT(viewz)) { // process the original ceiling first. - if (frontsector->CeilingSkyBox && frontsector->CeilingSkyBox->bAlways) gl_drawinfo->AddCeilingStack(sector); srf |= SSRF_RENDERCEILING; lightlevel = GetCeilingLight(frontsector); Colormap=frontsector->ColorMap; - stack = frontsector->CeilingSkyBox && frontsector->CeilingSkyBox->bAlways; - alpha=stack ? frontsector->CeilingSkyBox->PlaneAlpha/65536.0f : 1.0f-frontsector->GetCeilingReflect(); + if ((stack = (frontsector->portals[sector_t::ceiling] != NULL))) + { + gl_drawinfo->AddCeilingStack(sector); + alpha = frontsector->GetAlpha(sector_t::ceiling)/65536.0f; + } + else + { + alpha = 1.0f-frontsector->GetReflect(sector_t::ceiling); + } + if (frontsector->VBOHeightcheck(sector_t::ceiling)) { vboindex = frontsector->vboindex[sector_t::ceiling]; diff --git a/src/gl/scene/gl_portal.cpp b/src/gl/scene/gl_portal.cpp index b4ba4936..fcba91d0 100644 --- a/src/gl/scene/gl_portal.cpp +++ b/src/gl/scene/gl_portal.cpp @@ -83,13 +83,11 @@ int GLPortal::renderdepth; int GLPortal::PlaneMirrorMode; GLuint GLPortal::QueryObject; -bool GLPortal::inupperstack; -bool GLPortal::inlowerstack; +int GLPortal::instack[2]; bool GLPortal::inskybox; UniqueList UniqueSkies; UniqueList UniqueHorizons; -UniqueList UniqueStacks; UniqueList UniquePlaneMirrors; @@ -104,7 +102,6 @@ void GLPortal::BeginScene() { UniqueSkies.Clear(); UniqueHorizons.Clear(); - UniqueStacks.Clear(); UniquePlaneMirrors.Clear(); } @@ -292,6 +289,9 @@ bool GLPortal::Start(bool usestencil, bool doquery) savedviewactor=GLRenderer->mViewActor; savedviewangle=viewangle; savedviewarea=in_area; + + NextPortal = GLRenderer->mCurrentPortal; + GLRenderer->mCurrentPortal = NULL; // Portals which need this have to set it themselves PortalAll.Unclock(); return true; } @@ -325,6 +325,8 @@ inline void GLPortal::ClearClipper() angle_t a1 = GLRenderer->FrustumAngle(); if (a1mCurrentPortal = NextPortal; if (clipsave) gl.Enable (GL_CLIP_PLANE0+renderdepth-1); if (usestencil) { @@ -435,7 +438,8 @@ void GLPortal::StartFrame() portals.Push(p); if (renderdepth==0) { - inskybox=inupperstack=inlowerstack=false; + inskybox=false; + instack[sector_t::floor]=instack[sector_t::ceiling]=0; } renderdepth++; } @@ -466,6 +470,15 @@ void GLPortal::EndFrame() { GLPortal * p; + if (gl.flags & RFL_NOSTENCIL) + { + while (portals.Pop(p) && p) + { + delete p; + } + return; + } + if (gl_portalinfo) { Printf("%s%d portals, depth = %d\n%s{\n", indent.GetChars(), portals.Size(), renderdepth, indent.GetChars()); @@ -483,8 +496,10 @@ void GLPortal::EndFrame() { Printf("%sProcessing %s, depth = %d, query = %d\n", indent.GetChars(), p->GetName(), renderdepth, usequery); } - - p->RenderPortal(true, usequery); + if (p->lines.Size() > 0) + { + p->RenderPortal(true, usequery); + } delete p; } renderdepth--; @@ -517,7 +532,7 @@ bool GLPortal::RenderFirstSkyPortal(int recursion) for(unsigned i=portals.Size()-1;i>=0 && portals[i]!=NULL;i--) { p=portals[i]; - if (p->IsSky()) + if (p->lines.Size() > 0 && p->IsSky()) { // Cannot clear the depth buffer inside a portal recursion if (recursion && p->NeedDepthBuffer()) continue; @@ -532,9 +547,8 @@ bool GLPortal::RenderFirstSkyPortal(int recursion) if (best) { - best->RenderPortal(false, false); portals.Delete(bestindex); - + best->RenderPortal(false, false); delete best; return true; } @@ -547,6 +561,7 @@ bool GLPortal::RenderFirstSkyPortal(int recursion) // FindPortal // //----------------------------------------------------------------------------- + GLPortal * GLPortal::FindPortal(const void * src) { int i=portals.Size()-1; @@ -556,6 +571,23 @@ GLPortal * GLPortal::FindPortal(const void * src) } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- + +void GLPortal::SaveMapSection() +{ + savedmapsection.Resize(currentmapsection.Size()); + memcpy(&savedmapsection[0], ¤tmapsection[0], currentmapsection.Size()); + memset(¤tmapsection[0], 0, currentmapsection.Size()); +} + +void GLPortal::RestoreMapSection() +{ + memcpy(¤tmapsection[0], &savedmapsection[0], currentmapsection.Size()); +} //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -611,6 +643,12 @@ void GLSkyboxPortal::DrawContents() GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); GLRenderer->SetViewArea(); ClearClipper(); + + int mapsection = R_PointInSubsector(viewx, viewy)->mapsection; + + SaveMapSection(); + currentmapsection[mapsection>>3] |= 1 << (mapsection & 7); + GLRenderer->DrawScene(); origin->flags&=~MF_JUSTHIT; inskybox=false; @@ -619,6 +657,60 @@ void GLSkyboxPortal::DrawContents() PlaneMirrorMode=old_pm; extralight = saved_extralight; + + RestoreMapSection(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// +// +// Sector stack Portal +// +// +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// +// GLSectorStackPortal::SetupCoverage +// +//----------------------------------------------------------------------------- + +static BYTE SetCoverage(void *node) +{ + if (numnodes == 0) + { + return 0; + } + if (!((size_t)node & 1)) // Keep going until found a subsector + { + node_t *bsp = (node_t *)node; + BYTE coverage = SetCoverage(bsp->children[0]) | SetCoverage(bsp->children[1]); + gl_drawinfo->no_renderflags[bsp-nodes] = coverage; + return coverage; + } + else + { + subsector_t *sub = (subsector_t *)((BYTE *)node - 1); + return gl_drawinfo->ss_renderflags[sub-subsectors] & SSRF_SEEN; + } +} + +void GLSectorStackPortal::SetupCoverage() +{ + for(unsigned i=0; iplane; + for(int j=0;jportalcoverage[plane].sscount; j++) + { + subsector_t *dsub = &::subsectors[sub->portalcoverage[plane].subsectors[j]]; + currentmapsection[dsub->mapsection>>3] |= 1 << (dsub->mapsection&7); + gl_drawinfo->ss_renderflags[dsub-::subsectors] |= SSRF_SEEN; + } + } + SetCoverage(&nodes[numnodes-1]); } //----------------------------------------------------------------------------- @@ -628,11 +720,10 @@ void GLSkyboxPortal::DrawContents() //----------------------------------------------------------------------------- void GLSectorStackPortal::DrawContents() { - FPortal *portal = &::portals[origin->origin->special1]; - portal->UpdateClipAngles(); + FPortal *portal = origin; - viewx += origin->origin->x - origin->origin->Mate->x; - viewy += origin->origin->y - origin->origin->Mate->y; + viewx += origin->xDisplacement; + viewy += origin->yDisplacement; GLRenderer->mViewActor = NULL; GLRenderer->mCurrentPortal = this; @@ -640,153 +731,34 @@ void GLSectorStackPortal::DrawContents() validcount++; // avoid recursions! - if (origin->isupper) inupperstack=true; - else inlowerstack=true; + if (origin->plane != -1) instack[origin->plane]++; GLRenderer->SetupView(viewx, viewy, viewz, viewangle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); + SaveMapSection(); + SetupCoverage(); ClearClipper(); GLRenderer->DrawScene(); + RestoreMapSection(); + + if (origin->plane != -1) instack[origin->plane]--; } //----------------------------------------------------------------------------- -// -// GLSectorStackPortal::ClipSeg -// -//----------------------------------------------------------------------------- -int GLSectorStackPortal::ClipSeg(seg_t *seg) -{ - FPortal *portal = &::portals[origin->origin->special1]; - angle_t *angles = &portal->ClipAngles[0]; - unsigned numpoints = portal->ClipAngles.Size()-1; - angle_t clipangle = seg->v1->GetClipAngle(); - unsigned i, j; - int relation; - - // Check the front side of the portal. Anything in front of the shape must be discarded by the clipper. - for(i=0;i ANGLE_180 && angles[i+1] - angles[i] < ANGLE_180) - { - relation = DMulScale32(seg->v1->y - portal->Shape[i]->y - portal->yDisplacement, portal->Shape[i+1]->x - portal->Shape[i]->x, - portal->Shape[i]->x - seg->v1->x + portal->xDisplacement, portal->Shape[i+1]->y - portal->Shape[i]->y); - if (relation > 0) - { - return PClip_InFront; - } - else if (relation == 0) - { - // If this vertex is on the boundary we need to check the second one, too. The line may be partially inside the shape - // but outside the portal. We can use the same boundary line for this - relation = DMulScale32(seg->v2->y - portal->Shape[i]->y - portal->yDisplacement, portal->Shape[i+1]->x - portal->Shape[i]->x, - portal->Shape[i]->x - seg->v2->x + portal->xDisplacement, portal->Shape[i+1]->y - portal->Shape[i]->y); - if (relation >= 0) return PClip_InFront; - } - return PClip_Inside; - } - } - - // The first vertex did not yield any useful result. Check the second one. - clipangle = seg->v2->GetClipAngle(); - for(j=0;j ANGLE_180 && angles[j+1] - angles[j] < ANGLE_180) - { - relation = DMulScale32(seg->v2->y - portal->Shape[j]->y - portal->yDisplacement, portal->Shape[j+1]->x - portal->Shape[j]->x, - portal->Shape[j]->x - seg->v1->x + portal->xDisplacement, portal->Shape[j+1]->y - portal->Shape[j]->y); - if (relation > 0) - { - return PClip_InFront; - } - else if (relation == 0) - { - // If this vertex is on the boundary we need to check the second one, too. The line may be partially inside the shape - // but outside the portal. We can use the same boundary line for this - relation = DMulScale32(seg->v2->y - portal->Shape[j]->y - portal->yDisplacement, portal->Shape[j+1]->x - portal->Shape[j]->x, - portal->Shape[j]->x - seg->v2->x + portal->xDisplacement, portal->Shape[j+1]->y - portal->Shape[j]->y); - if (relation >= 0) return PClip_InFront; - } - return PClip_Inside; - } - } - return PClip_Inside; // The viewpoint is inside the portal - -#if 0 - // Check backside of portal - for(i=0;i ANGLE_180 && angles[i] - clipangle <= ANGLE_180) - { - relation1 = DMulScale32(seg->v1->y - portal->Shape[i]->y - portal->yDisplacement, portal->Shape[i+1]->x - portal->Shape[i]->x, - portal->Shape[i]->x - seg->v1->x + portal->xDisplacement, portal->Shape[i+1]->y - portal->Shape[i]->y); - if (relation1 < 0) return PClip_Inside; - // If this vertex is inside we need to check the second one, too. The line may be partially inside the shape - // but outside the portal. - break; - } - } - - clipangle = seg->v2->GetClipAngle(); - for(j=0;j ANGLE_180 && angles[j] - clipangle <= ANGLE_180) - { - relation2 = DMulScale32(seg->v2->y - portal->Shape[j]->y - portal->yDisplacement, portal->Shape[j+1]->x - portal->Shape[j]->x, - portal->Shape[j]->x - seg->v2->x + portal->xDisplacement, portal->Shape[j+1]->y - portal->Shape[j]->y); - if (relation2 < 0) return PClip_Inside; - break; - } - } - return PClip_Behind; -#endif -} - - //----------------------------------------------------------------------------- // -// GLSectorStackPortal::ClipPoint +// +// Plane Mirror Portal +// // //----------------------------------------------------------------------------- -int GLSectorStackPortal::ClipPoint(fixed_t x, fixed_t y) -{ - FPortal *portal = &::portals[origin->origin->special1]; - angle_t *angles = &portal->ClipAngles[0]; - unsigned numpoints = portal->ClipAngles.Size()-1; - angle_t clipangle = R_PointToPseudoAngle(viewx, viewy, x, y); - unsigned i; - - for(i=0;i ANGLE_180 && angles[i+1] - angles[i] < ANGLE_180) - { - int relation = DMulScale32(y - portal->Shape[i]->y - portal->yDisplacement, portal->Shape[i+1]->x - portal->Shape[i]->x, - portal->Shape[i]->x - x + portal->xDisplacement, portal->Shape[i+1]->y - portal->Shape[i]->y); - if (relation > 0) return PClip_InFront; - return PClip_Inside; - } - } - return PClip_Inside; - - /* - for(i=0;i= angles[i] && clipangle < angles[i+1]) - { - int relation = DMulScale32(y - portal->Shape[i]->y, portal->Shape[i+1]->x - portal->Shape[i]->x, - portal->Shape[i]->x - x, portal->Shape[i+1]->y - portal->Shape[i]->y); - if (relation > 0) return PClip_InFront; - return PClip_Inside; - } - } - */ - return PClip_Inside; -} - +//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // // GLPlaneMirrorPortal::DrawContents // //----------------------------------------------------------------------------- + void GLPlaneMirrorPortal::DrawContents() { if (renderdepth>r_mirror_recursions) @@ -820,6 +792,13 @@ void GLPlaneMirrorPortal::DrawContents() PlaneMirrorMode=old_pm; } +//----------------------------------------------------------------------------- +// +// GLPlaneMirrorPortal::DrawContents +// +//----------------------------------------------------------------------------- + + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- diff --git a/src/gl/scene/gl_portal.h b/src/gl/scene/gl_portal.h index 9767c5fc..5f152135 100644 --- a/src/gl/scene/gl_portal.h +++ b/src/gl/scene/gl_portal.h @@ -72,17 +72,8 @@ struct GLSkyInfo } }; -struct GLSectorStackInfo -{ - ASkyViewpoint *origin; - bool isupper; -}; - - - extern UniqueList UniqueSkies; extern UniqueList UniqueHorizons; -extern UniqueList UniqueStacks; extern UniqueList UniquePlaneMirrors; class GLPortal @@ -97,8 +88,8 @@ protected: public: static int PlaneMirrorMode; - static bool inupperstack; - static bool inlowerstack; + static int inupperstack; + static int instack[2]; static bool inskybox; private: @@ -111,6 +102,8 @@ private: AActor * savedviewactor; area_t savedviewarea; unsigned char clipsave; + GLPortal *NextPortal; + TArray savedmapsection; protected: TArray lines; @@ -129,6 +122,8 @@ protected: virtual bool NeedDepthBuffer() { return true; } void ClearScreen(); virtual const char *GetName() = 0; + void SaveMapSection(); + void RestoreMapSection(); public: @@ -241,21 +236,25 @@ public: struct GLSectorStackPortal : public GLPortal { + TArray subsectors; protected: virtual void DrawContents(); virtual void * GetSource() const { return origin; } virtual bool IsSky() { return true; } // although this isn't a real sky it can be handled as one. virtual const char *GetName(); - GLSectorStackInfo * origin; + FPortal *origin; public: - GLSectorStackPortal(GLSectorStackInfo * pt) + GLSectorStackPortal(FPortal *pt) { origin=pt; } - int ClipSeg(seg_t *seg); - int ClipPoint(fixed_t x, fixed_t y); + void SetupCoverage(); + void AddSubsector(subsector_t *sub) + { + subsectors.Push(sub); + } }; diff --git a/src/gl/scene/gl_renderhacks.cpp b/src/gl/scene/gl_renderhacks.cpp index 0b80d3da..65f96467 100644 --- a/src/gl/scene/gl_renderhacks.cpp +++ b/src/gl/scene/gl_renderhacks.cpp @@ -49,6 +49,7 @@ #include "gl/dynlights/gl_glow.h" #include "gl/dynlights/gl_lightbuffer.h" #include "gl/scene/gl_drawinfo.h" +#include "gl/scene/gl_portal.h" #include "gl/utility/gl_clock.h" #include "gl/utility/gl_templates.h" @@ -679,7 +680,7 @@ void FDrawInfo::DrawUnhandledMissingTextures() if (seg->PartnerSeg && (seg->PartnerSeg->Subsector()->flags & SSECF_DEGENERATE)) continue; if (seg->backsector->transdoor) continue; if (seg->backsector->GetTexture(sector_t::ceiling)==skyflatnum) continue; - if (seg->backsector->CeilingSkyBox && seg->backsector->CeilingSkyBox->bAlways) continue; + if (seg->backsector->portals[sector_t::ceiling] != NULL) continue; if (!glset.notexturefill) FloodUpperGap(seg); } @@ -699,7 +700,7 @@ void FDrawInfo::DrawUnhandledMissingTextures() if (seg->frontsector->GetPlaneTexZ(sector_t::floor) > viewz) continue; // out of sight if (seg->backsector->transdoor) continue; if (seg->backsector->GetTexture(sector_t::floor)==skyflatnum) continue; - if (seg->backsector->FloorSkyBox && seg->backsector->FloorSkyBox->bAlways) continue; + if (seg->backsector->portals[sector_t::floor] != NULL) continue; if (!glset.notexturefill) FloodLowerGap(seg); } @@ -1058,7 +1059,7 @@ void FDrawInfo::CollectSectorStacksCeiling(subsector_t * sub, sector_t * anchor) sub->validcount=validcount; // Has a sector stack or skybox itself! - if (sub->render_sector->CeilingSkyBox && sub->render_sector->CeilingSkyBox->bAlways) return; + if (sub->render_sector->portals[sector_t::ceiling] != NULL) return; // Don't bother processing unrendered subsectors if (sub->numlines>2 && !(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return; @@ -1106,7 +1107,7 @@ void FDrawInfo::CollectSectorStacksFloor(subsector_t * sub, sector_t * anchor) sub->validcount=validcount; // Has a sector stack or skybox itself! - if (sub->render_sector->FloorSkyBox && sub->render_sector->FloorSkyBox->bAlways) return; + if (sub->render_sector->portals[sector_t::floor] != NULL) return; // Don't bother processing unrendered subsectors if (sub->numlines>2 && !(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return; @@ -1155,7 +1156,8 @@ void FDrawInfo::ProcessSectorStacks() for (i=0;isubsectorcount;k++) + FPortal *portal = sec->portals[sector_t::ceiling]; + if (portal != NULL) for(int k=0;ksubsectorcount;k++) { subsector_t * sub = sec->subsectors[k]; if (ss_renderflags[sub-subsectors] & SSRF_PROCESSED) @@ -1173,12 +1175,20 @@ void FDrawInfo::ProcessSectorStacks() } for(unsigned int j=0;jrender_sector->CeilingSkyBox->PlaneAlpha!=0) + if (sub->portalcoverage[sector_t::ceiling].subsectors == NULL) + { + gl_BuildPortalCoverage(&sub->portalcoverage[sector_t::ceiling], sub, portal); + } + + portal->GetGLPortal()->AddSubsector(sub); + + if (sec->GetAlpha(sector_t::ceiling) != 0) { gl_subsectorrendernode * node = SSR_List.GetNew(); - node->sub = HandledSubsectors[j]; + node->sub = sub; AddOtherCeilingPlane(sub->render_sector->sectornum, node); } } @@ -1190,7 +1200,8 @@ void FDrawInfo::ProcessSectorStacks() for (i=0;isubsectorcount;k++) + FPortal *portal = sec->portals[sector_t::floor]; + if (portal != NULL) for(int k=0;ksubsectorcount;k++) { subsector_t * sub = sec->subsectors[k]; if (ss_renderflags[sub-subsectors] & SSRF_PROCESSED) @@ -1209,13 +1220,21 @@ void FDrawInfo::ProcessSectorStacks() for(unsigned int j=0;jrender_sector->sectornum); - ss_renderflags[DWORD(HandledSubsectors[j]-subsectors)] &= ~SSRF_RENDERFLOOR; + subsector_t *sub = HandledSubsectors[j]; + ss_renderflags[DWORD(sub-subsectors)] &= ~SSRF_RENDERFLOOR; - if (sub->render_sector->FloorSkyBox->PlaneAlpha!=0) + if (sub->portalcoverage[sector_t::floor].subsectors == NULL) + { + gl_BuildPortalCoverage(&sub->portalcoverage[sector_t::floor], sub, portal); + } + + GLSectorStackPortal *glportal = portal->GetGLPortal(); + glportal->AddSubsector(sub); + + if (sec->GetAlpha(sector_t::floor)!=0) { gl_subsectorrendernode * node = SSR_List.GetNew(); - node->sub = HandledSubsectors[j]; + node->sub = sub; AddOtherFloorPlane(sub->render_sector->sectornum, node); } } diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 9fdc9802..8fb9fc33 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -91,6 +91,7 @@ extern int viewpitch; DWORD gl_fixedcolormap; area_t in_area; +TArray currentmapsection; void R_SetupFrame (AActor * camera); @@ -312,6 +313,7 @@ void FGLRenderer::CreateScene() ProcessAll.Clock(); // clip the scene and fill the drawlists + for(unsigned i=0;iglportal = NULL; gl_spriteindex=0; Bsp.Clock(); gl_RenderBSPNode (nodes + numnodes - 1); @@ -847,6 +849,9 @@ void FGLRenderer::ProcessScene(bool toscreen) iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; GLPortal::BeginScene(); + int mapsection = R_PointInSubsector(viewx, viewy)->mapsection; + memset(¤tmapsection[0], 0, currentmapsection.Size()); + currentmapsection[mapsection>>3] |= 1 << (mapsection & 7); DrawScene(toscreen); FDrawInfo::EndDrawInfo(); @@ -951,9 +956,6 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo //----------------------------------------------------------------------------- static FRandom pr_glhom; EXTERN_CVAR(Int, r_clearbuffer) -CVAR(Bool, gl_testdl, false, 0) -static int dl = -1; -static int indl = 0; void FGLRenderer::RenderView (player_t* player) { @@ -1035,31 +1037,9 @@ void FGLRenderer::RenderView (player_t* player) TThinkerIterator it(STAT_DLIGHT); GLRenderer->mLightCount = ((it.Next()) != NULL); - if (gl_testdl) - { - if (dl == -1) - { - dl = glGenLists(1); - glNewList(dl, GL_COMPILE_AND_EXECUTE); - indl = true; - } - else - { - glCallList(dl); - All.Unclock(); - return; - } - } - sector_t * viewsector = RenderViewpoint(player->camera, NULL, FieldOfView * 360.0f / FINEANGLES, ratio, fovratio, true, true); EndDrawScene(viewsector); - if (gl_testdl && indl) - { - indl = false; - glEndList(); - } - All.Unclock(); } diff --git a/src/gl/scene/gl_sky.cpp b/src/gl/scene/gl_sky.cpp index 28e4a8b0..f69695b1 100644 --- a/src/gl/scene/gl_sky.cpp +++ b/src/gl/scene/gl_sky.cpp @@ -62,118 +62,104 @@ enum }; -//========================================================================== -// -// Calculate mirrorplane -// -//========================================================================== -void GLWall::MirrorPlane(secplane_t * plane, bool ceiling) -{ - if (!(gl.flags&RFL_NOSTENCIL)) - { - if (ceiling && FIXED2FLOAT(viewz) >= plane->ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy))) return; - if (!ceiling && FIXED2FLOAT(viewz) <= plane->ZatPoint(FIXED2FLOAT(viewx), FIXED2FLOAT(viewy))) return; - type=RENDERWALL_PLANEMIRROR; - planemirror=plane; - PutWall(0); - } -} - //========================================================================== // // Calculate sky texture // //========================================================================== -void GLWall::SkyTexture(int sky1,ASkyViewpoint * skyboxx, bool ceiling) +void GLWall::SkyPlane(sector_t *sector, int plane, bool allowreflect) { - GLSkyInfo skyinfo; - - // JUSTHIT is used as an indicator that a skybox is in use. - // This is to avoid recursion - if (!gl_noskyboxes && !(gl.flags&RFL_NOSTENCIL) && skyboxx && GLRenderer->mViewActor!=skyboxx && !(skyboxx->flags&MF_JUSTHIT)) + FPortal *portal = sector->portals[plane]; + if (portal != NULL) { - if (!skyboxx->Mate) + if (GLPortal::instack[1-plane]) return; + type=RENDERWALL_SECTORSTACK; + this->portal = portal; + } + else if (sector->GetTexture(plane)==skyflatnum) + { + GLSkyInfo skyinfo; + ASkyViewpoint * skyboxx = plane == sector_t::floor? sector->FloorSkyBox : sector->CeilingSkyBox; + + // JUSTHIT is used as an indicator that a skybox is in use. + // This is to avoid recursion + + if (!gl_noskyboxes && skyboxx && GLRenderer->mViewActor!=skyboxx && !(skyboxx->flags&MF_JUSTHIT)) { type=RENDERWALL_SKYBOX; skybox=skyboxx; } - else - { - static GLSectorStackInfo stackinfo; - if (ceiling && GLPortal::inlowerstack) return; - if (!ceiling && GLPortal::inupperstack) return; - type=RENDERWALL_SECTORSTACK; - stackinfo.origin = skyboxx; - stackinfo.isupper= ceiling; - stack=&stackinfo; - } - } - else - { - if (skyboxx && skyboxx->Mate) return; - - memset(&skyinfo, 0, sizeof(skyinfo)); - if ((sky1 & PL_SKYFLAT) && (sky1 & (PL_SKYFLAT-1)) && !(gl.flags&RFL_NOSTENCIL)) - { - const line_t *l = &lines[(sky1&(PL_SKYFLAT-1))-1]; - const side_t *s = l->sidedef[0]; - int pos; - - if (level.flags & LEVEL_SWAPSKIES && s->GetTexture(side_t::bottom).isValid()) - { - pos = side_t::bottom; - } - else - { - pos = side_t::top; - } - - FTextureID texno = s->GetTexture(pos); - skyinfo.texture[0] = FMaterial::ValidateTexture(texno, true); - if (!skyinfo.texture[0] || skyinfo.texture[0]->tex->UseType == FTexture::TEX_Null) goto normalsky; - skyinfo.skytexno1 = texno; - skyinfo.x_offset[0] = ANGLE_TO_FLOAT(s->GetTextureXOffset(pos)); - skyinfo.y_offset = FIXED2FLOAT(s->GetTextureYOffset(pos)); - skyinfo.mirrored = !l->args[2]; - } else { - normalsky: - if (level.flags&LEVEL_DOUBLESKY) + int sky1 = sector->sky; + memset(&skyinfo, 0, sizeof(skyinfo)); + if ((sky1 & PL_SKYFLAT) && (sky1 & (PL_SKYFLAT-1))) { - skyinfo.texture[1]=FMaterial::ValidateTexture(sky1texture, true); - if (!skyinfo.texture[1]) return; - skyinfo.x_offset[1] = GLRenderer->mSky1Pos; - skyinfo.doublesky = true; - } - - if ((level.flags&LEVEL_SWAPSKIES || (sky1==PL_SKYFLAT && !(gl.flags&RFL_NOSTENCIL)) || (level.flags&LEVEL_DOUBLESKY)) && - sky2texture!=sky1texture) // If both skies are equal use the scroll offset of the first! - { - skyinfo.texture[0]=FMaterial::ValidateTexture(sky2texture, true); - skyinfo.skytexno1=sky2texture; - skyinfo.sky2 = true; - skyinfo.x_offset[0] = GLRenderer->mSky2Pos; + const line_t *l = &lines[(sky1&(PL_SKYFLAT-1))-1]; + const side_t *s = l->sidedef[0]; + int pos; + + if (level.flags & LEVEL_SWAPSKIES && s->GetTexture(side_t::bottom).isValid()) + { + pos = side_t::bottom; + } + else + { + pos = side_t::top; + } + + FTextureID texno = s->GetTexture(pos); + skyinfo.texture[0] = FMaterial::ValidateTexture(texno, true); + if (!skyinfo.texture[0] || skyinfo.texture[0]->tex->UseType == FTexture::TEX_Null) goto normalsky; + skyinfo.skytexno1 = texno; + skyinfo.x_offset[0] = ANGLE_TO_FLOAT(s->GetTextureXOffset(pos)); + skyinfo.y_offset = FIXED2FLOAT(s->GetTextureYOffset(pos)); + skyinfo.mirrored = !l->args[2]; } else { - skyinfo.texture[0]=FMaterial::ValidateTexture(sky1texture, true); - skyinfo.skytexno1=sky1texture; - skyinfo.x_offset[0] = GLRenderer->mSky1Pos; + normalsky: + if (level.flags&LEVEL_DOUBLESKY) + { + skyinfo.texture[1]=FMaterial::ValidateTexture(sky1texture, true); + skyinfo.x_offset[1] = GLRenderer->mSky1Pos; + skyinfo.doublesky = true; + } + + if ((level.flags&LEVEL_SWAPSKIES || (sky1==PL_SKYFLAT) || (level.flags&LEVEL_DOUBLESKY)) && + sky2texture!=sky1texture) // If both skies are equal use the scroll offset of the first! + { + skyinfo.texture[0]=FMaterial::ValidateTexture(sky2texture, true); + skyinfo.skytexno1=sky2texture; + skyinfo.sky2 = true; + skyinfo.x_offset[0] = GLRenderer->mSky2Pos; + } + else + { + skyinfo.texture[0]=FMaterial::ValidateTexture(sky1texture, true); + skyinfo.skytexno1=sky1texture; + skyinfo.x_offset[0] = GLRenderer->mSky1Pos; + } } - if (!skyinfo.texture[0]) return; + if (skyfog>0) + { + skyinfo.fadecolor=Colormap.FadeColor; + skyinfo.fadecolor.a=0; + } + else skyinfo.fadecolor=0; + type=RENDERWALL_SKY; + sky=UniqueSkies.Get(&skyinfo); } - if (skyfog>0) - { - skyinfo.fadecolor=Colormap.FadeColor; - skyinfo.fadecolor.a=0; - } - else skyinfo.fadecolor=0; - - type=RENDERWALL_SKY; - sky = &skyinfo; } + else if (allowreflect && sector->GetReflect(plane) > 0) + { + if ((plane == sector_t::ceiling && viewz > sector->ceilingplane.d) || + (plane == sector_t::floor && viewz < -sector->floorplane.d)) return; + type=RENDERWALL_PLANEMIRROR; + planemirror = plane == sector_t::ceiling? §or->ceilingplane : §or->floorplane; + } + else return; PutWall(0); } @@ -183,34 +169,26 @@ void GLWall::SkyTexture(int sky1,ASkyViewpoint * skyboxx, bool ceiling) // Skies on one sided walls // //========================================================================== + void GLWall::SkyNormal(sector_t * fs,vertex_t * v1,vertex_t * v2) { - bool ceilingsky = fs->GetTexture(sector_t::ceiling)==skyflatnum || (fs->CeilingSkyBox && fs->CeilingSkyBox->bAlways); - if (ceilingsky || fs->ceiling_reflect) - { - ztop[0]=ztop[1]=32768.0f; - zbottom[0]=zceil[0]; - zbottom[1]=zceil[1]; - if (ceilingsky) SkyTexture(fs->sky,fs->CeilingSkyBox, true); - else MirrorPlane(&fs->ceilingplane, true); - } - bool floorsky = fs->GetTexture(sector_t::floor)==skyflatnum || (fs->FloorSkyBox && fs->FloorSkyBox->bAlways); - if (floorsky || fs->floor_reflect) - { - ztop[0]=zfloor[0]; - ztop[1]=zfloor[1]; - zbottom[0]=zbottom[1]=-32768.0f; - if (floorsky) SkyTexture(fs->sky,fs->FloorSkyBox, false); - else MirrorPlane(&fs->floorplane, false); - } -} + ztop[0]=ztop[1]=32768.0f; + zbottom[0]=zceil[0]; + zbottom[1]=zceil[1]; + SkyPlane(fs, sector_t::ceiling, true); + ztop[0]=zfloor[0]; + ztop[1]=zfloor[1]; + zbottom[0]=zbottom[1]=-32768.0f; + SkyPlane(fs, sector_t::floor, true); +} //========================================================================== // // Upper Skies on two sided walls // //========================================================================== + void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2) { if (fs->GetTexture(sector_t::ceiling)==skyflatnum) @@ -241,7 +219,7 @@ void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex ztop[0]=ztop[1]=32768.0f; zbottom[0]=zbottom[1]= FIXED2FLOAT(bs->ceilingplane.ZatPoint(v2) + seg->sidedef->GetTextureYOffset(side_t::mid)); - SkyTexture(fs->sky,fs->CeilingSkyBox, true); + SkyPlane(fs, sector_t::ceiling, false); return; } } @@ -263,25 +241,36 @@ void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex zbottom[1]=FIXED2FLOAT(bs->ceilingplane.ZatPoint(v2)); flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment! } - - SkyTexture(fs->sky,fs->CeilingSkyBox, true); } else { - bool ceilingsky = (fs->CeilingSkyBox && fs->CeilingSkyBox->bAlways && fs->CeilingSkyBox!=bs->CeilingSkyBox); - if (ceilingsky || fs->ceiling_reflect) + FPortal *pfront = fs->portals[sector_t::ceiling]; + FPortal *pback = bs->portals[sector_t::ceiling]; + float frontreflect = fs->GetReflect(sector_t::ceiling); + if (frontreflect > 0) { - // stacked sectors - fixed_t fsc1=fs->ceilingplane.ZatPoint(v1); - fixed_t fsc2=fs->ceilingplane.ZatPoint(v2); - - ztop[0]=ztop[1]=32768.0f; - zbottom[0]=FIXED2FLOAT(fsc1); - zbottom[1]=FIXED2FLOAT(fsc2); - if (ceilingsky) SkyTexture(fs->sky,fs->CeilingSkyBox, true); - else MirrorPlane(&fs->ceilingplane, true); + float backreflect = bs->GetReflect(sector_t::ceiling); + if (backreflect > 0 && bs->ceilingplane.d == fs->ceilingplane.d) + { + // Don't add intra-portal line to the portal. + return; + } } + else if (pfront == NULL || pfront == pback) + { + return; + } + + // stacked sectors + fixed_t fsc1=fs->ceilingplane.ZatPoint(v1); + fixed_t fsc2=fs->ceilingplane.ZatPoint(v2); + + ztop[0]=ztop[1]=32768.0f; + zbottom[0]=FIXED2FLOAT(fsc1); + zbottom[1]=FIXED2FLOAT(fsc2); } + + SkyPlane(fs, sector_t::ceiling, true); } @@ -290,6 +279,7 @@ void GLWall::SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex // Lower Skies on two sided walls // //========================================================================== + void GLWall::SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2) { if (fs->GetTexture(sector_t::floor)==skyflatnum) @@ -327,24 +317,35 @@ void GLWall::SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,ver ztop[1]=FIXED2FLOAT(bs->floorplane.ZatPoint(v2)); flags|=GLWF_SKYHACK; // mid textures on such lines need special treatment! } - - SkyTexture(fs->sky,fs->FloorSkyBox, false); } else { - bool floorsky = (fs->FloorSkyBox && fs->FloorSkyBox->bAlways && fs->FloorSkyBox!=bs->FloorSkyBox); - if (floorsky || fs->floor_reflect) + FPortal *pfront = fs->portals[sector_t::floor]; + FPortal *pback = bs->portals[sector_t::floor]; + float frontreflect = fs->GetReflect(sector_t::floor); + if (frontreflect > 0) { - // stacked sectors - fixed_t fsc1=fs->floorplane.ZatPoint(v1); - fixed_t fsc2=fs->floorplane.ZatPoint(v2); - - zbottom[0]=zbottom[1]=-32768.0f; - ztop[0]=FIXED2FLOAT(fsc1); - ztop[1]=FIXED2FLOAT(fsc2); - - if (floorsky) SkyTexture(fs->sky,fs->FloorSkyBox, false); - else MirrorPlane(&fs->floorplane, false); + float backreflect = bs->GetReflect(sector_t::floor); + if (backreflect > 0 && bs->floorplane.d == fs->floorplane.d) + { + // Don't add intra-portal line to the portal. + return; + } } + else if (pfront == NULL || pfront == pback) + { + return; + } + + // stacked sectors + fixed_t fsc1=fs->floorplane.ZatPoint(v1); + fixed_t fsc2=fs->floorplane.ZatPoint(v2); + + zbottom[0]=zbottom[1]=-32768.0f; + ztop[0]=FIXED2FLOAT(fsc1); + ztop[1]=FIXED2FLOAT(fsc2); } + + SkyPlane(fs, sector_t::floor, true); } + diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index af4973c9..b09fe2f6 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -67,6 +67,10 @@ CVAR(Float, gl_sclipfactor, 1.8, CVAR_ARCHIVE) CVAR(Int, gl_particles_style, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // 0 = square, 1 = round, 2 = smooth CVAR(Int, gl_billboard_mode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Int, gl_enhanced_nv_stealth, 3, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Int, gl_fuzztype, 0, CVAR_ARCHIVE) +{ + if (self < 0 || self > 7) self = 0; +} extern bool r_showviewer; EXTERN_CVAR (Float, transsouls) @@ -136,7 +140,7 @@ void GLSprite::Draw(int pass) gl_RenderState.AlphaFunc(GL_GEQUAL,trans*gl_mask_sprite_threshold); } - if (RenderStyle.BlendOp == STYLEOP_Fuzz) + if (RenderStyle.BlendOp == STYLEOP_Shadow) { float fuzzalpha=0.44f; float minalpha=0.1f; @@ -166,7 +170,7 @@ void GLSprite::Draw(int pass) additivefog = true; } } - if (RenderStyle.BlendOp!=STYLEOP_Fuzz) + if (RenderStyle.BlendOp!=STYLEOP_Shadow) { if (actor) { @@ -203,7 +207,7 @@ void GLSprite::Draw(int pass) gl_SetFog(foglevel, rel, &Colormap, additivefog); - if (gltexture) gltexture->BindPatch(Colormap.colormap,translation); + if (gltexture) gltexture->BindPatch(Colormap.colormap, translation, OverrideShader); else if (!modelframe) gl_RenderState.EnableTexture(false); if (!modelframe) @@ -446,6 +450,9 @@ void GLSprite::Process(AActor* thing,sector_t * sector) return; } + // If this thing is in a map section that's not in view it can't possible be visible + if (!(currentmapsection[thing->subsector->mapsection>>3] & (1 << (thing->subsector->mapsection & 7)))) return; + // [RH] Interpolate the sprite's position to make it look smooth fixed_t thingx = thing->PrevX + FixedMul (r_TicFrac, thing->x - thing->PrevX); fixed_t thingy = thing->PrevY + FixedMul (r_TicFrac, thing->y - thing->PrevY); @@ -726,10 +733,30 @@ void GLSprite::Process(AActor* thing,sector_t * sector) ThingColor=0xffffff; RenderStyle = thing->RenderStyle; - RenderStyle.CheckFuzz(); + OverrideShader = 0; trans = FIXED2FLOAT(thing->alpha); hw_styleflags = STYLEHW_Normal; + if (RenderStyle.BlendOp >= STYLEOP_Fuzz && RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub) + { + RenderStyle.CheckFuzz(); + if (RenderStyle.BlendOp == STYLEOP_Fuzz) + { + if (gl.shadermodel >= 4 && gl_fuzztype != 0) + { + // Todo: implement shader selection here + RenderStyle = LegacyRenderStyles[STYLE_Translucent]; + OverrideShader = gl_fuzztype + 4; + trans = 0.99f; // trans may not be 1 here + hw_styleflags |= STYLEHW_NoAlphaTest; + } + else + { + RenderStyle.BlendOp = STYLEOP_Shadow; + } + } + } + if (RenderStyle.Flags & STYLEF_TransSoulsAlpha) { trans = transsouls; @@ -739,7 +766,7 @@ void GLSprite::Process(AActor* thing,sector_t * sector) trans = 1.f; } - if (trans >= 1.f-FLT_EPSILON && RenderStyle.BlendOp != STYLEOP_Fuzz && ( + if (trans >= 1.f-FLT_EPSILON && RenderStyle.BlendOp != STYLEOP_Shadow && ( (RenderStyle.SrcAlpha == STYLEALPHA_One && RenderStyle.DestAlpha == STYLEALPHA_Zero) || (RenderStyle.SrcAlpha == STYLEALPHA_Src && RenderStyle.DestAlpha == STYLEALPHA_InvSrc) )) @@ -774,7 +801,7 @@ void GLSprite::Process(AActor* thing,sector_t * sector) if (enhancedvision && gl_enhanced_nightvision) { - if (RenderStyle.BlendOp == STYLEOP_Fuzz) + if (RenderStyle.BlendOp == STYLEOP_Shadow) { // enhanced vision makes them more visible! trans=0.5f; @@ -865,6 +892,7 @@ void GLSprite::ProcessParticle (particle_t *particle, sector_t *sector)//, int s trans=particle->trans/255.0f; RenderStyle = STYLE_Translucent; + OverrideShader = 0; ThingColor = GPalette.BaseColors[particle->color]; ThingColor.a=0; diff --git a/src/gl/scene/gl_spritelight.cpp b/src/gl/scene/gl_spritelight.cpp index f3086120..897c8361 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/gl/scene/gl_spritelight.cpp @@ -263,7 +263,7 @@ int gl_SetSpriteLighting(FRenderStyle style, AActor *thing, int lightlevel, int cm->LightColor.r = cm->LightColor.g = cm->LightColor.b = gray; } - if (style.BlendOp == STYLEOP_Fuzz) + if (style.BlendOp == STYLEOP_Shadow) { gl.Color4f(0.2f * ThingColor.r / 255.f, 0.2f * ThingColor.g / 255.f, 0.2f * ThingColor.b / 255.f, (alpha = 0.33f)); diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 139d5c21..0aab09f4 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -18,8 +18,8 @@ class ADynamicLight; class FMaterial; struct GLDrawList; struct GLSkyInfo; -struct GLSectorStackInfo; struct FTexCoordInfo; +struct FPortal; enum WallTypes @@ -135,7 +135,7 @@ public: AActor * skybox; // for skyboxes GLSkyInfo * sky; // for normal sky GLHorizonInfo * horizon; // for horizon information - GLSectorStackInfo * stack; // for sector stacks + FPortal * portal; // stacked sector portals secplane_t * planemirror; // for plane mirrors }; @@ -163,12 +163,11 @@ private: void FloodPlane(int pass); - void MirrorPlane(secplane_t * plane, bool ceiling); - void SkyTexture(int sky1,ASkyViewpoint * skyboxx, bool ceiling); - + void SkyPlane(sector_t *sector, int plane, bool allowmirror); void SkyNormal(sector_t * fs,vertex_t * v1,vertex_t * v2); void SkyTop(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2); void SkyBottom(seg_t * seg,sector_t * fs,sector_t * bs,vertex_t * v1,vertex_t * v2); + void Put3DWall(lightlist_t * lightlist, bool translucent); void SplitWall(sector_t * frontsector, bool translucent); void LightPass(); @@ -185,6 +184,7 @@ private: int v_offset); void DoMidTexture(seg_t * seg, bool drawfogboundary, + sector_t * front, sector_t * back, sector_t * realfront, sector_t * realback, fixed_t fch1, fixed_t fch2, fixed_t ffh1, fixed_t ffh2, fixed_t bch1, fixed_t bch2, fixed_t bfh1, fixed_t bfh2); @@ -305,6 +305,7 @@ public: FColormap Colormap; FSpriteModelFrame * modelframe; FRenderStyle RenderStyle; + int OverrideShader; int translation; int index; diff --git a/src/gl/scene/gl_walls.cpp b/src/gl/scene/gl_walls.cpp index 1ece523c..c242826c 100644 --- a/src/gl/scene/gl_walls.cpp +++ b/src/gl/scene/gl_walls.cpp @@ -214,9 +214,7 @@ void GLWall::PutWall(bool translucent) case RENDERWALL_SECTORSTACK: //@sync-portal - stack=UniqueStacks.Get(stack); // map all stacks with the same displacement together - portal=GLPortal::FindPortal(stack); - if (!portal) portal=new GLSectorStackPortal(stack); + portal = this->portal->GetGLPortal(); portal->AddLine(this); break; @@ -246,7 +244,6 @@ void GLWall::PutWall(bool translucent) case RENDERWALL_SKY: //@sync-portal - sky=UniqueSkies.Get(sky); portal=GLPortal::FindPortal(sky); if (!portal) portal=new GLSkyPortal(sky); portal->AddLine(this); @@ -505,7 +502,7 @@ bool GLWall::DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2) if (fs->GetTexture(sector_t::ceiling) == skyflatnum) { - SkyTexture(fs->sky, fs->CeilingSkyBox, true); + SkyPlane(fs, sector_t::ceiling, false); } else { @@ -534,7 +531,7 @@ bool GLWall::DoHorizon(seg_t * seg,sector_t * fs, vertex_t * v1,vertex_t * v2) zbottom[1] = zbottom[0] = FIXED2FLOAT(fs->GetPlaneTexZ(sector_t::floor)); if (fs->GetTexture(sector_t::floor) == skyflatnum) { - SkyTexture(fs->sky, fs->FloorSkyBox, false); + SkyPlane(fs, sector_t::floor, false); } else { @@ -755,8 +752,7 @@ void GLWall::DoTexture(int _type,seg_t * seg, int peg, gltexture->GetTexCoordInfo(&tci, seg->sidedef->GetTextureXScale(texpos), seg->sidedef->GetTextureYScale(texpos)); - type = (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S && - !(gl.flags & RFL_NOSTENCIL) && gl_mirrors) ? RENDERWALL_MIRROR : _type; + type = (seg->linedef->special == Line_Mirror && _type == RENDERWALL_M1S && gl_mirrors) ? RENDERWALL_MIRROR : _type; float floatceilingref = FIXED2FLOAT(ceilingrefheight) + FIXED2FLOAT(tci.RowOffset(seg->sidedef->GetTextureYOffset(texpos))) + @@ -785,6 +781,7 @@ void GLWall::DoTexture(int _type,seg_t * seg, int peg, //========================================================================== void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary, + sector_t * front, sector_t * back, sector_t * realfront, sector_t * realback, fixed_t fch1, fixed_t fch2, fixed_t ffh1, fixed_t ffh2, fixed_t bch1, fixed_t bch2, fixed_t bfh1, fixed_t bfh2) @@ -837,9 +834,18 @@ void GLWall::DoMidTexture(seg_t * seg, bool drawfogboundary, FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::top)); if (!tex || tex->UseType==FTexture::TEX_Null) { - // texture is missing - use the higher plane - topleft = MAX(bch1,fch1); - topright = MAX(bch2,fch2); + if (front->GetTexture(sector_t::ceiling) == skyflatnum && + back->GetTexture(sector_t::ceiling) == skyflatnum) + { + // intra-sky lines do not clip the texture at all if there's no upper texture + topleft = topright = texturetop; + } + else + { + // texture is missing - use the higher plane + topleft = MAX(bch1,fch1); + topright = MAX(bch2,fch2); + } } else if ((bch1>fch1 || bch2>fch2) && (seg->frontsector->GetTexture(sector_t::ceiling)!=skyflatnum || seg->backsector->GetTexture(sector_t::ceiling)==skyflatnum)) @@ -1436,7 +1442,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector) #ifdef _MSC_VER #ifdef _DEBUG - if (seg->linedef-lines==8) + if (seg->linedef-lines==1095) __asm nop #endif #endif @@ -1545,7 +1551,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector) } - if (seg->linedef->special==Line_Horizon && !(gl.flags&RFL_NOSTENCIL)) + if (seg->linedef->special==Line_Horizon) { SkyNormal(frontsector,v1,v2); DoHorizon(seg,frontsector, v1,v2); @@ -1648,7 +1654,8 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector) gltexture=FMaterial::ValidateTexture(seg->sidedef->GetTexture(side_t::mid), true); if (gltexture || drawfogboundary) { - DoMidTexture(seg, drawfogboundary, realfront, realback, fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2); + DoMidTexture(seg, drawfogboundary, frontsector, backsector, realfront, realback, + fch1, fch2, ffh1, ffh2, bch1, bch2, bfh1, bfh2); } if (backsector->e->XFloor.ffloors.Size() || frontsector->e->XFloor.ffloors.Size()) diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index 91b2957c..15f51158 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -57,6 +57,7 @@ EXTERN_CVAR (Bool, r_drawplayersprites) EXTERN_CVAR(Float, transsouls) EXTERN_CVAR (Bool, st_scale) +EXTERN_CVAR(Int, gl_fuzztype) //========================================================================== @@ -65,7 +66,7 @@ EXTERN_CVAR (Bool, st_scale) // //========================================================================== -void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy, int cm_index, bool hudModelStep) +void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed_t sy, int cm_index, bool hudModelStep, int OverrideShader) { float fU1,fV1; float fU2,fV2; @@ -91,7 +92,7 @@ void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed FMaterial * tex = FMaterial::ValidateTexture(lump, false); if (!tex) return; - tex->BindPatch(cm_index, 0); + tex->BindPatch(cm_index, 0, OverrideShader); int vw = viewwidth; int vh = viewheight; @@ -144,7 +145,10 @@ void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed fV2=tex->GetVB(); } - if (tex->tex->gl_info.mIsTransparent) gl_RenderState.EnableAlphaTest(false); + if (tex->GetTransparent() || OverrideShader != 0) + { + gl_RenderState.EnableAlphaTest(false); + } gl_RenderState.Apply(); gl.Begin(GL_TRIANGLE_STRIP); gl.TexCoord2f(fU1, fV1); gl.Vertex2f(x1,y1); @@ -152,7 +156,10 @@ void FGLRenderer::DrawPSprite (player_t * player,pspdef_t *psp,fixed_t sx, fixed gl.TexCoord2f(fU2, fV1); gl.Vertex2f(x2,y1); gl.TexCoord2f(fU2, fV2); gl.Vertex2f(x2,y2); gl.End(); - if (tex->tex->gl_info.mIsTransparent) gl_RenderState.EnableAlphaTest(true); + if (tex->GetTransparent() || OverrideShader != 0) + { + gl_RenderState.EnableAlphaTest(true); + } } //========================================================================== @@ -264,10 +271,31 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) } // Set the render parameters - vis.RenderStyle.CheckFuzz(); + + int OverrideShader = 0; + float trans = 0.f; + if (vis.RenderStyle.BlendOp >= STYLEOP_Fuzz && vis.RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub) + { + vis.RenderStyle.CheckFuzz(); + if (vis.RenderStyle.BlendOp == STYLEOP_Fuzz) + { + if (gl.shadermodel >= 4 && gl_fuzztype != 0) + { + // Todo: implement shader selection here + vis.RenderStyle = LegacyRenderStyles[STYLE_Translucent]; + OverrideShader = gl_fuzztype + 4; + trans = 0.99f; // trans may not be 1 here + } + else + { + vis.RenderStyle.BlendOp = STYLEOP_Shadow; + } + } + statebright[0] = statebright[1] = false; + } + gl_SetRenderStyle(vis.RenderStyle, false, false); - float trans; if (vis.RenderStyle.Flags & STYLEF_TransSoulsAlpha) { trans = transsouls; @@ -276,7 +304,7 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) { trans = 1.f; } - else + else if (trans == 0.f) { trans = FIXED2FLOAT(vis.alpha); } @@ -313,7 +341,7 @@ void FGLRenderer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) // set the lighting parameters (only calls glColor and glAlphaFunc) gl_SetSpriteLighting(vis.RenderStyle, playermo, statebright[i]? 255 : lightlevel, 0, &cmc, 0xffffff, trans, statebright[i], true); - DrawPSprite (player,psp,psp->sx+ofsx, psp->sy+ofsy, cm.colormap, hudModelStep); + DrawPSprite (player,psp,psp->sx+ofsx, psp->sy+ofsy, cm.colormap, hudModelStep, OverrideShader); } } gl_RenderState.EnableBrightmap(false); @@ -344,5 +372,5 @@ void FGLRenderer::DrawTargeterSprites() // The Targeter's sprites are always drawn normally. for (i=ps_targetcenter, psp = &player->psprites[ps_targetcenter]; istate) DrawPSprite (player,psp,psp->sx, psp->sy, CM_DEFAULT, false); + if (psp->state) DrawPSprite (player,psp,psp->sx, psp->sy, CM_DEFAULT, false, 0); } \ No newline at end of file diff --git a/src/gl/shaders/gl_shader.cpp b/src/gl/shaders/gl_shader.cpp index 2711ba96..c3fd8955 100644 --- a/src/gl/shaders/gl_shader.cpp +++ b/src/gl/shaders/gl_shader.cpp @@ -389,6 +389,13 @@ static const FDefaultShader defaultshaders[]= {"Warp 2", "shaders/glsl/func_warp2.fp"}, {"Brightmap","shaders/glsl/func_brightmap.fp"}, {"No Texture", "shaders/glsl/func_notexture.fp"}, + {"Basic Fuzz", "shaders/glsl/fuzz_standard.fp"}, + {"Smooth Fuzz", "shaders/glsl/fuzz_smooth.fp"}, + {"Swirly Fuzz", "shaders/glsl/fuzz_swirly.fp"}, + {"Translucent Fuzz", "shaders/glsl/fuzz_smoothtranslucent.fp"}, + {"Jagged Fuzz", "shaders/glsl/fuzz_jagged.fp"}, + {"Noise Fuzz", "shaders/glsl/fuzz_noise.fp"}, + {"Smooth Noise Fuzz", "shaders/glsl/fuzz_smoothnoise.fp"}, {NULL,NULL} }; @@ -564,6 +571,17 @@ FShader *FShaderManager::BindEffect(int effect) } +//========================================================================== +// +// +// +//========================================================================== + +void gl_DestroyUserShaders() +{ + // todo +} + //========================================================================== // // Parses a shader definition diff --git a/src/gl/shaders/gl_shader.h b/src/gl/shaders/gl_shader.h index 27eb82ae..cacb15ea 100644 --- a/src/gl/shaders/gl_shader.h +++ b/src/gl/shaders/gl_shader.h @@ -131,7 +131,7 @@ class FShaderManager void Clean(); void CompileShaders(); - + public: FShaderManager(); ~FShaderManager(); diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index b869d1b7..bc488529 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -629,3 +629,12 @@ void OpenGLFrameBuffer::DrawRemainingPlayerSprites() { // not used by hardware renderer } + +void OpenGLFrameBuffer::GameRestart() +{ + memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256); + UpdatePalette (); + ScreenshotBuffer = NULL; + LastCamera = NULL; + gl_GenerateGlobalBrightmapFromColormap(); +} \ No newline at end of file diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index efe24fb5..0d48bfb8 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -48,6 +48,7 @@ public: int GetPageCount(); bool Begin2D(bool copy3d); void GetHitlist(BYTE *hitlist); + void GameRestart(); // Retrieves a buffer containing image data for a screenshot. // Hint: Pitch can be negative for upside-down images, in which case buffer diff --git a/src/gl/system/gl_interface.h b/src/gl/system/gl_interface.h index 0c5b6c2a..c2c39f95 100644 --- a/src/gl/system/gl_interface.h +++ b/src/gl/system/gl_interface.h @@ -5,20 +5,17 @@ enum RenderFlags { RFL_NPOT_TEXTURE=1, RFL_NOSTENCIL=2, - RFL_FRAGMENT_PROGRAM=4, - RFL_OCCLUSION_QUERY=16, - RFL_TEX_ENV_COMBINE4_NV=32, - RFL_TEX_ENV_COMBINE3_ATI=64, + RFL_OCCLUSION_QUERY=4, // [BB] Added texture compression flags. - RFL_TEXTURE_COMPRESSION=128, - RFL_TEXTURE_COMPRESSION_S3TC=256, + RFL_TEXTURE_COMPRESSION=8, + RFL_TEXTURE_COMPRESSION_S3TC=16, - RFL_VBO = 512, - RFL_MAP_BUFFER_RANGE = 1024, - RFL_FRAMEBUFFER = 2048, - RFL_TEXTUREBUFFER = 4096, - RFL_NVIDIA = 8192, - RFL_ATI = 16384, + RFL_VBO = 32, + RFL_MAP_BUFFER_RANGE = 64, + RFL_FRAMEBUFFER = 128, + RFL_TEXTUREBUFFER = 256, + RFL_NVIDIA = 512, + RFL_ATI = 1024, RFL_GL_20 = 0x10000000, diff --git a/src/gl/textures/gl_material.cpp b/src/gl/textures/gl_material.cpp index 495a90fc..680e73cf 100644 --- a/src/gl/textures/gl_material.cpp +++ b/src/gl/textures/gl_material.cpp @@ -834,10 +834,10 @@ outl: // //=========================================================================== -void FMaterial::Bind(int cm, int clampmode, int translation) +void FMaterial::Bind(int cm, int clampmode, int translation, int overrideshader) { int usebright = false; - int shaderindex = mShaderIndex; + int shaderindex = overrideshader > 0? overrideshader : mShaderIndex; int maxbound = 0; bool allowhires = tex->xScale == FRACUNIT && tex->yScale == FRACUNIT; @@ -848,7 +848,7 @@ void FMaterial::Bind(int cm, int clampmode, int translation) else clampmode = 4; const FHardwareTexture *gltexture = mBaseLayer->Bind(0, cm, clampmode, translation, allowhires? tex:NULL, softwarewarp); - if (gltexture != NULL && shaderindex > 0) + if (gltexture != NULL && shaderindex > 0 && overrideshader == 0) { for(unsigned i=0;i 0? overrideshader : mShaderIndex; int maxbound = 0; int softwarewarp = gl_RenderState.SetupShader(tex->bHasCanvas, shaderindex, cm, tex->gl_info.shaderspeed); diff --git a/src/gl/textures/gl_material.h b/src/gl/textures/gl_material.h index f5d29d27..f1402173 100644 --- a/src/gl/textures/gl_material.h +++ b/src/gl/textures/gl_material.h @@ -134,8 +134,8 @@ public: return !!mBaseLayer->tex->bMasked; } - void Bind(int cm, int clamp=0, int translation=0); - void BindPatch(int cm, int translation=0); + void Bind(int cm, int clamp = 0, int translation = 0, int overrideshader = 0); + void BindPatch(int cm, int translation = 0, int overrideshader = 0); unsigned char * CreateTexBuffer(int cm, int translation, int & w, int & h, bool expand = false, bool allowhires=true) const { diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index 2dc57563..8ec0491b 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -132,6 +132,7 @@ FRemapTable GlobalBrightmap; void gl_GenerateGlobalBrightmapFromColormap() { + HasGlobalBrightmap = false; int lump = Wads.CheckNumForName("COLORMAP"); if (lump == -1) lump = Wads.CheckNumForName("COLORMAP", ns_colormaps); if (lump == -1) return; diff --git a/src/info.cpp b/src/info.cpp index 1b49ce7d..32aa92a9 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -52,6 +52,8 @@ #include "g_level.h" extern void LoadActors (); +extern void InitBotStuff(); +extern void ClearStrifeTypes(); //========================================================================== @@ -100,6 +102,7 @@ int GetSpriteIndex(const char * spritename) void FActorInfo::StaticInit () { + sprites.Clear(); if (sprites.Size() == 0) { spritedef_t temp; @@ -120,7 +123,9 @@ void FActorInfo::StaticInit () } Printf ("LoadActors: Load actor definitions.\n"); + ClearStrifeTypes(); LoadActors (); + InitBotStuff(); } //========================================================================== diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index acb9fb62..0c75575c 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -110,10 +110,9 @@ void DIntermissionScreen::Init(FIntermissionAction *desc, bool first) { texname = GStrings[texname+1]; } - FTextureID tex = TexMan.CheckForTexture(texname, FTexture::TEX_MiscPatch); - if (tex.isValid()) + if (texname[0] != 0) { - mBackground = tex; + mBackground = TexMan.CheckForTexture(texname, FTexture::TEX_MiscPatch); mFlatfill = desc->mFlatfill; } S_Sound (CHAN_VOICE | CHAN_UI, desc->mSound, 1.0f, ATTN_NONE); @@ -392,7 +391,12 @@ void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first) mName = static_cast(desc)->mName; mClass = PClass::FindClass(static_cast(desc)->mCastClass); if (mClass != NULL) mDefaults = GetDefaultByType(mClass); - else mDefaults = NULL; + else + { + mDefaults = NULL; + caststate = NULL; + return; + } mCastSounds.Resize(static_cast(desc)->mCastSounds.Size()); for (unsigned i=0; i < mCastSounds.Size(); i++) @@ -405,15 +409,17 @@ void DIntermissionScreenCast::Init(FIntermissionAction *desc, bool first) if (mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn))) { advplayerstate = mDefaults->MissileState; - castsprite = skins[players[consoleplayer].userinfo.skin].sprite; casttranslation = translationtables[TRANSLATION_Players][consoleplayer]; } else { advplayerstate = NULL; - if (caststate != NULL) castsprite = caststate->sprite; - else castsprite = -1; casttranslation = NULL; + if (mDefaults->Translation != 0) + { + casttranslation = translationtables[GetTranslationType(mDefaults->Translation)] + [GetTranslationIndex(mDefaults->Translation)]; + } } castdeath = false; castframes = 0; @@ -433,21 +439,26 @@ int DIntermissionScreenCast::Responder (event_t *ev) return 1; // already in dying frames castdeath = true; - caststate = mClass->ActorInfo->FindState(NAME_Death); - if (caststate == NULL) return -1; - casttics = caststate->GetTics(); - castframes = 0; - castattacking = false; + if (mClass != NULL) + { + FName label[] = {NAME_Death, NAME_Cast}; + caststate = mClass->ActorInfo->FindState(2, label); + if (caststate == NULL) return -1; - if (mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn))) - { - int snd = S_FindSkinnedSound(players[consoleplayer].mo, "*death"); - if (snd != 0) S_Sound (CHAN_VOICE | CHAN_UI, snd, 1, ATTN_NONE); - } - else if (mDefaults->DeathSound) - { - S_Sound (CHAN_VOICE | CHAN_UI, mDefaults->DeathSound, 1, ATTN_NONE); + casttics = caststate->GetTics(); + castframes = 0; + castattacking = false; + + if (mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn))) + { + int snd = S_FindSkinnedSound(players[consoleplayer].mo, "*death"); + if (snd != 0) S_Sound (CHAN_VOICE | CHAN_UI, snd, 1, ATTN_NONE); + } + else if (mDefaults->DeathSound) + { + S_Sound (CHAN_VOICE | CHAN_UI, mDefaults->DeathSound, 1, ATTN_NONE); + } } return true; } @@ -478,7 +489,8 @@ int DIntermissionScreenCast::Ticker () if (--casttics > 0 && caststate != NULL) return 0; // not time to change state yet - if (caststate == NULL || caststate->GetTics() == -1 || caststate->GetNextState() == NULL) + if (caststate == NULL || caststate->GetTics() == -1 || caststate->GetNextState() == NULL || + (caststate->GetNextState() == caststate && castdeath)) { return -1; } @@ -494,7 +506,7 @@ int DIntermissionScreenCast::Ticker () castframes++; } - if (castframes == 12) + if (castframes == 12 && !castdeath) { // go into attack frame castattacking = true; @@ -559,6 +571,20 @@ void DIntermissionScreenCast::Drawer () // draw the current frame in the middle of the screen if (caststate != NULL) { + int castsprite; + + if (!(mDefaults->flags4 & MF4_NOSKIN) && + mDefaults->SpawnState != NULL && caststate->sprite == mDefaults->SpawnState->sprite && + mClass->IsDescendantOf(RUNTIME_CLASS(APlayerPawn)) && + skins != NULL) + { + castsprite = skins[players[consoleplayer].userinfo.skin].sprite; + } + else + { + castsprite = caststate->sprite; + } + sprframe = &SpriteFrames[sprites[castsprite].spriteframes + caststate->GetFrame()]; pic = TexMan(sprframe->Texture[0]); @@ -811,6 +837,7 @@ void F_StartIntermission(FIntermissionDescriptor *desc, bool deleteme, BYTE stat viewactive = false; automapactive = false; DIntermissionController::CurrentIntermission = new DIntermissionController(desc, deleteme, state); + GC::WriteBarrier(DIntermissionController::CurrentIntermission); } diff --git a/src/intermission/intermission.h b/src/intermission/intermission.h index 72dd5a2e..1035bd8f 100644 --- a/src/intermission/intermission.h +++ b/src/intermission/intermission.h @@ -80,6 +80,7 @@ struct FIntermissionAction TArray mOverlays; FIntermissionAction(); + virtual ~FIntermissionAction() {} virtual bool ParseKey(FScanner &sc); }; @@ -145,7 +146,7 @@ struct FIntermissionActionScroller : public FIntermissionAction struct FIntermissionDescriptor { FName mLink; - TArray mActions; + TDeletingArray mActions; }; typedef TMap FIntermissionDescriptorList; @@ -233,7 +234,6 @@ class DIntermissionScreenCast : public DIntermissionScreen TArray mCastSounds; int casttics; - int castsprite; // [RH] For overriding the player sprite with a skin const FRemapTable *casttranslation; // [RH] Draw "our hero" with their chosen suit color FState* caststate; FState* basestate; diff --git a/src/intermission/intermission_parse.cpp b/src/intermission/intermission_parse.cpp index b7951986..fab4dca2 100644 --- a/src/intermission/intermission_parse.cpp +++ b/src/intermission/intermission_parse.cpp @@ -47,6 +47,20 @@ static void ReplaceIntermission(FName intname,FIntermissionDescriptor *desc) IntermissionDescriptors[intname] = desc; } +void DeinitIntermissions() +{ + FIntermissionDescriptorList::Iterator it(IntermissionDescriptors); + + FIntermissionDescriptorList::Pair *pair; + + while (it.NextPair(pair)) + { + delete pair->Value; + pair->Value = NULL; + } + IntermissionDescriptors.Clear(); +} + //========================================================================== // // FIntermissionAction @@ -820,7 +834,15 @@ void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int textscreen->mText << '$' << text; } textscreen->mTextDelay = 10; - textscreen->mBackground = flat; + if (flat != NULL && *flat != 0) + { + textscreen->mBackground = flat; + } + else + { + // force a black screen if no texture is set. + textscreen->mBackground = "-"; + } textscreen->mFlatfill = !finalePic; if (music != NULL && *music != 0) diff --git a/src/keysections.cpp b/src/keysections.cpp index 60afce21..8d23c958 100644 --- a/src/keysections.cpp +++ b/src/keysections.cpp @@ -41,14 +41,16 @@ #include "c_bind.h" #include "c_dispatch.h" #include "gameconfigfile.h" +#include "w_wad.h" TArray KeySections; +extern TArray KeyConfWeapons; static void LoadKeys (const char *modname, bool dbl) { char section[64]; - mysnprintf (section, countof(section), "%s.%s%sBindings", gameinfo.ConfigName, modname, + mysnprintf (section, countof(section), "%s.%s%sBindings", gameinfo.ConfigName.GetChars(), modname, dbl ? ".Double" : "."); FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings; @@ -141,3 +143,79 @@ CCMD (addmenukey) } } +//========================================================================== +// +// D_LoadWadSettings +// +// Parses any loaded KEYCONF lumps. These are restricted console scripts +// that can only execute the alias, defaultbind, addkeysection, +// addmenukey, weaponsection, and addslotdefault commands. +// +//========================================================================== + +void D_LoadWadSettings () +{ + char cmd[4096]; + int lump, lastlump = 0; + + ParsingKeyConf = true; + KeySections.Clear(); + KeyConfWeapons.Clear(); + + while ((lump = Wads.FindLump ("KEYCONF", &lastlump)) != -1) + { + FMemLump data = Wads.ReadLump (lump); + const char *eof = (char *)data.GetMem() + Wads.LumpLength (lump); + const char *conf = (char *)data.GetMem(); + + while (conf < eof) + { + size_t i; + + // Fetch a line to execute + for (i = 0; conf + i < eof && conf[i] != '\n'; ++i) + { + cmd[i] = conf[i]; + } + cmd[i] = 0; + conf += i; + if (*conf == '\n') + { + conf++; + } + + // Comments begin with // + char *stop = cmd + i - 1; + char *comment = cmd; + int inQuote = 0; + + if (*stop == '\r') + *stop-- = 0; + + while (comment < stop) + { + if (*comment == '\"') + { + inQuote ^= 1; + } + else if (!inQuote && *comment == '/' && *(comment + 1) == '/') + { + break; + } + comment++; + } + if (comment == cmd) + { // Comment at line beginning + continue; + } + else if (comment < stop) + { // Comment in middle of line + *comment = 0; + } + + AddCommandString (cmd); + } + } + ParsingKeyConf = false; +} + diff --git a/src/m_argv.cpp b/src/m_argv.cpp index e414ca36..457a1b33 100644 --- a/src/m_argv.cpp +++ b/src/m_argv.cpp @@ -230,6 +230,26 @@ FString DArgs::TakeValue(const char *check) return out; } +//=========================================================================== +// +// DArgs :: RemoveArg +// +//=========================================================================== + +void DArgs::RemoveArgs(const char *check) +{ + int i = CheckParm(check); + + if (i > 0 && i < (int)Argv.Size() - 1) + { + do + { + RemoveArg(i); + } + while (Argv[i][0] != '+' && Argv[i][0] != '-' && i < (int)Argv.Size() - 1); + } +} + //=========================================================================== // // DArgs :: GetArg diff --git a/src/m_argv.h b/src/m_argv.h index 8b4fbf2d..0fc107a0 100644 --- a/src/m_argv.h +++ b/src/m_argv.h @@ -54,6 +54,7 @@ public: void AppendArg(FString arg); void AppendArgs(int argc, const FString *argv); void RemoveArg(int argindex); + void RemoveArgs(const char *check); void SetArgs(int argc, char **argv); void CollectFiles(const char *param, const char *extension); DArgs *GatherFiles(const char *param) const; diff --git a/src/m_fixed.h b/src/m_fixed.h index 14db59d6..61080d73 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -139,5 +139,6 @@ inline SDWORD ModDiv (SDWORD num, SDWORD den, SDWORD *dmval) #define FLOAT2FIXED(f) xs_Fix<16>::ToFix(f) #define FIXED2FLOAT(f) ((f) / float(65536)) +#define FIXED2DBL(f) ((f) / double(65536)) #endif diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 97bda849..bdc5c3c3 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -53,9 +53,10 @@ class DLoadSaveMenu : public DListMenu { DECLARE_CLASS(DLoadSaveMenu, DListMenu) + friend void ClearSaveGames(); protected: - static TDeletingArray SaveGames; + static TArray SaveGames; static int LastSaved; static int LastAccessed; @@ -114,7 +115,7 @@ public: IMPLEMENT_CLASS(DLoadSaveMenu) -TDeletingArray DLoadSaveMenu::SaveGames; +TArray DLoadSaveMenu::SaveGames; int DLoadSaveMenu::LastSaved = -1; int DLoadSaveMenu::LastAccessed = -1; @@ -126,6 +127,21 @@ FSaveGameNode *quickSaveSlot; // //============================================================================= +void ClearSaveGames() +{ + for(unsigned i=0;itype == EV_KeyDown || ev->type == EV_KeyUp) + else if (menuactive != MENU_WaitKey && (ev->type == EV_KeyDown || ev->type == EV_KeyUp)) { keyup = ev->type == EV_KeyUp; diff --git a/src/menu/menu.h b/src/menu/menu.h index e8632a0b..dc333b42 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -111,6 +111,22 @@ struct FListMenuDescriptor : public FMenuDescriptor const PClass *mClass; FMenuDescriptor *mRedirect; // used to redirect overlong skill and episode menus to option menu based alternatives bool mCenter; + + void Reset() + { + // Reset the default settings (ignore all other values in the struct) + mSelectOfsX = 0; + mSelectOfsY = 0; + mSelector.SetInvalid(); + mDisplayTop = 0; + mXpos = 0; + mYpos = 0; + mLinespacing = 0; + mNetgameMessage = ""; + mFont = NULL; + mFontColor = CR_UNTRANSLATED; + mFontColor2 = CR_UNTRANSLATED; + } }; struct FOptionMenuSettings @@ -141,6 +157,14 @@ struct FOptionMenuDescriptor : public FMenuDescriptor void CalcIndent(); FOptionMenuItem *GetItem(FName name); + void Reset() + { + // Reset the default settings (ignore all other values in the struct) + mPosition = 0; + mScrollTop = 0; + mIndent = 0; + mDontDim = 0; + } }; diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index a751caf5..f413a947 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -52,6 +52,8 @@ #include "optionmenuitems.h" +void ClearSaveGames(); + MenuDescriptorList MenuDescriptors; static FListMenuDescriptor DefaultListMenuSettings; // contains common settings for all list menus static FOptionMenuDescriptor DefaultOptionMenuSettings; // contains common settings for all Option menus @@ -83,7 +85,11 @@ static void DeinitMenus() pair->Value = NULL; } } + MenuDescriptors.Clear(); + OptionValues.Clear(); DMenu::CurrentMenu = NULL; + DefaultListMenuSettings.mItems.Clear(); + ClearSaveGames(); } //============================================================================= @@ -825,8 +831,11 @@ void M_ParseMenuDefs() OptionSettings.mFontColorHeader = V_FindFontColor(gameinfo.mFontColorHeader); OptionSettings.mFontColorHighlight = V_FindFontColor(gameinfo.mFontColorHighlight); OptionSettings.mFontColorSelection = V_FindFontColor(gameinfo.mFontColorSelection); + DefaultListMenuSettings.Reset(); + DefaultOptionMenuSettings.Reset(); atterm( DeinitMenus); + DeinitMenus(); while ((lump = Wads.FindLump ("MENUDEF", &lastlump)) != -1) { FScanner sc(lump); @@ -841,6 +850,10 @@ void M_ParseMenuDefs() else if (sc.Compare("DEFAULTLISTMENU")) { ParseListMenuBody(sc, &DefaultListMenuSettings); + if (DefaultListMenuSettings.mItems.Size() > 0) + { + I_FatalError("You cannot add menu items to the menu default settings."); + } } else if (sc.Compare("OPTIONVALUE")) { @@ -861,6 +874,10 @@ void M_ParseMenuDefs() else if (sc.Compare("DEFAULTOPTIONMENU")) { ParseOptionMenuBody(sc, &DefaultOptionMenuSettings); + if (DefaultOptionMenuSettings.mItems.Size() > 0) + { + I_FatalError("You cannot add menu items to the menu default settings."); + } } else { @@ -1221,10 +1238,11 @@ void M_CreateMenus() // THe skill menu must be refeshed each time it starts up // //============================================================================= +extern int restart; void M_StartupSkillMenu(FGameStartup *gs) { - static bool done = false; + static int done = -1; bool success = false; FMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Skillmenu); if (desc != NULL) @@ -1250,9 +1268,9 @@ void M_StartupSkillMenu(FGameStartup *gs) } } - if (!done) + if (done != restart) { - done = true; + done = restart; int defskill = DefaultSkill; if ((unsigned int)defskill >= AllSkills.Size()) { @@ -1327,7 +1345,7 @@ void M_StartupSkillMenu(FGameStartup *gs) } if (AllEpisodes[gs->Episode].mNoSkill || AllSkills.Size() == 1) { - ld->mAutoselect = firstitem + MIN(2u, AllEpisodes.Size()-1); + ld->mAutoselect = firstitem + MIN(2u, AllSkills.Size()-1); } else { diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index eecd997e..e415f57c 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -679,7 +679,7 @@ CCMD (quickload) if (netgame) { - M_StartMessage (GStrings("QLOADNET"), NULL); + M_StartMessage (GStrings("QLOADNET"), 1); return; } diff --git a/src/menu/optionmenuitems.h b/src/menu/optionmenuitems.h index e365f603..8aab6f9c 100644 --- a/src/menu/optionmenuitems.h +++ b/src/menu/optionmenuitems.h @@ -891,13 +891,13 @@ public: if (mkey == MKEY_Left) { if (--mSelection < 0) mSelection = mMaxValid; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); return true; } else if (mkey == MKEY_Right) { if (++mSelection > mMaxValid) mSelection = 0; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); + S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE); return true; } else diff --git a/src/menu/playermenu.cpp b/src/menu/playermenu.cpp index c4ad7b86..de0292f7 100644 --- a/src/menu/playermenu.cpp +++ b/src/menu/playermenu.cpp @@ -115,23 +115,34 @@ bool FPlayerNameBox::GetString(int i, char *s, int len) void FPlayerNameBox::DrawBorder (int x, int y, int len) { - if (gameinfo.gametype & (GAME_DoomStrifeChex)) + FTexture *left = TexMan[TexMan.CheckForTexture("M_LSLEFT", FTexture::TEX_MiscPatch)]; + FTexture *mid = TexMan[TexMan.CheckForTexture("M_LSCNTR", FTexture::TEX_MiscPatch)]; + FTexture *right = TexMan[TexMan.CheckForTexture("M_LSRGHT", FTexture::TEX_MiscPatch)]; + if (left != NULL && right != NULL && mid != NULL) { int i; - screen->DrawTexture (TexMan["M_LSLEFT"], x-8, y+7, DTA_Clean, true, TAG_DONE); + screen->DrawTexture (left, x-8, y+7, DTA_Clean, true, TAG_DONE); for (i = 0; i < len; i++) { - screen->DrawTexture (TexMan["M_LSCNTR"], x, y+7, DTA_Clean, true, TAG_DONE); + screen->DrawTexture (mid, x, y+7, DTA_Clean, true, TAG_DONE); x += 8; } - screen->DrawTexture (TexMan["M_LSRGHT"], x, y+7, DTA_Clean, true, TAG_DONE); + screen->DrawTexture (right, x, y+7, DTA_Clean, true, TAG_DONE); } else { - screen->DrawTexture (TexMan["M_FSLOT"], x, y+1, DTA_Clean, true, TAG_DONE); + FTexture *slot = TexMan[TexMan.CheckForTexture("M_FSLOT", FTexture::TEX_MiscPatch)]; + if (slot != NULL) + { + screen->DrawTexture (slot, x, y+1, DTA_Clean, true, TAG_DONE); + } + else + { + screen->Clear(x, y, x + len, y + SmallFont->GetHeight() * 3/2, -1, 0); + } } } @@ -901,7 +912,7 @@ void DPlayerMenu::ClassChanged (FListMenuItem *li) players[consoleplayer].userinfo.PlayerClass = sel-1; PickPlayerClass(); - cvar_set ("playerclass", sel == 0 ? "Random" : PlayerClass->Type->TypeName); + cvar_set ("playerclass", sel == 0 ? "Random" : PlayerClass->Type->Meta.GetMetaString (APMETA_DisplayName)); UpdateSkins(); UpdateColorsets(); diff --git a/src/namedef.h b/src/namedef.h index c9168fed..d9573b74 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -105,12 +105,6 @@ xx(ArtiPoisonBag3) // Strife quests xx(QuestItem) -// Auto-usable health items -xx(ArtiHealth) -xx(ArtiSuperHealth) -xx(MedicalKit) -xx(MedPatch) - // Armor xx(BasicArmor) @@ -251,6 +245,7 @@ xx(PoisonCloud) // makes monsters howl. // a damage type if you wanted to force an extreme death. xx(Extreme) xx(MDK) +xx(Cast) // 'damage type' for the cast call // Special names for thingdef_exp.cpp xx(Random) @@ -285,6 +280,8 @@ xx(Communicator) // Textmap properties //xx(X) //xx(Y) +xx(ZFloor) +xx(ZCeiling) xx(Height) //xx(Tid) //xx(Angle) @@ -424,6 +421,8 @@ xx(Silent) xx(Nofallingdamage) xx(Dropactors) xx(NoRespawn) +xx(Alphafloor) +xx(Alphaceiling) xx(offsetx_top) xx(offsety_top) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 390fc23c..6ba516db 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -707,5 +707,59 @@ secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z) return retplane; } +//========================================================================== +// +// Gives the index to an extra floor above or below the given location. +// -1 means normal floor or ceiling +// +//========================================================================== + +int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, bool floor, fixed_t &cmpz) +{ + // If no sector given, find the one appropriate + if (sec == NULL) + sec = R_PointInSubsector(x, y)->sector; + + // Above normal ceiling + cmpz = sec->ceilingplane.ZatPoint(x, y); + if (z >= cmpz) + return -1; + + // Below normal floor + cmpz = sec->floorplane.ZatPoint(x, y); + if (z <= cmpz) + return -1; + + // Looking through planes from top to bottom + for (int i = 0; i < (signed)sec->e->XFloor.ffloors.Size(); ++i) + { + F3DFloor *rover = sec->e->XFloor.ffloors[i]; + + // We are only interested in solid 3D floors here + if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue; + + if (above) + { + // z is above that floor + if (floor && (z >= (cmpz = rover->top.plane->ZatPoint(x, y)))) + return i - 1; + // z is above that ceiling + if (z >= (cmpz = rover->bottom.plane->ZatPoint(x, y))) + return i - 1; + } + else // below + { + // z is below that ceiling + if (!floor && (z <= (cmpz = rover->bottom.plane->ZatPoint(x, y)))) + return i; + // z is below that floor + if (z <= (cmpz = rover->top.plane->ZatPoint(x, y))) + return i; + } + } + + // Failsafe + return -1; +} #endif \ No newline at end of file diff --git a/src/p_3dfloors.h b/src/p_3dfloors.h index 6a0005ba..e58d316e 100644 --- a/src/p_3dfloors.h +++ b/src/p_3dfloors.h @@ -128,6 +128,7 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li fixed_t x, fixed_t y, fixed_t refx, fixed_t refy); secplane_t P_FindFloorPlane(sector_t * sector, fixed_t x, fixed_t y, fixed_t z); +int P_Find3DFloor(sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool above, bool floor, fixed_t &cmpz); #else diff --git a/src/p_acs.cpp b/src/p_acs.cpp index b789f22b..63c3f0a6 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -312,6 +312,7 @@ static void ReadArrayVars (PNGHandle *png, FWorldGlobalArray *vars, size_t count { SDWORD key, val; key = arc.ReadCount(); + val = arc.ReadCount(); vars[i].Insert (key, val); } @@ -2536,8 +2537,12 @@ enum APROP_DamageFactor = 24, APROP_MasterTID = 25, APROP_TargetTID = 26, - APROP_TracerTID = 27 -}; + APROP_TracerTID = 27, + APROP_WaterLevel = 28, + APROP_ScaleX = 29, + APROP_ScaleY = 30, + APROP_Dormant = 31, +}; // These are needed for ACS's APROP_RenderStyle static const int LegacyRenderStyleIndices[] = @@ -2717,6 +2722,14 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) DoSetMaster (actor, other); break; + case APROP_ScaleX: + actor->scaleX = value; + break; + + case APROP_ScaleY: + actor->scaleY = value; + break; + default: // do nothing. break; @@ -2757,6 +2770,7 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_Friendly: return !!(actor->flags & MF_FRIENDLY); case APROP_Notarget: return !!(actor->flags3 & MF3_NOTARGET); case APROP_Notrigger: return !!(actor->flags6 & MF6_NOTRIGGER); + case APROP_Dormant: return !!(actor->flags2 & MF2_DORMANT); case APROP_SpawnHealth: if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) { return static_cast(actor)->MaxHealth; @@ -2778,6 +2792,10 @@ int DLevelScript::GetActorProperty (int tid, int property) case APROP_MasterTID: return DoGetMasterTID (actor); case APROP_TargetTID: return (actor->target != NULL)? actor->target->tid : 0; case APROP_TracerTID: return (actor->tracer != NULL)? actor->tracer->tid : 0; + case APROP_WaterLevel: return actor->waterlevel; + case APROP_ScaleX: return actor->scaleX; + case APROP_ScaleY: return actor->scaleY; + default: return 0; } } @@ -2811,6 +2829,9 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_MasterTID: case APROP_TargetTID: case APROP_TracerTID: + case APROP_WaterLevel: + case APROP_ScaleX: + case APROP_ScaleY: return (GetActorProperty(tid, property) == value); // Boolean values need to compare to a binary version of value @@ -2822,6 +2843,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_Friendly: case APROP_Notarget: case APROP_Notrigger: + case APROP_Dormant: return (GetActorProperty(tid, property) == (!!value)); // Strings are not covered by GetActorProperty, so make the check here diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index ec569735..3cb60bcb 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -30,9 +30,11 @@ #include "r_state.h" #include "gi.h" +//============================================================================ // // CEILINGS // +//============================================================================ IMPLEMENT_CLASS (DCeiling) @@ -40,6 +42,12 @@ DCeiling::DCeiling () { } +//============================================================================ +// +// +// +//============================================================================ + void DCeiling::Serialize (FArchive &arc) { Super::Serialize (arc); @@ -59,6 +67,12 @@ void DCeiling::Serialize (FArchive &arc) << m_Hexencrush; } +//============================================================================ +// +// +// +//============================================================================ + void DCeiling::PlayCeilingSound () { if (m_Sector->seqType >= 0) @@ -80,9 +94,12 @@ void DCeiling::PlayCeilingSound () } } +//============================================================================ // -// T_MoveCeiling +// DCeiling :: Tick // +//============================================================================ + void DCeiling::Tick () { EResult res; @@ -176,6 +193,12 @@ void DCeiling::Tick () } } +//============================================================================ +// +// +// +//============================================================================ + DCeiling::DCeiling (sector_t *sec) : DMovingCeiling (sec) { @@ -191,11 +214,258 @@ DCeiling::DCeiling (sector_t *sec, fixed_t speed1, fixed_t speed2, int silent) m_Silent = silent; } +//============================================================================ +// +// +// +//============================================================================ + +DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, + fixed_t speed, fixed_t speed2, fixed_t height, + int crush, int silent, int change, bool hexencrush) +{ + fixed_t targheight = 0; // Silence, GCC + + // if ceiling already moving, don't start a second function on it + if (sec->PlaneMoving(sector_t::ceiling)) + { + return NULL; + } + + // new door thinker + DCeiling *ceiling = new DCeiling (sec, speed, speed2, silent); + vertex_t *spot = sec->lines[0]->v1; + + switch (type) + { + case ceilCrushAndRaise: + case ceilCrushRaiseAndStay: + ceiling->m_TopHeight = sec->ceilingplane.d; + case ceilLowerAndCrush: + case ceilLowerAndCrushDist: + targheight = sec->FindHighestFloorPoint (&spot); + if (type == ceilLowerAndCrush) + { + targheight += 8*FRACUNIT; + } + else if (type == ceilLowerAndCrushDist) + { + targheight += height; + } + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + break; + + case ceilRaiseToHighest: + targheight = sec->FindHighestCeilingSurrounding (&spot); + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = 1; + break; + + case ceilLowerByValue: + targheight = sec->ceilingplane.ZatPoint (spot) - height; + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + break; + + case ceilRaiseByValue: + targheight = sec->ceilingplane.ZatPoint (spot) + height; + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = 1; + break; + + case ceilMoveToValue: + { + int diff = height - sec->ceilingplane.ZatPoint (spot); + + targheight = height; + if (diff < 0) + { + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, height); + ceiling->m_Direction = -1; + } + else + { + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, height); + ceiling->m_Direction = 1; + } + } + break; + + case ceilLowerToHighestFloor: + targheight = sec->FindHighestFloorSurrounding (&spot); + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + break; + + case ceilRaiseToHighestFloor: + targheight = sec->FindHighestFloorSurrounding (&spot); + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = 1; + break; + + case ceilLowerInstant: + targheight = sec->ceilingplane.ZatPoint (spot) - height; + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + ceiling->m_Speed = height; + break; + + case ceilRaiseInstant: + targheight = sec->ceilingplane.ZatPoint (spot) + height; + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = 1; + ceiling->m_Speed = height; + break; + + case ceilLowerToNearest: + targheight = sec->FindNextLowestCeiling (&spot); + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + break; + + case ceilRaiseToNearest: + targheight = sec->FindNextHighestCeiling (&spot); + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = 1; + break; + + case ceilLowerToLowest: + targheight = sec->FindLowestCeilingSurrounding (&spot); + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + break; + + case ceilRaiseToLowest: + targheight = sec->FindLowestCeilingSurrounding (&spot); + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = 1; + break; + + case ceilLowerToFloor: + targheight = sec->FindHighestFloorPoint (&spot); + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + break; + + case ceilRaiseToFloor: // [RH] What's this for? + targheight = sec->FindHighestFloorPoint (&spot); + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = 1; + break; + + case ceilLowerToHighest: + targheight = sec->FindHighestCeilingSurrounding (&spot); + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + break; + + case ceilLowerByTexture: + targheight = sec->ceilingplane.ZatPoint (spot) - sec->FindShortestUpperAround (); + ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = -1; + break; + + case ceilRaiseByTexture: + targheight = sec->ceilingplane.ZatPoint (spot) + sec->FindShortestUpperAround (); + ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); + ceiling->m_Direction = 1; + break; + + default: + break; // Silence GCC + } + + ceiling->m_Tag = tag; + ceiling->m_Type = type; + ceiling->m_Crush = crush; + ceiling->m_Hexencrush = hexencrush; + + // Do not interpolate instant movement ceilings. + // Note for ZDoomGL: Check to make sure that you update the sector + // after the ceiling moves, because it hasn't actually moved yet. + fixed_t movedist; + + if (ceiling->m_Direction < 0) + { + movedist = sec->ceilingplane.d - ceiling->m_BottomHeight; + } + else + { + movedist = ceiling->m_TopHeight - sec->ceilingplane.d; + } + if (ceiling->m_Speed >= movedist) + { + ceiling->StopInterpolation(); + } + + // set texture/type change properties + if (change & 3) // if a texture change is indicated + { + if (change & 4) // if a numeric model change + { + sector_t *modelsec; + + //jff 5/23/98 find model with floor at target height if target + //is a floor type + modelsec = (/*type == ceilRaiseToHighest ||*/ + type == ceilRaiseToFloor || + /*type == ceilLowerToHighest ||*/ + type == ceilLowerToFloor) ? + sec->FindModelFloorSector (targheight) : + sec->FindModelCeilingSector (targheight); + if (modelsec != NULL) + { + ceiling->m_Texture = modelsec->GetTexture(sector_t::ceiling); + switch (change & 3) + { + case 1: // type is zeroed + ceiling->m_NewSpecial = 0; + ceiling->m_Type = genCeilingChg0; + break; + case 2: // type is copied + ceiling->m_NewSpecial = sec->special; + ceiling->m_Type = genCeilingChgT; + break; + case 3: // type is left alone + ceiling->m_Type = genCeilingChg; + break; + } + } + } + else if (line) // else if a trigger model change + { + ceiling->m_Texture = line->frontsector->GetTexture(sector_t::ceiling); + switch (change & 3) + { + case 1: // type is zeroed + ceiling->m_NewSpecial = 0; + ceiling->m_Type = genCeilingChg0; + break; + case 2: // type is copied + ceiling->m_NewSpecial = line->frontsector->special; + ceiling->m_Type = genCeilingChgT; + break; + case 3: // type is left alone + ceiling->m_Type = genCeilingChg; + break; + } + } + } + + ceiling->PlayCeilingSound (); + return ceiling; +} + +//============================================================================ // // EV_DoCeiling // Move a ceiling up/down and all around! // // [RH] Added tag, speed, speed2, height, crush, silent, change params +// +//============================================================================ + bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, int tag, fixed_t speed, fixed_t speed2, fixed_t height, int crush, int silent, int change, bool hexencrush) @@ -203,10 +473,6 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, int secnum; bool rtn; sector_t* sec; - DCeiling* ceiling; - bool manual = false; - fixed_t targheight = 0; // Silence, GCC - vertex_t* spot; rtn = false; @@ -216,11 +482,10 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, if (!line || !(sec = line->backsector)) return rtn; secnum = (int)(sec-sectors); - manual = true; // [RH] Hack to let manual crushers be retriggerable, too tag ^= secnum | 0x1000000; P_ActivateInStasisCeiling (tag); - goto manual_ceiling; + return !!DCeiling::Create(sec, type, line, tag, speed, speed2, height, crush, silent, change, hexencrush); } // Reactivate in-stasis ceilings...for certain types. @@ -234,252 +499,19 @@ bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, // affects all sectors with the same tag as the linedef while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) { - sec = §ors[secnum]; -manual_ceiling: - // if ceiling already moving, don't start a second function on it - if (sec->PlaneMoving(sector_t::ceiling)) - { - if (!manual) - continue; - else - return false; - } - - // new door thinker - rtn = 1; - ceiling = new DCeiling (sec, speed, speed2, silent); - spot = sec->lines[0]->v1; - - switch (type) - { - case DCeiling::ceilCrushAndRaise: - case DCeiling::ceilCrushRaiseAndStay: - ceiling->m_TopHeight = sec->ceilingplane.d; - case DCeiling::ceilLowerAndCrush: - case DCeiling::ceilLowerAndCrushDist: - targheight = sec->FindHighestFloorPoint (&spot); - if (type == DCeiling::ceilLowerAndCrush) - { - targheight += 8*FRACUNIT; - } - else if (type == DCeiling::ceilLowerAndCrushDist) - { - targheight += height; - } - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - break; - - case DCeiling::ceilRaiseToHighest: - targheight = sec->FindHighestCeilingSurrounding (&spot); - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = 1; - break; - - case DCeiling::ceilLowerByValue: - targheight = sec->ceilingplane.ZatPoint (spot) - height; - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - break; - - case DCeiling::ceilRaiseByValue: - targheight = sec->ceilingplane.ZatPoint (spot) + height; - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = 1; - break; - - case DCeiling::ceilMoveToValue: - { - int diff = height - sec->ceilingplane.ZatPoint (spot); - - targheight = height; - if (diff < 0) - { - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, height); - ceiling->m_Direction = -1; - } - else - { - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, height); - ceiling->m_Direction = 1; - } - } - break; - - case DCeiling::ceilLowerToHighestFloor: - targheight = sec->FindHighestFloorSurrounding (&spot); - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - break; - - case DCeiling::ceilRaiseToHighestFloor: - targheight = sec->FindHighestFloorSurrounding (&spot); - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = 1; - break; - - case DCeiling::ceilLowerInstant: - targheight = sec->ceilingplane.ZatPoint (spot) - height; - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - ceiling->m_Speed = height; - break; - - case DCeiling::ceilRaiseInstant: - targheight = sec->ceilingplane.ZatPoint (spot) + height; - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = 1; - ceiling->m_Speed = height; - break; - - case DCeiling::ceilLowerToNearest: - targheight = sec->FindNextLowestCeiling (&spot); - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - break; - - case DCeiling::ceilRaiseToNearest: - targheight = sec->FindNextHighestCeiling (&spot); - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = 1; - break; - - case DCeiling::ceilLowerToLowest: - targheight = sec->FindLowestCeilingSurrounding (&spot); - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - break; - - case DCeiling::ceilRaiseToLowest: - targheight = sec->FindLowestCeilingSurrounding (&spot); - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = 1; - break; - - case DCeiling::ceilLowerToFloor: - targheight = sec->FindHighestFloorPoint (&spot); - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - break; - - case DCeiling::ceilRaiseToFloor: // [RH] What's this for? - targheight = sec->FindHighestFloorPoint (&spot); - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = 1; - break; - - case DCeiling::ceilLowerToHighest: - targheight = sec->FindHighestCeilingSurrounding (&spot); - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - break; - - case DCeiling::ceilLowerByTexture: - targheight = sec->ceilingplane.ZatPoint (spot) - sec->FindShortestUpperAround (); - ceiling->m_BottomHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = -1; - break; - - case DCeiling::ceilRaiseByTexture: - targheight = sec->ceilingplane.ZatPoint (spot) + sec->FindShortestUpperAround (); - ceiling->m_TopHeight = sec->ceilingplane.PointToDist (spot, targheight); - ceiling->m_Direction = 1; - break; - - default: - break; // Silence GCC - } - - ceiling->m_Tag = tag; - ceiling->m_Type = type; - ceiling->m_Crush = crush; - ceiling->m_Hexencrush = hexencrush; - - // Do not interpolate instant movement ceilings. - // Note for ZDoomGL: Check to make sure that you update the sector - // after the ceiling moves, because it hasn't actually moved yet. - fixed_t movedist; - - if (ceiling->m_Direction < 0) - { - movedist = sec->ceilingplane.d - ceiling->m_BottomHeight; - } - else - { - movedist = ceiling->m_TopHeight - sec->ceilingplane.d; - } - if (ceiling->m_Speed >= movedist) - { - ceiling->StopInterpolation(); - } - - // set texture/type change properties - if (change & 3) // if a texture change is indicated - { - if (change & 4) // if a numeric model change - { - sector_t *modelsec; - - //jff 5/23/98 find model with floor at target height if target - //is a floor type - modelsec = (/*type == DCeiling::ceilRaiseToHighest ||*/ - type == DCeiling::ceilRaiseToFloor || - /*type == DCeiling::ceilLowerToHighest ||*/ - type == DCeiling::ceilLowerToFloor) ? - sec->FindModelFloorSector (targheight) : - sec->FindModelCeilingSector (targheight); - if (modelsec != NULL) - { - ceiling->m_Texture = modelsec->GetTexture(sector_t::ceiling); - switch (change & 3) - { - case 1: // type is zeroed - ceiling->m_NewSpecial = 0; - ceiling->m_Type = DCeiling::genCeilingChg0; - break; - case 2: // type is copied - ceiling->m_NewSpecial = sec->special; - ceiling->m_Type = DCeiling::genCeilingChgT; - break; - case 3: // type is left alone - ceiling->m_Type = DCeiling::genCeilingChg; - break; - } - } - } - else if (line) // else if a trigger model change - { - ceiling->m_Texture = line->frontsector->GetTexture(sector_t::ceiling); - switch (change & 3) - { - case 1: // type is zeroed - ceiling->m_NewSpecial = 0; - ceiling->m_Type = DCeiling::genCeilingChg0; - break; - case 2: // type is copied - ceiling->m_NewSpecial = line->frontsector->special; - ceiling->m_Type = DCeiling::genCeilingChgT; - break; - case 3: // type is left alone - ceiling->m_Type = DCeiling::genCeilingChg; - break; - } - } - } - - ceiling->PlayCeilingSound (); - - if (manual) - return rtn; + rtn |= !!DCeiling::Create(§ors[secnum], type, line, tag, speed, speed2, height, crush, silent, change, hexencrush); } return rtn; } +//============================================================================ // // Restart a ceiling that's in-stasis // [RH] Passed a tag instead of a line and rewritten to use a list // +//============================================================================ + void P_ActivateInStasisCeiling (int tag) { DCeiling *scan; @@ -495,11 +527,14 @@ void P_ActivateInStasisCeiling (int tag) } } +//============================================================================ // // EV_CeilingCrushStop // Stop a ceiling from crushing! // [RH] Passed a tag instead of a line and rewritten to use a list // +//============================================================================ + bool EV_CeilingCrushStop (int tag) { bool rtn = false; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 3c631c4e..39da6b65 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -145,6 +145,11 @@ void SetStrifeType(int convid, const PClass *Class) StrifeTypes[convid] = Class; } +void ClearStrifeTypes() +{ + StrifeTypes.Clear(); +} + void SetConversation(int convid, const PClass *Class, int dlgindex) { if (convid != -1) @@ -914,7 +919,7 @@ public: { if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_Char && ev->data1 >= '0' && ev->data1 <= '9') { // Activate an item of type numberedmore (dialogue only) - mSelection = ev->data1 == '0' ? 10 : ev->data1 - '0'; + mSelection = ev->data1 == '0' ? 9 : ev->data1 - '1'; return MenuEvent(MKEY_Enter, false); } return Super::Responder(ev); diff --git a/src/p_doors.cpp b/src/p_doors.cpp index e82adbe4..c01abab6 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -36,6 +36,12 @@ #include "sc_man.h" #include "cmdlib.h" +//============================================================================ +// +// VERTICAL DOORS +// +//============================================================================ + IMPLEMENT_CLASS (DDoor) DDoor::DDoor () @@ -55,14 +61,12 @@ void DDoor::Serialize (FArchive &arc) << m_LightTag; } - -// -// VERTICAL DOORS -// - +//============================================================================ // // T_VerticalDoor // +//============================================================================ + void DDoor::Tick () { EResult res; @@ -215,7 +219,12 @@ void DDoor::Tick () } } +//============================================================================ +// // [RH] DoorSound: Plays door sound depending on direction and speed +// +//============================================================================ + void DDoor::DoorSound (bool raise) const { int choice; @@ -309,10 +318,12 @@ DDoor::DDoor (sector_t *sector) { } -// [RH] Merged EV_VerticalDoor and EV_DoLockedDoor into EV_DoDoor -// and made them more general to support the new specials. - +//============================================================================ +// // [RH] SpawnDoor: Helper function for EV_DoDoor +// +//============================================================================ + DDoor::DDoor (sector_t *sec, EVlDoor type, fixed_t speed, int delay, int lightTag) : DMovingCeiling (sec), m_Type (type), m_Speed (speed), m_TopWait (delay), m_LightTag (lightTag) @@ -371,6 +382,13 @@ DDoor::DDoor (sector_t *sec, EVlDoor type, fixed_t speed, int delay, int lightTa m_OldFloorDist = sec->floorplane.d; } +//============================================================================ +// +// [RH] Merged EV_VerticalDoor and EV_DoLockedDoor into EV_DoDoor +// and made them more general to support the new specials. +// +//============================================================================ + bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing, int tag, int speed, int delay, int lock, int lightTag) { @@ -464,10 +482,12 @@ bool EV_DoDoor (DDoor::EVlDoor type, line_t *line, AActor *thing, return rtn; } - +//============================================================================ // // Spawn a door that closes after 30 seconds // +//============================================================================ + void P_SpawnDoorCloseIn30 (sector_t *sec) { fixed_t height; @@ -487,60 +507,59 @@ void P_SpawnDoorCloseIn30 (sector_t *sec) door->m_LightTag = 0; } +//============================================================================ // // Spawn a door that opens after 5 minutes // +//============================================================================ + void P_SpawnDoorRaiseIn5Mins (sector_t *sec) { sec->special = 0; new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0); } -// Strife's animated doors. Based on Doom's unused sliding doors, but significantly improved. -class DeletingDoorArray : public TArray +//============================================================================ +// +// animated doors +// +//============================================================================ + +IMPLEMENT_CLASS (DAnimatedDoor) + +DAnimatedDoor::DAnimatedDoor () { -public: - ~DeletingDoorArray() - { - for(unsigned i=0;iTextureFrames != NULL) - { - delete [] ani->TextureFrames; - ani->TextureFrames = NULL; - } - } - } -}; - -DeletingDoorArray DoorAnimations; - -// EV_SlidingDoor : slide a door horizontally -// (animate midtexture, then set noblocking line) -// - -// -// Return index into "DoorAnimations" array for which door type to use -// -static int P_FindSlidingDoorType (FTextureID picnum) -{ - unsigned int i; - - for (i = 0; i < DoorAnimations.Size(); ++i) - { - if (picnum == DoorAnimations[i].BaseTexture) - return i; - } - - return -1; } +DAnimatedDoor::DAnimatedDoor (sector_t *sec) + : DMovingCeiling (sec) +{ +} + +void DAnimatedDoor::Serialize (FArchive &arc) +{ + Super::Serialize (arc); + + arc << m_Line1 << m_Line2 + << m_Frame + << m_Timer + << m_BotDist + << m_Status + << m_Speed + << m_Delay + << m_DoorAnim + << m_SetBlocking1 << m_SetBlocking2; +} + +//============================================================================ +// +// Starts a closing action on an animated door +// +//============================================================================ + bool DAnimatedDoor::StartClosing () { - FDoorAnimation &ani = DoorAnimations[m_WhichDoorIndex]; - // CAN DOOR CLOSE? if (m_Sector->touching_thinglist != NULL) { @@ -557,9 +576,9 @@ bool DAnimatedDoor::StartClosing () m_Line1->flags |= ML_BLOCKING; m_Line2->flags |= ML_BLOCKING; - if (ani.CloseSound != NAME_None) + if (m_DoorAnim->CloseSound != NAME_None) { - SN_StartSequence (m_Sector, CHAN_CEILING, ani.CloseSound, 1); + SN_StartSequence (m_Sector, CHAN_CEILING, m_DoorAnim->CloseSound, 1); } m_Status = Closing; @@ -567,9 +586,20 @@ bool DAnimatedDoor::StartClosing () return true; } +//============================================================================ +// +// +// +//============================================================================ + void DAnimatedDoor::Tick () { - FDoorAnimation &ani = DoorAnimations[m_WhichDoorIndex]; + if (m_DoorAnim == NULL) + { + // can only happen when a bad savegame is loaded. + Destroy(); + return; + } switch (m_Status) { @@ -581,7 +611,7 @@ void DAnimatedDoor::Tick () case Opening: if (!m_Timer--) { - if (++m_Frame >= ani.NumTextureFrames) + if (++m_Frame >= m_DoorAnim->NumTextureFrames) { // IF DOOR IS DONE OPENING... m_Line1->flags &= ~ML_BLOCKING; @@ -602,10 +632,10 @@ void DAnimatedDoor::Tick () // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME... m_Timer = m_Speed; - m_Line1->sidedef[0]->SetTexture(side_t::mid, ani.TextureFrames[m_Frame]); - m_Line1->sidedef[1]->SetTexture(side_t::mid, ani.TextureFrames[m_Frame]); - m_Line2->sidedef[0]->SetTexture(side_t::mid, ani.TextureFrames[m_Frame]); - m_Line2->sidedef[1]->SetTexture(side_t::mid, ani.TextureFrames[m_Frame]); + m_Line1->sidedef[0]->SetTexture(side_t::mid, m_DoorAnim->TextureFrames[m_Frame]); + m_Line1->sidedef[1]->SetTexture(side_t::mid, m_DoorAnim->TextureFrames[m_Frame]); + m_Line2->sidedef[0]->SetTexture(side_t::mid, m_DoorAnim->TextureFrames[m_Frame]); + m_Line2->sidedef[1]->SetTexture(side_t::mid, m_DoorAnim->TextureFrames[m_Frame]); } } break; @@ -648,61 +678,23 @@ void DAnimatedDoor::Tick () // IF DOOR NEEDS TO ANIMATE TO NEXT FRAME... m_Timer = m_Speed; - m_Line1->sidedef[0]->SetTexture(side_t::mid, ani.TextureFrames[m_Frame]); - m_Line1->sidedef[1]->SetTexture(side_t::mid, ani.TextureFrames[m_Frame]); - m_Line2->sidedef[0]->SetTexture(side_t::mid, ani.TextureFrames[m_Frame]); - m_Line2->sidedef[1]->SetTexture(side_t::mid, ani.TextureFrames[m_Frame]); + m_Line1->sidedef[0]->SetTexture(side_t::mid, m_DoorAnim->TextureFrames[m_Frame]); + m_Line1->sidedef[1]->SetTexture(side_t::mid, m_DoorAnim->TextureFrames[m_Frame]); + m_Line2->sidedef[0]->SetTexture(side_t::mid, m_DoorAnim->TextureFrames[m_Frame]); + m_Line2->sidedef[1]->SetTexture(side_t::mid, m_DoorAnim->TextureFrames[m_Frame]); } } break; } } -IMPLEMENT_CLASS (DAnimatedDoor) +//============================================================================ +// +// +// +//============================================================================ -DAnimatedDoor::DAnimatedDoor () -{ -} - -DAnimatedDoor::DAnimatedDoor (sector_t *sec) - : DMovingCeiling (sec) -{ -} - -void DAnimatedDoor::Serialize (FArchive &arc) -{ - Super::Serialize (arc); - - FTextureID basetex = DoorAnimations[m_WhichDoorIndex].BaseTexture; - - arc << m_Line1 << m_Line2 - << m_Frame - << m_Timer - << m_BotDist - << m_Status - << m_Speed - << m_Delay - << basetex; - if (SaveVersion < 2336) - { - m_SetBlocking1 = m_SetBlocking2 = true; - } - else - { - arc << m_SetBlocking1 << m_SetBlocking2; - } - - if (arc.IsLoading()) - { - m_WhichDoorIndex = P_FindSlidingDoorType (basetex); - if (m_WhichDoorIndex == -1) - { // Oh no! The door animation doesn't exist anymore! - m_WhichDoorIndex = 0; - } - } -} - -DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay) +DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim) : DMovingCeiling (sec) { fixed_t topdist; @@ -711,13 +703,7 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay) // The DMovingCeiling constructor automatically sets up an interpolation for us. // Stop it, since the ceiling is moving instantly here. StopInterpolation(); - m_WhichDoorIndex = P_FindSlidingDoorType (line->sidedef[0]->GetTexture(side_t::top)); - if (m_WhichDoorIndex < 0) - { - Printf ("EV_SlidingDoor: Textures are not defined for sliding door!"); - m_Status = Dead; - return; - } + m_DoorAnim = anim; m_Line1 = line; m_Line2 = line; @@ -756,15 +742,16 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay) m_Line2->flags |= ML_BLOCKING; m_BotDist = m_Sector->ceilingplane.d; MoveCeiling (2048*FRACUNIT, topdist, 1); - if (DoorAnimations[m_WhichDoorIndex].OpenSound != NAME_None) + if (m_DoorAnim->OpenSound != NAME_None) { - SN_StartSequence (m_Sector, CHAN_INTERIOR, DoorAnimations[m_WhichDoorIndex].OpenSound, 1); + SN_StartSequence (m_Sector, CHAN_INTERIOR, m_DoorAnim->OpenSound, 1); } } //============================================================================ // -// EV_SlidingDoor +// EV_SlidingDoor : slide a door horizontally +// (animate midtexture, then set noblocking line) // //============================================================================ @@ -798,9 +785,10 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay) } return false; } - if (P_FindSlidingDoorType (line->sidedef[0]->GetTexture(side_t::top)) >= 0) + FDoorAnimation *anim = TexMan.FindAnimatedDoor (line->sidedef[0]->GetTexture(side_t::top)); + if (anim != NULL) { - new DAnimatedDoor (sec, line, speed, delay); + new DAnimatedDoor (sec, line, speed, delay, anim); return true; } return false; @@ -821,10 +809,11 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay) { continue; } - if (P_FindSlidingDoorType (line->sidedef[0]->GetTexture(side_t::top)) >= 0) + FDoorAnimation *anim = TexMan.FindAnimatedDoor (line->sidedef[0]->GetTexture(side_t::top)); + if (anim != NULL) { rtn = true; - new DAnimatedDoor (sec, line, speed, delay); + new DAnimatedDoor (sec, line, speed, delay, anim); break; } } @@ -832,62 +821,3 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay) return rtn; } -void P_ParseAnimatedDoor(FScanner &sc) -{ - const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; - FDoorAnimation anim; - TArray frames; - bool error = false; - FTextureID v; - - sc.MustGetString(); - anim.BaseTexture = TexMan.CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); - - if (!anim.BaseTexture.Exists()) - { - error = true; - } - - while (sc.GetString ()) - { - if (sc.Compare ("opensound")) - { - sc.MustGetString (); - anim.OpenSound = sc.String; - } - else if (sc.Compare ("closesound")) - { - sc.MustGetString (); - anim.CloseSound = sc.String; - } - else if (sc.Compare ("pic")) - { - sc.MustGetString (); - if (IsNum (sc.String)) - { - v = anim.BaseTexture + (atoi(sc.String) - 1); - } - else - { - v = TexMan.CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); - if (!v.Exists() && anim.BaseTexture.Exists() && !error) - { - sc.ScriptError ("Unknown texture %s", sc.String); - } - frames.Push (v); - } - } - else - { - sc.UnGet (); - break; - } - } - if (!error) - { - anim.TextureFrames = new FTextureID[frames.Size()]; - memcpy (anim.TextureFrames, &frames[0], sizeof(FTextureID) * frames.Size()); - anim.NumTextureFrames = frames.Size(); - DoorAnimations.Push (anim); - } -} diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 378aaae9..2a61f833 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -2517,6 +2517,25 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates) if ( abs(corpsehit-> x - viletryx) > maxdist || abs(corpsehit-> y - viletryy) > maxdist ) continue; // not actually touching +#ifdef _3DFLOORS + // Let's check if there are floors in between the archvile and its target + sector_t *vilesec = self->Sector; + sector_t *corpsec = corpsehit->Sector; + // We only need to test if at least one of the sectors has a 3D floor. + sector_t *testsec = vilesec->e->XFloor.ffloors.Size() ? vilesec : + (vilesec != corpsec && corpsec->e->XFloor.ffloors.Size()) ? corpsec : NULL; + if (testsec) + { + fixed_t zdist1, zdist2; + if (P_Find3DFloor(testsec, corpsehit->x, corpsehit->y, corpsehit->z, false, true, zdist1) + != P_Find3DFloor(testsec, self->x, self->y, self->z, false, true, zdist2)) + { + // Not on same floor + if (vilesec == corpsec || abs(zdist1 - self->z) > self->height) + continue; + } + } +#endif corpsehit->velx = corpsehit->vely = 0; // [RH] Check against real height and radius diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index c48d72e8..4d34c704 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1223,6 +1223,7 @@ static void CreateCachedNodes(MapData *map) FILE *f = fopen(path, "wb"); fwrite(compressed, 1, outlen+offset, f); fclose(f); + delete [] compressed; } diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 93bb0c44..4a082cff 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1164,7 +1164,8 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage // but telefragging should still do enough damage to kill the player) if ((player->cheats & CF_BUDDHA) && damage < TELEFRAG_DAMAGE) { - target->health = player->health = 1; + // If this is a voodoo doll we need to handle the real player as well. + player->mo->health = target->health = player->health = 1; } else { diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index d71bfbf7..1b3f627a 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1683,10 +1683,18 @@ FUNC(LS_FloorAndCeiling_RaiseByValue) } FUNC(LS_FloorAndCeiling_LowerRaise) -// FloorAndCeiling_LowerRaise (tag, fspeed, cspeed) +// FloorAndCeiling_LowerRaise (tag, fspeed, cspeed, boomemu) { - return EV_DoCeiling (DCeiling::ceilRaiseToHighest, ln, arg0, SPEED(arg2), 0, 0, 0, 0, 0, false) | - EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0, false); + bool res = EV_DoCeiling (DCeiling::ceilRaiseToHighest, ln, arg0, SPEED(arg2), 0, 0, 0, 0, 0, false); + // The switch based Boom equivalents of FloorandCeiling_LowerRaise do incorrect checks + // which cause the floor only to move when the ceiling fails to do so. + // To avoid problems with maps that have incorrect args this only uses a + // more or less unintuitive value for the fourth arg to trigger Boom's broken behavior + if (arg3 != 1998 || !res) // (1998 for the year in which Boom was released... :P) + { + res |= EV_DoFloor (DFloor::floorLowerToLowest, ln, arg0, SPEED(arg1), 0, 0, 0, false); + } + return res; } FUNC(LS_Elevator_MoveToFloor) @@ -1897,7 +1905,7 @@ void AdjustPusher (int tag, int magnitude, int angle, DPusher::EPusher type) unsigned int i; for (i = 0; i < numcollected; i++) { - if (Collection[i].RefNum == sectors[secnum].tag) + if (Collection[i].RefNum == sectors[secnum].sectornum) break; } if (i == numcollected) @@ -2790,6 +2798,7 @@ FUNC(LS_Autosave) { if (gameaction != ga_savegame) { + level.flags2 &= ~LEVEL2_NOAUTOSAVEHINT; Net_WriteByte (DEM_CHECKAUTOSAVE); } return true; diff --git a/src/p_map.cpp b/src/p_map.cpp index 424591be..725d6582 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4305,8 +4305,8 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b return; fulldamagedistance = clamp(fulldamagedistance, 0, bombdistance-1); - float bombdistancefloat = 1.f / (float)(bombdistance - fulldamagedistance); - float bombdamagefloat = (float)bombdamage; + double bombdistancefloat = 1.f / (double)(bombdistance - fulldamagedistance); + double bombdamagefloat = (double)bombdamage; FVector3 bombvec(FIXED2FLOAT(bombspot->x), FIXED2FLOAT(bombspot->y), FIXED2FLOAT(bombspot->z)); @@ -4325,7 +4325,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b if (thing->flags3 & MF3_NORADIUSDMG && !(bombspot->flags4 & MF4_FORCERADIUSDMG)) continue; - if (!DamageSource && thing == bombsource) + if (!DamageSource && (thing == bombsource || thing == bombspot)) { // don't damage the source of the explosion continue; } @@ -4349,29 +4349,29 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b { // [RH] New code. The bounding box only covers the // height of the thing and not the height of the map. - float points; - float len; + double points; + double len; fixed_t dx, dy; - float boxradius; + double boxradius; dx = abs (thing->x - bombspot->x); dy = abs (thing->y - bombspot->y); - boxradius = float (thing->radius); + boxradius = double (thing->radius); // The damage pattern is square, not circular. - len = float (dx > dy ? dx : dy); + len = double (dx > dy ? dx : dy); if (bombspot->z < thing->z || bombspot->z >= thing->z + thing->height) { - float dz; + double dz; if (bombspot->z > thing->z) { - dz = float (bombspot->z - thing->z - thing->height); + dz = double (bombspot->z - thing->z - thing->height); } else { - dz = float (thing->z - bombspot->z); + dz = double (thing->z - bombspot->z); } if (len <= boxradius) { @@ -4380,7 +4380,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b else { len -= boxradius; - len = sqrtf (len*len + dz*dz); + len = sqrt (len*len + dz*dz); } } else @@ -4390,18 +4390,18 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b len = 0.f; } len /= FRACUNIT; - len = clamp(len - (float)fulldamagedistance, 0, len); + len = clamp(len - (double)fulldamagedistance, 0, len); points = bombdamagefloat * (1.f - len * bombdistancefloat); if (thing == bombsource) { points = points * splashfactor; } - points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT)/(float)FRACUNIT; + points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT)/(double)FRACUNIT; if (points > 0.f && P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) { // OK to damage; target is in direct path - float velz; - float thrust; + double velz; + double thrust; int damage = (int)points; if (bombdodamage) P_DamageMobj (thing, bombspot, bombsource, damage, bombmod); @@ -4415,12 +4415,12 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b { if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST)) { - thrust = points * 0.5f / (float)thing->Mass; + thrust = points * 0.5f / (double)thing->Mass; if (bombsource == thing) { thrust *= selfthrustscale; } - velz = (float)(thing->z + (thing->height>>1) - bombspot->z) * thrust; + velz = (double)(thing->z + (thing->height>>1) - bombspot->z) * thrust; if (bombsource != thing) { velz *= 0.5f; @@ -4460,7 +4460,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b { // OK to damage; target is in direct path dist = clamp(dist - fulldamagedistance, 0, dist); int damage = Scale (bombdamage, bombdistance-dist, bombdistance); - damage = (int)((float)damage * splashfactor); + damage = (int)((double)damage * splashfactor); damage = Scale(damage, thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT), FRACUNIT); if (damage > 0) @@ -4737,9 +4737,11 @@ int P_PushUp (AActor *thing, FChangePosition *cpos) { AActor *intersect = intersectors[firstintersect]; if (!(intersect->flags2 & MF2_PASSMOBJ) || - (!(intersect->flags3 & MF3_ISMONSTER) && - intersect->Mass > mymass)) - { // Can't push things more massive than ourself + (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || + (intersect->flags4 & MF4_ACTLIKEBRIDGE) + ) + { + // Can't push bridges or things more massive than ourself return 2; } fixed_t oldz = intersect->z; @@ -4779,9 +4781,11 @@ int P_PushDown (AActor *thing, FChangePosition *cpos) { AActor *intersect = intersectors[firstintersect]; if (!(intersect->flags2 & MF2_PASSMOBJ) || - (!(intersect->flags3 & MF3_ISMONSTER) && - intersect->Mass > mymass)) - { // Can't push things more massive than ourself + (!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) || + (intersect->flags4 & MF4_ACTLIKEBRIDGE) + ) + { + // Can't push bridges or things more massive than ourself return 2; } fixed_t oldz = intersect->z; @@ -4813,6 +4817,7 @@ void PIT_FloorDrop (AActor *thing, FChangePosition *cpos) P_AdjustFloorCeil (thing, cpos); if (oldfloorz == thing->floorz) return; + if (thing->flags4 & MF4_ACTLIKEBRIDGE) return; // do not move bridge things if (thing->velz == 0 && (!(thing->flags & MF_NOGRAVITY) || @@ -4856,6 +4861,11 @@ void PIT_FloorRaise (AActor *thing, FChangePosition *cpos) if (thing->z <= thing->floorz || (!(thing->flags & MF_NOGRAVITY) && (thing->flags2 & MF2_FLOATBOB))) { + if (thing->flags4 & MF4_ACTLIKEBRIDGE) + { + cpos->nofit = true; + return; // do not move bridge things + } intersectors.Clear (); fixed_t oldz = thing->z; if (!(thing->flags2 & MF2_FLOATBOB)) @@ -4898,6 +4908,11 @@ void PIT_CeilingLower (AActor *thing, FChangePosition *cpos) if (thing->z + thing->height > thing->ceilingz) { + if (thing->flags4 & MF4_ACTLIKEBRIDGE) + { + cpos->nofit = true; + return; // do not move bridge things + } intersectors.Clear (); fixed_t oldz = thing->z; if (thing->ceilingz - thing->height >= thing->floorz) @@ -4935,6 +4950,8 @@ void PIT_CeilingRaise (AActor *thing, FChangePosition *cpos) { bool isgood = P_AdjustFloorCeil (thing, cpos); + if (thing->flags4 & MF4_ACTLIKEBRIDGE) return; // do not move bridge things + // For DOOM compatibility, only move things that are inside the floor. // (or something else?) Things marked as hanging from the ceiling will // stay where they are. diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 71e0a251..39a17bf7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -81,7 +81,6 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj); extern cycle_t BotSupportCycles; extern int BotWTG; -EXTERN_CVAR (Bool, r_drawfuzz); EXTERN_CVAR (Int, cl_rockettrails) // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -258,18 +257,9 @@ void AActor::Serialize (FArchive &arc) << args[0] << args[1] << args[2] << args[3] << args[4] << goal << waterlevel - << MinMissileChance; - if (SaveVersion >= 2826) - { - arc << SpawnFlags; - } - else - { - WORD w; - arc << w; - SpawnFlags = w; - } - arc << Inventory + << MinMissileChance + << SpawnFlags + << Inventory << InventoryID << id << FloatBobPhase @@ -281,12 +271,9 @@ void AActor::Serialize (FArchive &arc) << ActiveSound << UseSound << BounceSound - << WallBounceSound; - if (SaveVersion >= 2234) - { - arc << CrushPainSound; - } - arc << Speed + << WallBounceSound + << CrushPainSound + << Speed << FloatSpeed << Mass << PainChance @@ -313,83 +300,14 @@ void AActor::Serialize (FArchive &arc) << pushfactor << Species << Score - << Tag; - if (SaveVersion >= 1904) - { - arc << lastpush << lastbump; - } - - if (SaveVersion >= 1900) - { - arc << PainThreshold; - } - if (SaveVersion >= 1914) - { - arc << DamageFactor; - } - if (SaveVersion > 2036) - { - arc << WeaveIndexXY << WeaveIndexZ; - } - else - { - int index; - - if (SaveVersion < 2036) - { - index = special2; - } - else - { - arc << index; - } - // A_BishopMissileWeave and A_CStaffMissileSlither stored the weaveXY - // value in different parts of the index. - if (this->IsKindOf(PClass::FindClass("BishopFX"))) - { - WeaveIndexXY = index >> 16; - WeaveIndexZ = index; - } - else - { - WeaveIndexXY = index; - WeaveIndexZ = 0; - } - } - if (SaveVersion >= 2450) - { - arc << PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner; - arc << PoisonDamage << PoisonDuration << PoisonPeriod; - } - - // Skip past uservar array in old savegames - if (SaveVersion < 1933) - { - int foo; - for (int i = 0; i < 10; ++i) - arc << foo; - } - - if (SaveVersion > 2560) - { - arc << ConversationRoot << Conversation; - } - else // old code which uses relative indexing. - { - int convnum; - - convnum = arc.ReadCount(); - if (GetConversation(GetClass()->TypeName) == -1) - { - Conversation = NULL; - ConversationRoot = -1; - } - else - { - // This cannot be restored anymore. - I_Error("Cannot load old savegames with active dialogues"); - } - } + << Tag + << lastpush << lastbump + << PainThreshold + << DamageFactor + << WeaveIndexXY << WeaveIndexZ + << PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner + << PoisonDamage << PoisonDuration << PoisonPeriod + << ConversationRoot << Conversation; if (arc.IsLoading ()) { @@ -2237,7 +2155,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) mo->z = mo->floorz; if (mo->velz < 0) { - const fixed_t minvel = -9*FRACUNIT; // landing speed from a jump with normal gravity + const fixed_t minvel = -8*FRACUNIT; // landing speed from a jump with normal gravity // Spawn splashes, etc. P_HitFloor (mo); @@ -2253,7 +2171,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) mo->HitFloor (); if (mo->player) { - if (mo->player->jumpTics != 0 && mo->velz < -grav*4) + if (mo->player->jumpTics < 0 || mo->velz < minvel) { // delay any jumping for a short while mo->player->jumpTics = 7; } @@ -4417,7 +4335,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) mobj->tid = mthing->thingid; mobj->AddToHash (); - mobj->PrevAngle = mobj->angle = (DWORD)((mthing->angle * UCONST64(0x100000000)) / 360); + mobj->PrevAngle = mobj->angle = (DWORD)((mthing->angle * CONST64(0x100000000)) / 360); // Check if this actor's mapthing has a conversation defined if (mthing->Conversation > 0) @@ -4526,6 +4444,8 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc th = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement th->velz = FRACUNIT*2; th->angle = dir; + // [NG] Applying PUFFGETSOWNER to the blood will make it target the owner + if (th->flags5 & MF5_PUFFGETSOWNER) th->target = originator; if (gameinfo.gametype & GAME_DoomChex) { th->tics -= pr_spawnblood() & 3; @@ -4667,6 +4587,8 @@ void P_RipperBlood (AActor *mo, AActor *bleeder) { AActor *th; th = Spawn (bloodcls, x, y, z, NO_REPLACE); // GetBloodType already performed the replacement + // [NG] Applying PUFFGETSOWNER to the blood will make it target the owner + if (th->flags5 & MF5_PUFFGETSOWNER) th->target = bleeder; if (gameinfo.gametype == GAME_Heretic) th->flags |= MF_NOGRAVITY; th->velx = mo->velx >> 1; @@ -4909,7 +4831,7 @@ bool P_HitFloor (AActor *thing) void P_CheckSplash(AActor *self, fixed_t distance) { - if (self->z <= self->floorz + (distance<floorsector == self->Sector) + if (self->z <= self->floorz + (distance<floorsector == self->Sector && self->Sector->GetHeightSec() == NULL) { // Explosion splashes never alert monsters. This is because A_Explode has // a separate parameter for that so this would get in the way of proper @@ -5626,7 +5548,7 @@ const char *AActor::GetTag(const char *def) const void AActor::ClearCounters() { - if (CountsAsKill()) + if (CountsAsKill() && health > 0) { level.total_monsters--; flags &= ~MF_COUNTKILL; @@ -5663,12 +5585,13 @@ void FreeDropItemChain(FDropItem *chain) } } -FDropItemPtrArray::~FDropItemPtrArray() +void FDropItemPtrArray::Clear() { for (unsigned int i = 0; i < Size(); ++i) { FreeDropItemChain ((*this)[i]); } + TArray::Clear(); } int StoreDropItemChain(FDropItem *chain) diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index a30e2d73..606acdb2 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -861,15 +861,7 @@ void P_MovePsprites (player_t *player) FArchive &operator<< (FArchive &arc, pspdef_t &def) { - arc << def.state << def.tics << def.sx << def.sy; - if (SaveVersion >= 2295) - { - arc << def.sprite << def.frame; - } - else - { - def.sprite = def.state->sprite; - def.frame = def.state->Frame; - } + arc << def.state << def.tics << def.sx << def.sy + << def.sprite << def.frame; return arc; } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 4be7243f..a8d01acf 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -347,16 +347,8 @@ void P_SerializeWorld (FArchive &arc) << sec->interpolations[0] << sec->interpolations[1] << sec->interpolations[2] - << sec->interpolations[3]; - - if (SaveVersion < 2492) - { - sec->SeqName = NAME_None; - } - else - { - arc << sec->SeqName; - } + << sec->interpolations[3] + << sec->SeqName; sec->e->Serialize(arc); if (arc.IsStoring ()) @@ -374,7 +366,7 @@ void P_SerializeWorld (FArchive &arc) << desaturate; sec->ColorMap = GetSpecialLights (color, fade, desaturate); } - arc << sec->ceiling_reflect << sec->floor_reflect; + arc << sec->reflect[sector_t::ceiling] << sec->reflect[sector_t::floor]; } // do lines @@ -445,7 +437,7 @@ FArchive &operator<< (FArchive &arc, sector_t::splane &p) { arc << p.xform.xoffs << p.xform.yoffs << p.xform.xscale << p.xform.yscale << p.xform.angle << p.xform.base_yoffs << p.xform.base_angle - << p.Flags << p.Light << p.Texture << p.TexZ; + << p.Flags << p.Light << p.Texture << p.TexZ << p.alpha; return arc; } @@ -607,15 +599,6 @@ void P_SerializeSubsectors(FArchive &arc) } else { - if (SaveVersion < 2609) - { - if (hasglnodes) - { - RecalculateDrawnSubsectors(); - } - return; - } - arc << num_verts << num_subs << num_nodes; if (num_verts != numvertexes || num_subs != numsubsectors || diff --git a/src/p_setup.cpp b/src/p_setup.cpp index b34b0cc2..6051d51c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -106,6 +106,8 @@ bool P_IsBuildMap(MapData *map); // int numvertexes; vertex_t* vertexes; +int numvertexdatas; +vertexdata_t* vertexdatas; int numsegs; seg_t* segs; @@ -795,6 +797,7 @@ void P_LoadVertexes (MapData * map) // Determine number of vertices: // total lump length / vertex record length. numvertexes = map->MapLumps[ML_VERTEXES].Size / sizeof(mapvertex_t); + numvertexdatas = 0; if (numvertexes == 0) { @@ -803,6 +806,7 @@ void P_LoadVertexes (MapData * map) // Allocate memory for buffer. vertexes = new vertex_t[numvertexes]; + vertexdatas = NULL; map->Seek(ML_VERTEXES); @@ -1460,7 +1464,8 @@ void P_LoadSectors (MapData * map) ss->nextsec = -1; //jff 2/26/98 add fields to support locking out ss->prevsec = -1; // stair retriggering until build completes - // killough 3/7/98: + ss->SetAlpha(sector_t::floor, FRACUNIT); + ss->SetAlpha(sector_t::ceiling, FRACUNIT); ss->SetXScale(sector_t::floor, FRACUNIT); // [RH] floor and ceiling scaling ss->SetYScale(sector_t::floor, FRACUNIT); ss->SetXScale(sector_t::ceiling, FRACUNIT); @@ -1817,6 +1822,7 @@ void P_SetLineID (line_t *ld) { ld->id = ld->args[0]; } + ld->special = 0; break; case TranslucentLine: @@ -1873,8 +1879,8 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha) ld->frontsector = ld->sidedef[0] != NULL ? ld->sidedef[0]->sector : NULL; ld->backsector = ld->sidedef[1] != NULL ? ld->sidedef[1]->sector : NULL; - float dx = FIXED2FLOAT(ld->v2->x - ld->v1->x); - float dy = FIXED2FLOAT(ld->v2->y - ld->v1->y); + double dx = FIXED2DBL(ld->v2->x - ld->v1->x); + double dy = FIXED2DBL(ld->v2->y - ld->v1->y); int linenum = int(ld-lines); if (ld->frontsector == NULL) @@ -1883,7 +1889,7 @@ void P_FinishLoadingLineDef(line_t *ld, int alpha) } // [RH] Set some new sidedef properties - int len = (int)(sqrtf (dx*dx + dy*dy) + 0.5f); + int len = (int)(sqrt (dx*dx + dy*dy) + 0.5f); if (ld->sidedef[0] != NULL) { @@ -3398,11 +3404,13 @@ void P_FreeLevelData () delete[] vertexes; vertexes = NULL; } + numvertexes = 0; if (segs != NULL) { delete[] segs; segs = NULL; } + numsegs = 0; if (glsegextras != NULL) { delete[] glsegextras; @@ -3413,8 +3421,8 @@ void P_FreeLevelData () delete[] sectors[0].e; delete[] sectors; sectors = NULL; - numsectors = 0; // needed for the pointer cleanup code } + numsectors = 0; if (gamenodes != NULL && gamenodes != nodes) { delete[] gamenodes; @@ -3447,11 +3455,14 @@ void P_FreeLevelData () delete[] lines; lines = NULL; } + numlines = 0; if (sides != NULL) { delete[] sides; sides = NULL; } + numsides = 0; + if (blockmaplump != NULL) { delete[] blockmaplump; @@ -3508,6 +3519,7 @@ void P_FreeLevelData () delete[] zones; zones = NULL; } + numzones = 0; P_FreeStrifeConversations (); if (level.Scrolls != NULL) { @@ -3532,6 +3544,7 @@ void P_FreeExtraLevelData() delete node; node = next; } + FBlockNode::FreeBlocks = NULL; } { msecnode_t *node = headsecnode; @@ -3570,8 +3583,11 @@ void P_SetupLevel (char *lumpname, int position) wminfo.partime = 180; + MapThingsConverted.Clear(); + linemap.Clear(); FCanvasTextureInfo::EmptyList (); R_FreePastViewers (); + P_ClearUDMFKeys(); if (!savegamerestore) { @@ -4124,8 +4140,6 @@ void P_Init () atterm (P_Shutdown); P_InitEffects (); // [RH] - R_InitPicAnims (); - P_InitSwitchList (); P_InitTerrainTypes (); P_InitKeyMessages (); R_InitSprites (); @@ -4137,11 +4151,7 @@ static void P_Shutdown () P_DeinitKeyMessages (); P_FreeLevelData (); P_FreeExtraLevelData (); - if (StatusBar != NULL) - { - StatusBar->Destroy(); - StatusBar = NULL; - } + ST_Clear(); } #if 0 diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 4324ebc0..359b5d4d 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -102,6 +102,11 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) // // crosses a two sided line // + + // ignore self referencing sectors if COMPAT_TRACE is on + if ((i_compatflags & COMPATF_TRACE) && li->frontsector == li->backsector) + return true; + fixed_t trX=trace.x + FixedMul (trace.dx, in->frac); fixed_t trY=trace.y + FixedMul (trace.dy, in->frac); P_LineOpening (open, NULL, li, trX, trY); diff --git a/src/p_slopes.cpp b/src/p_slopes.cpp index 3ebaef14..7cf6c5fb 100644 --- a/src/p_slopes.cpp +++ b/src/p_slopes.cpp @@ -309,6 +309,27 @@ static void P_SetSlopesFromVertexHeights(FMapThing *firstmt, FMapThing *lastmt) mt->type = 0; } } + + for(int i = 0; i < numvertexdatas; i++) + { + if (vertexdatas[i].flags & VERTEXFLAG_ZCeilingEnabled) + { + vt_heights[1][i] = vertexdatas[i].zCeiling; + vt_found = true; + } + + if (vertexdatas[i].flags & VERTEXFLAG_ZFloorEnabled) + { + vt_heights[0][i] = vertexdatas[i].zFloor; + vt_found = true; + } + } + + // If vertexdata_t is ever extended for non-slope usage, this will obviously have to be deferred or removed. + delete[] vertexdatas; + vertexdatas = NULL; + numvertexdatas = 0; + if (vt_found) { for (int i = 0; i < numsectors; i++) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index d48ef90d..cf97c16f 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -867,10 +867,11 @@ static void SetupFloorPortal (AStackPoint *point) NActorIterator it (NAME_LowerStackLookOnly, point->tid); sector_t *Sector = point->Sector; Sector->FloorSkyBox = static_cast(it.Next()); - if (Sector->FloorSkyBox != NULL) + if (Sector->FloorSkyBox != NULL && Sector->FloorSkyBox->bAlways) { Sector->FloorSkyBox->Mate = point; - Sector->FloorSkyBox->PlaneAlpha = Scale (point->args[0], OPAQUE, 255); + if (Sector->GetAlpha(sector_t::floor) == OPAQUE) + Sector->SetAlpha(sector_t::floor, Scale (point->args[0], OPAQUE, 255)); } } @@ -879,13 +880,47 @@ static void SetupCeilingPortal (AStackPoint *point) NActorIterator it (NAME_UpperStackLookOnly, point->tid); sector_t *Sector = point->Sector; Sector->CeilingSkyBox = static_cast(it.Next()); - if (Sector->CeilingSkyBox != NULL) + if (Sector->CeilingSkyBox != NULL && Sector->CeilingSkyBox->bAlways) { Sector->CeilingSkyBox->Mate = point; - Sector->CeilingSkyBox->PlaneAlpha = Scale (point->args[0], OPAQUE, 255); + if (Sector->GetAlpha(sector_t::ceiling) == OPAQUE) + Sector->SetAlpha(sector_t::ceiling, Scale (point->args[0], OPAQUE, 255)); } } +static bool SpreadCeilingPortal(AStackPoint *pt, fixed_t alpha, sector_t *sector) +{ + bool fail = false; + sector->validcount = validcount; + for(int i=0; ilinecount; i++) + { + line_t *line = sector->lines[i]; + sector_t *backsector = sector == line->frontsector? line->backsector : line->frontsector; + if (line->backsector == line->frontsector) continue; + if (backsector == NULL) { fail = true; continue; } + if (backsector->validcount == validcount) continue; + if (backsector->CeilingSkyBox == pt) continue; + + // Check if the backside would map to the same visplane + if (backsector->CeilingSkyBox != NULL) { fail = true; continue; } + if (backsector->ceilingplane != sector->ceilingplane) { fail = true; continue; } + if (backsector->lightlevel != sector->lightlevel) { fail = true; continue; } + if (backsector->GetTexture(sector_t::ceiling) != sector->GetTexture(sector_t::ceiling)) { fail = true; continue; } + if (backsector->GetXOffset(sector_t::ceiling) != sector->GetXOffset(sector_t::ceiling)) { fail = true; continue; } + if (backsector->GetYOffset(sector_t::ceiling) != sector->GetYOffset(sector_t::ceiling)) { fail = true; continue; } + if (backsector->GetXScale(sector_t::ceiling) != sector->GetXScale(sector_t::ceiling)) { fail = true; continue; } + if (backsector->GetYScale(sector_t::ceiling) != sector->GetYScale(sector_t::ceiling)) { fail = true; continue; } + if (backsector->GetAngle(sector_t::ceiling) != sector->GetAngle(sector_t::ceiling)) { fail = true; continue; } + if (SpreadCeilingPortal(pt, alpha, backsector)) { fail = true; continue; } + } + if (!fail) + { + sector->CeilingSkyBox = pt; + sector->SetAlpha(sector_t::ceiling, alpha); + } + return fail; +} + void P_SetupPortals() { TThinkerIterator it; @@ -906,45 +941,28 @@ void P_SetupPortals() pt->special1 = 0; points.Push(pt); } - - for(unsigned i=0;ispecial1 == 0 && points[i]->Mate != NULL) - { - for(unsigned j=1;jspecial1 == 0 && points[j]->Mate != NULL && points[i]->GetClass() == points[j]->GetClass()) - { - fixed_t deltax1 = points[i]->Mate->x - points[i]->x; - fixed_t deltay1 = points[i]->Mate->y - points[i]->y; - fixed_t deltax2 = points[j]->Mate->x - points[j]->x; - fixed_t deltay2 = points[j]->Mate->y - points[j]->y; - if (deltax1 == deltax2 && deltay1 == deltay2) - { - if (points[j]->Sector->FloorSkyBox == points[j]->Mate) - points[j]->Sector->FloorSkyBox = points[i]->Mate; - - if (points[j]->Sector->CeilingSkyBox == points[j]->Mate) - points[j]->Sector->CeilingSkyBox = points[i]->Mate; - - points[j]->special1 = 1; - } - } - } - } - } } -inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal) +inline void SetPortal(sector_t *sector, int plane, AStackPoint *portal, fixed_t alpha) { // plane: 0=floor, 1=ceiling, 2=both if (plane > 0) { - if (sector->CeilingSkyBox == NULL) sector->CeilingSkyBox = portal; + if (sector->CeilingSkyBox == NULL || !sector->CeilingSkyBox->bAlways) + { + sector->CeilingSkyBox = portal; + if (sector->GetAlpha(sector_t::ceiling) == OPAQUE) + sector->SetAlpha(sector_t::ceiling, alpha); + } } if (plane == 2 || plane == 0) { - if (sector->FloorSkyBox == NULL) sector->FloorSkyBox = portal; + if (sector->FloorSkyBox == NULL || !sector->FloorSkyBox->bAlways) + { + sector->FloorSkyBox = portal; + } + if (sector->GetAlpha(sector_t::floor) == OPAQUE) + sector->SetAlpha(sector_t::floor, alpha); } } @@ -964,6 +982,7 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha) fixed_t y1 = (line->v1->y + line->v2->y) >> 1; fixed_t x2 = (lines[i].v1->x + lines[i].v2->x) >> 1; fixed_t y2 = (lines[i].v1->y + lines[i].v2->y) >> 1; + fixed_t alpha = Scale (lines[i].args[4], OPAQUE, 255); AStackPoint *anchor = Spawn(x1, y1, 0, NO_REPLACE); AStackPoint *reference = Spawn(x2, y2, 0, NO_REPLACE); @@ -978,7 +997,7 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha) for (int s=-1; (s = P_FindSectorFromTag(sectortag,s)) >= 0;) { - SetPortal(§ors[s], plane, reference); + SetPortal(§ors[s], plane, reference, alpha); } for (int j=0;j= 0;) { - SetPortal(§ors[s], plane, reference); + SetPortal(§ors[s], plane, reference, alpha); } } } diff --git a/src/p_spec.h b/src/p_spec.h index 70b79ec0..8656e424 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -396,9 +396,6 @@ void EV_StartLightFading (int tag, int value, int tics); bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *quest=NULL); bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno); -void P_InitSwitchList (); -void P_ProcessSwitchDef (FScanner &sc); - // // P_PLATS // @@ -598,23 +595,12 @@ inline FArchive &operator<< (FArchive &arc, DDoor::EVlDoor &type) return arc; } -struct FDoorAnimation -{ - FTextureID BaseTexture; - FTextureID *TextureFrames; - int NumTextureFrames; - FName OpenSound; - FName CloseSound; -}; - -void P_ParseAnimatedDoor (FScanner &sc); - class DAnimatedDoor : public DMovingCeiling { DECLARE_CLASS (DAnimatedDoor, DMovingCeiling) public: DAnimatedDoor (sector_t *sector); - DAnimatedDoor (sector_t *sector, line_t *line, int speed, int delay); + DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, FDoorAnimation *anim); void Serialize (FArchive &arc); void Tick (); @@ -623,7 +609,7 @@ public: protected: line_t *m_Line1, *m_Line2; int m_Frame; - int m_WhichDoorIndex; + FDoorAnimation *m_DoorAnim; int m_Timer; fixed_t m_BotDist; int m_Status; @@ -691,6 +677,10 @@ public: void Serialize (FArchive &arc); void Tick (); + static DCeiling *Create(sector_t *sec, DCeiling::ECeiling type, line_t *line, int tag, + fixed_t speed, fixed_t speed2, fixed_t height, + int crush, int silent, int change, bool hexencrush); + protected: ECeiling m_Type; fixed_t m_BottomHeight; @@ -716,9 +706,6 @@ protected: private: DCeiling (); - friend bool EV_DoCeiling (DCeiling::ECeiling type, line_t *line, - int tag, fixed_t speed, fixed_t speed2, fixed_t height, - int crush, int silent, int change, bool hexencrush); friend bool EV_CeilingCrushStop (int tag); friend void P_ActivateInStasisCeiling (int tag); }; diff --git a/src/p_states.cpp b/src/p_states.cpp index 15ff3711..21dd1537 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -861,7 +861,6 @@ bool FStateDefinitions::AddStates(FState *state, const char *framechars) int FStateDefinitions::FinishStates (FActorInfo *actor, AActor *defaults) { - static int c=0; int count = StateArray.Size(); if (count > 0) diff --git a/src/p_switch.cpp b/src/p_switch.cpp index 42363358..6e468e41 100644 --- a/src/p_switch.cpp +++ b/src/p_switch.cpp @@ -46,12 +46,9 @@ #include "w_wad.h" #include "tarray.h" #include "cmdlib.h" -#include "sc_man.h" #include "gi.h" -#define MAX_FRAMES 128 - static FRandom pr_switchanim ("AnimSwitch"); class DActiveButton : public DThinker @@ -59,357 +56,33 @@ class DActiveButton : public DThinker DECLARE_CLASS (DActiveButton, DThinker) public: DActiveButton (); - DActiveButton (side_t *, int, WORD switchnum, fixed_t x, fixed_t y, bool flippable); + DActiveButton (side_t *, int, FSwitchDef *, fixed_t x, fixed_t y, bool flippable); void Serialize (FArchive &arc); void Tick (); - side_t *m_Side; - SBYTE m_Part; - WORD m_SwitchDef; - WORD m_Frame; - WORD m_Timer; - bool bFlippable; - fixed_t m_X, m_Y; // Location of timer sound + side_t *m_Side; + SBYTE m_Part; + bool bFlippable; + bool bReturning; + FSwitchDef *m_SwitchDef; + SDWORD m_Frame; + DWORD m_Timer; + fixed_t m_X, m_Y; // Location of timer sound protected: bool AdvanceFrame (); }; -struct FSwitchDef -{ - FTextureID PreTexture; // texture to switch from - WORD PairIndex; // switch def to use to return to PreTexture - WORD NumFrames; // # of animation frames - FSoundID Sound; // sound to play at start of animation - bool QuestPanel; // Special texture for Strife mission - struct frame // Array of times followed by array of textures - { // actual length of each array is - DWORD Time; - FTextureID Texture; - } u[1]; -}; - -static int STACK_ARGS SortSwitchDefs (const void *a, const void *b); -static FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad); -static WORD AddSwitchDef (FSwitchDef *def); - -// -// CHANGE THE TEXTURE OF A WALL SWITCH TO ITS OPPOSITE -// - -class DeletingSwitchArray : public TArray -{ -public: - ~DeletingSwitchArray() - { - for(unsigned i=0;iPreTexture = def2->u[0].Texture = TexMan.CheckForTexture (list_p /* .name1 */, FTexture::TEX_Wall, texflags); - def2->PreTexture = def1->u[0].Texture = TexMan.CheckForTexture (list_p + 9, FTexture::TEX_Wall, texflags); - def1->Sound = def2->Sound = 0; - def1->NumFrames = def2->NumFrames = 1; - def1->u[0].Time = def2->u[0].Time = 0; - def2->PairIndex = AddSwitchDef (def1); - def1->PairIndex = AddSwitchDef (def2); - } - } - } - - SwitchList.ShrinkToFit (); - - // Sort SwitchList for quick searching - origMap = new FSwitchDef *[SwitchList.Size ()]; - for (i = 0; i < (int)SwitchList.Size (); i++) - { - origMap[i] = SwitchList[i]; - } - - qsort (&SwitchList[0], i, sizeof(FSwitchDef *), SortSwitchDefs); - - // Correct the PairIndex of each switch def, since the sorting broke them - for (i = (int)(SwitchList.Size () - 1); i >= 0; i--) - { - FSwitchDef *def = SwitchList[i]; - if (def->PairIndex != 65535) - { - for (j = (int)(SwitchList.Size () - 1); j >= 0; j--) - { - if (SwitchList[j] == origMap[def->PairIndex]) - { - def->PairIndex = (WORD)j; - break; - } - } - } - } - - delete[] origMap; -} - -static int STACK_ARGS SortSwitchDefs (const void *a, const void *b) -{ - return (*(FSwitchDef **)a)->PreTexture - (*(FSwitchDef **)b)->PreTexture; -} - -// Parse a switch block in ANIMDEFS and add the definitions to SwitchList -void P_ProcessSwitchDef (FScanner &sc) -{ - const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; - FString picname; - FSwitchDef *def1, *def2; - FTextureID picnum; - int gametype; - bool quest = false; - - def1 = def2 = NULL; - sc.MustGetString (); - if (sc.Compare ("doom")) - { - gametype = GAME_DoomChex; - sc.CheckNumber(); // skip the gamemission filter - } - else if (sc.Compare ("heretic")) - { - gametype = GAME_Heretic; - } - else if (sc.Compare ("hexen")) - { - gametype = GAME_Hexen; - } - else if (sc.Compare ("strife")) - { - gametype = GAME_Strife; - } - else if (sc.Compare ("any")) - { - gametype = GAME_Any; - } - else - { - // There is no game specified; just treat as any - //max = 240; - gametype = GAME_Any; - sc.UnGet (); - } - - sc.MustGetString (); - picnum = TexMan.CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); - picname = sc.String; - while (sc.GetString ()) - { - if (sc.Compare ("quest")) - { - quest = true; - } - else if (sc.Compare ("on")) - { - if (def1 != NULL) - { - sc.ScriptError ("Switch already has an on state"); - } - def1 = ParseSwitchDef (sc, !picnum.Exists()); - } - else if (sc.Compare ("off")) - { - if (def2 != NULL) - { - sc.ScriptError ("Switch already has an off state"); - } - def2 = ParseSwitchDef (sc, !picnum.Exists()); - } - else - { - sc.UnGet (); - break; - } - } - - if (def1 == NULL || !picnum.Exists() || - (gametype != GAME_Any && !(gametype & gameinfo.gametype))) - { - if (def2 != NULL) - { - M_Free (def2); - } - if (def1 != NULL) - { - M_Free (def1); - } - return; - } - - // If the switch did not have an off state, create one that just returns - // it to the original texture without doing anything interesting - if (def2 == NULL) - { - def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); - def2->Sound = def1->Sound; - def2->NumFrames = 1; - def2->u[0].Time = 0; - def2->u[0].Texture = picnum; - } - - def1->PreTexture = picnum; - def2->PreTexture = def1->u[def1->NumFrames-1].Texture; - if (def1->PreTexture == def2->PreTexture) - { - sc.ScriptError ("The on state for switch %s must end with a texture other than %s", picname.GetChars(), picname.GetChars()); - } - def2->PairIndex = AddSwitchDef (def1); - def1->PairIndex = AddSwitchDef (def2); - def1->QuestPanel = def2->QuestPanel = quest; -} - -FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad) -{ - const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; - FSwitchDef *def; - TArray frames; - FSwitchDef::frame thisframe; - FTextureID picnum; - bool bad; - FSoundID sound; - - bad = false; - - while (sc.GetString ()) - { - if (sc.Compare ("sound")) - { - if (sound != 0) - { - sc.ScriptError ("Switch state already has a sound"); - } - sc.MustGetString (); - sound = sc.String; - } - else if (sc.Compare ("pic")) - { - sc.MustGetString (); - picnum = TexMan.CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); - if (!picnum.Exists() && !ignoreBad) - { - //Printf ("Unknown switch texture %s\n", sc.String); - bad = true; - } - thisframe.Texture = picnum; - sc.MustGetString (); - if (sc.Compare ("tics")) - { - sc.MustGetNumber (); - thisframe.Time = sc.Number & 65535; - } - else if (sc.Compare ("rand")) - { - int min, max; - - sc.MustGetNumber (); - min = sc.Number & 65535; - sc.MustGetNumber (); - max = sc.Number & 65535; - if (min > max) - { - swapvalues (min, max); - } - thisframe.Time = ((max - min + 1) << 16) | min; - } - else - { - thisframe.Time = 0; // Shush, GCC. - sc.ScriptError ("Must specify a duration for switch frame"); - } - frames.Push(thisframe); - } - else - { - sc.UnGet (); - break; - } - } - if (frames.Size() == 0) - { - sc.ScriptError ("Switch state needs at least one frame"); - } - if (bad) - { - return NULL; - } - - def = (FSwitchDef *)M_Malloc (myoffsetof (FSwitchDef, u[0]) + frames.Size()*sizeof(frames[0])); - def->Sound = sound; - def->NumFrames = frames.Size(); - memcpy (&def->u[0], &frames[0], frames.Size() * sizeof(frames[0])); - def->PairIndex = 65535; - return def; -} - -static WORD AddSwitchDef (FSwitchDef *def) -{ - unsigned int i; - - for (i = SwitchList.Size (); i-- > 0; ) - { - if (SwitchList[i]->PreTexture == def->PreTexture) - { - free (SwitchList[i]); - SwitchList[i] = def; - return (WORD)i; - } - } - return (WORD)SwitchList.Push (def); -} +//========================================================================== // // Start a button counting down till it turns off. // [RH] Rewritten to remove MAXBUTTONS limit. // -static bool P_StartButton (side_t *side, int Where, int switchnum, - fixed_t x, fixed_t y, bool useagain) +//========================================================================== + +static bool P_StartButton (side_t *side, int Where, FSwitchDef *Switch, fixed_t x, fixed_t y, bool useagain) { DActiveButton *button; TThinkerIterator iterator; @@ -424,44 +97,18 @@ static bool P_StartButton (side_t *side, int Where, int switchnum, } } - new DActiveButton (side, Where, switchnum, x, y, useagain); + new DActiveButton (side, Where, Switch, x, y, useagain); return true; } -static int TryFindSwitch (side_t *side, int Where) -{ - int mid, low, high; - - FTextureID texture = side->GetTexture(Where); - high = (int)(SwitchList.Size () - 1); - if (high >= 0) - { - low = 0; - do - { - mid = (high + low) / 2; - if (SwitchList[mid]->PreTexture == texture) - { - return mid; - } - else if (texture < SwitchList[mid]->PreTexture) - { - high = mid - 1; - } - else - { - low = mid + 1; - } - } while (low <= high); - } - return -1; -} - +//========================================================================== // // Checks whether a switch is reachable // This is optional because old maps can rely on being able to // use non-reachable switches. // +//========================================================================== + bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) { // Activated from an empty side -> always succeed @@ -521,15 +168,15 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) if (open.range <= 0) goto onesided; - if ((TryFindSwitch (side, side_t::top)) != -1) + if ((TexMan.FindSwitch (side->GetTexture(side_t::top))) != NULL) { return (user->z + user->height >= open.top); } - else if ((TryFindSwitch (side, side_t::bottom)) != -1) + else if ((TexMan.FindSwitch (side->GetTexture(side_t::bottom))) != NULL) { return (user->z <= open.bottom); } - else if ((line->flags & (ML_3DMIDTEX)) || (TryFindSwitch (side, side_t::mid)) != -1) + else if ((line->flags & (ML_3DMIDTEX)) || (TexMan.FindSwitch (side->GetTexture(side_t::mid))) != NULL) { // 3DMIDTEX lines will force a mid texture check if no switch is found on this line // to keep compatibility with Eternity's implementation. @@ -544,24 +191,28 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno) } } +//========================================================================== // // Function that changes wall texture. // Tell it if switch is ok to use again (1=yes, it's a button). // +//========================================================================== + bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *quest) { int texture; - int i, sound; + int sound; + FSwitchDef *Switch; - if ((i = TryFindSwitch (side, side_t::top)) != -1) + if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::top))) != NULL) { texture = side_t::top; } - else if ((i = TryFindSwitch (side, side_t::bottom)) != -1) + else if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::bottom))) != NULL) { texture = side_t::bottom; } - else if ((i = TryFindSwitch (side, side_t::mid)) != -1) + else if ((Switch = TexMan.FindSwitch (side->GetTexture(side_t::mid))) != NULL) { texture = side_t::mid; } @@ -575,9 +226,9 @@ bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *ques } // EXIT SWITCH? - if (SwitchList[i]->Sound != 0) + if (Switch->Sound != 0) { - sound = SwitchList[i]->Sound; + sound = Switch->Sound; } else { @@ -599,20 +250,32 @@ bool P_ChangeSwitchTexture (side_t *side, int useAgain, BYTE special, bool *ques pt[0] = line->v1->x + (line->dx >> 1); pt[1] = line->v1->y + (line->dy >> 1); - side->SetTexture(texture, SwitchList[i]->u[0].Texture); - if (useAgain || SwitchList[i]->NumFrames > 1) - playsound = P_StartButton (side, texture, i, pt[0], pt[1], !!useAgain); + side->SetTexture(texture, Switch->frames[0].Texture); + if (useAgain || Switch->NumFrames > 1) + { + playsound = P_StartButton (side, texture, Switch, pt[0], pt[1], !!useAgain); + } else + { playsound = true; + } if (playsound) + { S_Sound (pt[0], pt[1], 0, CHAN_VOICE|CHAN_LISTENERZ, sound, 1, ATTN_STATIC); + } if (quest != NULL) { - *quest = SwitchList[i]->QuestPanel; + *quest = Switch->QuestPanel; } return true; } +//========================================================================== +// +// Button thinker +// +//========================================================================== + IMPLEMENT_CLASS (DActiveButton) DActiveButton::DActiveButton () @@ -624,9 +287,11 @@ DActiveButton::DActiveButton () m_X = 0; m_Y = 0; bFlippable = false; + bReturning = false; + m_Frame = 0; } -DActiveButton::DActiveButton (side_t *side, int Where, WORD switchnum, +DActiveButton::DActiveButton (side_t *side, int Where, FSwitchDef *Switch, fixed_t x, fixed_t y, bool useagain) { m_Side = side; @@ -634,42 +299,52 @@ DActiveButton::DActiveButton (side_t *side, int Where, WORD switchnum, m_X = x; m_Y = y; bFlippable = useagain; + bReturning = false; - m_SwitchDef = switchnum; - m_Frame = 65535; + m_SwitchDef = Switch; + m_Frame = -1; AdvanceFrame (); } +//========================================================================== +// +// +// +//========================================================================== + void DActiveButton::Serialize (FArchive &arc) { - SDWORD sidenum; - Super::Serialize (arc); - if (arc.IsStoring ()) - { - sidenum = m_Side ? SDWORD(m_Side - sides) : -1; - } - arc << sidenum << m_Part << m_SwitchDef << m_Frame << m_Timer << bFlippable << m_X << m_Y; - if (arc.IsLoading ()) - { - m_Side = sidenum >= 0 ? sides + sidenum : NULL; - } + arc << m_Side << m_Part << m_SwitchDef << m_Frame << m_Timer << bFlippable << m_X << m_Y << bReturning; } +//========================================================================== +// +// +// +//========================================================================== + void DActiveButton::Tick () { + if (m_SwitchDef == NULL) + { + // We lost our definition due to a bad savegame. + Destroy(); + return; + } + + FSwitchDef *def = bReturning? m_SwitchDef->PairDef : m_SwitchDef; if (--m_Timer == 0) { - FSwitchDef *def = SwitchList[m_SwitchDef]; if (m_Frame == def->NumFrames - 1) { - m_SwitchDef = def->PairIndex; - if (m_SwitchDef != 65535) + bReturning = true; + def = m_SwitchDef->PairDef; + if (def != NULL) { - def = SwitchList[def->PairIndex]; - m_Frame = 65535; + m_Frame = -1; S_Sound (m_X, m_Y, 0, CHAN_VOICE|CHAN_LISTENERZ, - def->Sound != 0 ? def->Sound : FSoundID("switches/normbutn"), + def->Sound != 0 ? FSoundID(def->Sound) : FSoundID("switches/normbutn"), 1, ATTN_STATIC); bFlippable = false; } @@ -681,7 +356,7 @@ void DActiveButton::Tick () } bool killme = AdvanceFrame (); - m_Side->SetTexture(m_Part, def->u[m_Frame].Texture); + m_Side->SetTexture(m_Part, def->frames[m_Frame].Texture); if (killme) { @@ -690,10 +365,16 @@ void DActiveButton::Tick () } } +//========================================================================== +// +// +// +//========================================================================== + bool DActiveButton::AdvanceFrame () { bool ret = false; - FSwitchDef *def = SwitchList[m_SwitchDef]; + FSwitchDef *def = bReturning? m_SwitchDef->PairDef : m_SwitchDef; if (++m_Frame == def->NumFrames - 1) { @@ -708,17 +389,10 @@ bool DActiveButton::AdvanceFrame () } else { - if (def->u[m_Frame].Time & 0xffff0000) + m_Timer = def->frames[m_Frame].TimeMin; + if (def->frames[m_Frame].TimeRnd != 0) { - int t = pr_switchanim(); - - m_Timer = (WORD)((((t | (pr_switchanim() << 8)) - % def->u[m_Frame].Time) >> 16) - + (def->u[m_Frame].Time & 0xffff)); - } - else - { - m_Timer = (WORD)def->u[m_Frame].Time; + m_Timer += pr_switchanim(def->frames[m_Frame].TimeRnd); } } return ret; diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 8fe870e8..6ba60be0 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -228,6 +228,9 @@ static AActor *SelectTeleDest (int tid, int tag) // behavior is used instead (return the first teleport dest found in a tagged // sector). + // Compatibility hack for some maps that fell victim to a bug in the teleport code in 2.0.9x + if (ib_compatflags & BCOMPATF_BADTELEPORTERS) tag = 0; + if (tid != 0) { NActorIterator iterator (NAME_TeleportDest, tid); diff --git a/src/p_terrain.cpp b/src/p_terrain.cpp index 14d2bb3d..c3df86b2 100644 --- a/src/p_terrain.cpp +++ b/src/p_terrain.cpp @@ -242,6 +242,8 @@ void P_InitTerrainTypes () int lump; int size; + Splashes.Clear(); + Terrains.Clear(); size = (TexMan.NumTextures()+1); TerrainTypes.Resize(size); TerrainTypes.Clear(); diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 8ae9403b..72c3cb24 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -390,6 +390,7 @@ class UDMFParser : public UDMFParserBase TArray ParsedSideTextures; TArray ParsedSectors; TArray ParsedVertices; + TArray ParsedVertexDatas; FDynamicColormap *fogMap, *normMap; @@ -1074,6 +1075,8 @@ public: sec->SetYScale(sector_t::floor, FRACUNIT); sec->SetXScale(sector_t::ceiling, FRACUNIT); sec->SetYScale(sector_t::ceiling, FRACUNIT); + sec->SetAlpha(sector_t::floor, FRACUNIT); + sec->SetAlpha(sector_t::ceiling, FRACUNIT); sec->thinglist = NULL; sec->touching_thinglist = NULL; // phares 3/14/98 sec->seqType = (level.flags & LEVEL_SNDSEQTOTALCTRL) ? 0 : -1; @@ -1185,6 +1188,14 @@ public: sec->SetPlaneLight(sector_t::ceiling, CheckInt(key)); continue; + case NAME_Alphafloor: + sec->SetAlpha(sector_t::floor, CheckFixed(key)); + continue; + + case NAME_Alphaceiling: + sec->SetAlpha(sector_t::ceiling, CheckFixed(key)); + continue; + case NAME_Lightfloorabsolute: if (CheckBool(key)) sec->ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING); else sec->ChangeFlags(sector_t::floor, PLANEF_ABSLIGHTING, 0); @@ -1293,9 +1304,10 @@ public: // //=========================================================================== - void ParseVertex(vertex_t *vt) + void ParseVertex(vertex_t *vt, vertexdata_t *vd) { vt->x = vt->y = 0; + vd->zCeiling = vd->zFloor = vd->flags = 0; sc.MustGetStringName("{"); while (!sc.CheckString("}")) { @@ -1310,9 +1322,21 @@ public: case NAME_X: vt->x = FLOAT2FIXED(strtod(value, NULL)); break; + case NAME_Y: vt->y = FLOAT2FIXED(strtod(value, NULL)); break; + + case NAME_ZCeiling: + vd->zCeiling = FLOAT2FIXED(strtod(value, NULL)); + vd->flags |= VERTEXFLAG_ZCeilingEnabled; + break; + + case NAME_ZFloor: + vd->zFloor = FLOAT2FIXED(strtod(value, NULL)); + vd->flags |= VERTEXFLAG_ZFloorEnabled; + break; + default: break; } @@ -1510,8 +1534,10 @@ public: else if (sc.Compare("vertex")) { vertex_t vt; - ParseVertex(&vt); + vertexdata_t vd; + ParseVertex(&vt, &vd); ParsedVertices.Push(vt); + ParsedVertexDatas.Push(vd); } else { @@ -1524,6 +1550,11 @@ public: vertexes = new vertex_t[numvertexes]; memcpy(vertexes, &ParsedVertices[0], numvertexes * sizeof(*vertexes)); + // Create the real vertex datas + numvertexdatas = ParsedVertexDatas.Size(); + vertexdatas = new vertexdata_t[numvertexdatas]; + memcpy(vertexdatas, &ParsedVertexDatas[0], numvertexdatas * sizeof(*vertexdatas)); + // Create the real sectors numsectors = ParsedSectors.Size(); sectors = new sector_t[numsectors]; diff --git a/src/p_user.cpp b/src/p_user.cpp index e844d268..831d65dd 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -133,6 +133,7 @@ void SetupPlayerClasses () { FPlayerClass newclass; + PlayerClasses.Clear(); for (unsigned i=0; ijumpTics) + if (player->jumpTics != 0) { player->jumpTics--; + if (onground && player->jumpTics < -18) + { + player->jumpTics = 0; + } } if (player->morphTics && !(player->cheats & CF_PREDICTING)) { @@ -2217,7 +2218,7 @@ void P_PlayerThink (player_t *player) // [RH] check for jump if (cmd->ucmd.buttons & BT_JUMP) { - if (player->crouchoffset!=0) + if (player->crouchoffset != 0) { // Jumping while crouching will force an un-crouch but not jump player->crouching = 1; @@ -2231,7 +2232,7 @@ void P_PlayerThink (player_t *player) { player->mo->velz = 3*FRACUNIT; } - else if (level.IsJumpingAllowed() && onground && !player->jumpTics) + else if (level.IsJumpingAllowed() && onground && player->jumpTics == 0) { fixed_t jumpvelz = player->mo->JumpZ * 35 / TICRATE; @@ -2241,7 +2242,7 @@ void P_PlayerThink (player_t *player) player->mo->velz += jumpvelz; S_Sound (player->mo, CHAN_BODY, "*jump", 1, ATTN_NORM); player->mo->flags2 &= ~MF2_ONMOBJ; - player->jumpTics = 18*TICRATE/35; + player->jumpTics = -1; } } @@ -2550,33 +2551,9 @@ void player_t::Serialize (FArchive &arc) << poisoncount << poisoner << attacker - << extralight; - if (SaveVersion < 1858) - { - int fixedmap; - arc << fixedmap; - fixedcolormap = NOFIXEDCOLORMAP; - fixedlightlevel = -1; - if (fixedmap >= NUMCOLORMAPS) - { - fixedcolormap = fixedmap - NUMCOLORMAPS; - } - else if (fixedmap > 0) - { - fixedlightlevel = fixedmap; - } - } - else if (SaveVersion < 1893) - { - int ll; - arc << fixedcolormap << ll; - fixedlightlevel = ll; - } - else - { - arc << fixedcolormap << fixedlightlevel; - } - arc << morphTics + << extralight + << fixedcolormap << fixedlightlevel + << morphTics << MorphedPlayerClass << MorphStyle << MorphExitFlash diff --git a/src/r_blend.h b/src/r_blend.h index 132d0950..f9fefc9d 100644 --- a/src/r_blend.h +++ b/src/r_blend.h @@ -48,6 +48,7 @@ enum ERenderStyle STYLE_Add, // Draw additive STYLE_Shaded, // Treat patch data as alpha values for alphacolor STYLE_TranslucentStencil, + STYLE_Shadow, STYLE_Count }; @@ -63,6 +64,9 @@ enum ERenderOp STYLEOP_FuzzOrAdd, // Draw fuzzy or add, based on user preference STYLEOP_FuzzOrSub, // Draw fuzzy or subtract, based on user preference STYLEOP_FuzzOrRevSub, // Draw fuzzy or reverse subtract, based on user preference + + // special styles + STYLEOP_Shadow, }; enum ERenderAlpha diff --git a/src/r_bsp.cpp b/src/r_bsp.cpp index e7ba7c11..e26b92ca 100644 --- a/src/r_bsp.cpp +++ b/src/r_bsp.cpp @@ -1197,6 +1197,7 @@ void R_Subsector (subsector_t *sub) R_FindPlane(frontsector->ceilingplane, // killough 3/8/98 frontsector->GetTexture(sector_t::ceiling), ceilinglightlevel + r_actualextralight, // killough 4/11/98 + frontsector->GetAlpha(sector_t::ceiling), frontsector->GetXOffset(sector_t::ceiling), // killough 3/7/98 frontsector->GetYOffset(sector_t::ceiling), // killough 3/7/98 frontsector->GetXScale(sector_t::ceiling), @@ -1221,6 +1222,7 @@ void R_Subsector (subsector_t *sub) R_FindPlane(frontsector->floorplane, frontsector->GetTexture(sector_t::floor), floorlightlevel + r_actualextralight, // killough 3/16/98 + frontsector->GetAlpha(sector_t::floor), frontsector->GetXOffset(sector_t::floor), // killough 3/7/98 frontsector->GetYOffset(sector_t::floor), // killough 3/7/98 frontsector->GetXScale(sector_t::floor), diff --git a/src/r_data.cpp b/src/r_data.cpp index e0a00d8e..8983d5e5 100644 --- a/src/r_data.cpp +++ b/src/r_data.cpp @@ -127,6 +127,22 @@ void R_SetDefaultColormap (const char *name) } } +//========================================================================== +// +// R_DeinitColormaps +// +//========================================================================== + +void R_DeinitColormaps () +{ + fakecmaps.Clear(); + if (realcolormaps != NULL) + { + delete[] realcolormaps; + realcolormaps = NULL; + } +} + //========================================================================== // // R_InitColormaps @@ -141,6 +157,8 @@ void R_InitColormaps () FakeCmap cm; + R_DeinitColormaps(); + cm.name[0] = 0; cm.blend = 0; fakecmaps.Push(cm); @@ -215,21 +233,6 @@ void R_InitColormaps () numfakecmaps = fakecmaps.Size(); } -//========================================================================== -// -// R_DeinitColormaps -// -//========================================================================== - -void R_DeinitColormaps () -{ - if (realcolormaps != NULL) - { - delete[] realcolormaps; - realcolormaps = NULL; - } -} - //========================================================================== // // [RH] Returns an index into realcolormaps. Multiply it by @@ -286,103 +289,6 @@ void R_InitData () StartScreen->Progress(); } -//=========================================================================== -// -// R_GuesstimateNumTextures -// -// Returns an estimate of the number of textures R_InitData will have to -// process. Used by D_DoomMain() when it calls ST_Init(). -// -//=========================================================================== - -int R_GuesstimateNumTextures () -{ - int numtex = 0; - - for(int i = Wads.GetNumLumps()-1; i>=0; i--) - { - int space = Wads.GetLumpNamespace(i); - switch(space) - { - case ns_flats: - case ns_sprites: - case ns_newtextures: - case ns_hires: - case ns_patches: - case ns_graphics: - numtex++; - break; - - default: - if (Wads.GetLumpFlags(i) & LUMPF_MAYBEFLAT) numtex++; - - break; - } - } - - numtex += R_CountBuildTiles (); - numtex += R_CountTexturesX (); - return numtex; -} - -//=========================================================================== -// -// R_CountTexturesX -// -// See R_InitTextures() for the logic in deciding what lumps to check. -// -//=========================================================================== - -static int R_CountTexturesX () -{ - int count = 0; - int wadcount = Wads.GetNumWads(); - for (int wadnum = 0; wadnum < wadcount; wadnum++) - { - // Use the most recent PNAMES for this WAD. - // Multiple PNAMES in a WAD will be ignored. - int pnames = Wads.CheckNumForName("PNAMES", ns_global, wadnum, false); - - // should never happen except for zdoom.pk3 - if (pnames < 0) continue; - - // Only count the patches if the PNAMES come from the current file - // Otherwise they have already been counted. - if (Wads.GetLumpFile(pnames) == wadnum) - { - count += R_CountLumpTextures (pnames); - } - - int texlump1 = Wads.CheckNumForName ("TEXTURE1", ns_global, wadnum); - int texlump2 = Wads.CheckNumForName ("TEXTURE2", ns_global, wadnum); - - count += R_CountLumpTextures (texlump1) - 1; - count += R_CountLumpTextures (texlump2) - 1; - } - return count; -} - -//=========================================================================== -// -// R_CountLumpTextures -// -// Returns the number of patches in a PNAMES/TEXTURE1/TEXTURE2 lump. -// -//=========================================================================== - -static int R_CountLumpTextures (int lumpnum) -{ - if (lumpnum >= 0) - { - FWadLump file = Wads.OpenLumpNum (lumpnum); - DWORD numtex; - - file >> numtex; - return numtex >= 0 ? numtex : 0; - } - return 0; -} - //=========================================================================== // // R_DeinitData @@ -392,7 +298,6 @@ static int R_CountLumpTextures (int lumpnum) void R_DeinitData () { R_DeinitColormaps (); - R_DeinitBuildTiles(); FCanvasTextureInfo::EmptyList(); // Free openings diff --git a/src/r_defs.h b/src/r_defs.h index 4ce00363..ac52cc36 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -71,6 +71,16 @@ extern size_t MaxDrawSegs; // Note: transformed values not buffered locally, // like some DOOM-alikes ("wt", "WebView") did. // +enum +{ + VERTEXFLAG_ZCeilingEnabled = 0x01, + VERTEXFLAG_ZFloorEnabled = 0x02 +}; +struct vertexdata_t +{ + fixed_t zCeiling, zFloor; + DWORD flags; +}; struct vertex_t { fixed_t x, y; @@ -84,11 +94,27 @@ struct vertex_t sector_t ** sectors; float * heightlist; + vertex_t() + { + x = y = 0; + fx = fy = 0; + viewangle = 0; + dirty = true; + numheights = numsectors = 0; + sectors = NULL; + heightlist = NULL; + } + bool operator== (const vertex_t &other) { return x == other.x && y == other.y; } + bool operator!= (const vertex_t &other) + { + return x != other.x || y != other.y; + } + void clear() { x = y = 0; @@ -320,6 +346,7 @@ struct subsector_t; struct sector_t; struct side_t; extern bool gl_plane_reflection_i; +struct FPortal; // Ceiling/floor flags enum @@ -477,6 +504,7 @@ struct sector_t FTransform xform; int Flags; int Light; + fixed_t alpha; FTextureID Texture; fixed_t TexZ; }; @@ -564,6 +592,16 @@ struct sector_t planes[pos].xform.base_angle = o; } + void SetAlpha(int pos, fixed_t o) + { + planes[pos].alpha = o; + } + + fixed_t GetAlpha(int pos) const + { + return planes[pos].alpha; + } + int GetFlags(int pos) const { return planes[pos].Flags; @@ -733,7 +771,7 @@ struct sector_t extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat. // GL only stuff starts here - float ceiling_reflect, floor_reflect; + float reflect[2]; int dirtyframe[3]; // last frame this sector was marked dirty bool dirty; // marked for recalculation @@ -741,6 +779,7 @@ struct sector_t fixed_t transdoorheight; // for transparent door hacks int subsectorcount; // list of subsectors subsector_t ** subsectors; + FPortal * portals[2]; // floor and ceiling portals enum { @@ -756,8 +795,7 @@ struct sector_t int ibocount; #endif - float GetFloorReflect() { return gl_plane_reflection_i? floor_reflect : 0; } - float GetCeilingReflect() { return gl_plane_reflection_i? ceiling_reflect : 0; } + float GetReflect(int pos) { return gl_plane_reflection_i? reflect[pos] : 0; } bool VBOHeightcheck(int pos) const { return vboheight[pos] == GetPlaneTexZ(pos); } enum @@ -1041,6 +1079,12 @@ enum SSECF_POLYORG = 4, }; +struct FPortalCoverage +{ + DWORD * subsectors; + int sscount; +}; + struct subsector_t { sector_t *sector; @@ -1053,10 +1097,11 @@ struct subsector_t // subsector related GL data FLightNode * lighthead[2]; // Light nodes (blended and additive) - fixed_t bbox[4]; // Bounding box int validcount; + short mapsection; char hacked; // 1: is part of a render hack // 2: has one-sided walls + FPortalCoverage portalcoverage[2]; }; diff --git a/src/r_draw.cpp b/src/r_draw.cpp index a967595c..36c87fa8 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -141,6 +141,7 @@ FRenderStyle LegacyRenderStyles[STYLE_Count] = /* STYLE_Add */ {{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, 0 }}, /* STYLE_Shaded */ {{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_RedIsAlpha | STYLEF_ColorIsFixed }}, /* STYLE_TranslucentStencil */{{ STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_ColorIsFixed }}, + /* STYLE_Shadow */{{ STYLEOP_Shadow, 0, 0, 0 }}, }; #else FRenderStyle LegacyRenderStyles[STYLE_Count]; @@ -157,6 +158,7 @@ static const BYTE Styles[STYLE_Count * 4] = STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_One, 0, STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_RedIsAlpha | STYLEF_ColorIsFixed, STYLEOP_Add, STYLEALPHA_Src, STYLEALPHA_InvSrc, STYLEF_ColorIsFixed, + STYLEOP_Shadow, 0, 0, 0 }; static struct LegacyInit @@ -2159,7 +2161,7 @@ void R_InitColumnDrawers () } // [RH] Choose column drawers in a single place -EXTERN_CVAR (Bool, r_drawfuzz) +EXTERN_CVAR (Int, r_drawfuzz) EXTERN_CVAR (Float, transsouls) CVAR (Bool, r_drawtrans, true, 0) @@ -2326,6 +2328,13 @@ ESPSResult R_SetPatchStyle (FRenderStyle style, fixed_t alpha, int translation, style.CheckFuzz(); + if (style.BlendOp == STYLEOP_Shadow) + { + style = LegacyRenderStyles[STYLE_TranslucentStencil]; + alpha = FRACUNIT*3/10; + color = 0; + } + if (style.Flags & STYLEF_TransSoulsAlpha) { alpha = fixed_t(transsouls * FRACUNIT); @@ -2481,16 +2490,42 @@ bool FRenderStyle::IsVisible(fixed_t alpha) const throw() void FRenderStyle::CheckFuzz() { - if (BlendOp == STYLEOP_FuzzOrAdd) + switch (BlendOp) { - BlendOp = (r_drawfuzz || !r_drawtrans) ? STYLEOP_Fuzz : STYLEOP_Add; + default: + return; + + case STYLEOP_FuzzOrAdd: + if (r_drawtrans && r_drawfuzz == 0) + { + BlendOp = STYLEOP_Add; + return; + } + break; + + case STYLEOP_FuzzOrSub: + if (r_drawtrans && r_drawfuzz == 0) + { + BlendOp = STYLEOP_Sub; + return; + } + break; + + case STYLEOP_FuzzOrRevSub: + if (r_drawtrans && r_drawfuzz == 0) + { + BlendOp = STYLEOP_RevSub; + return; + } + break; } - else if (BlendOp == STYLEOP_FuzzOrSub) + + if (r_drawfuzz == 2) { - BlendOp = (r_drawfuzz || !r_drawtrans) ? STYLEOP_Fuzz : STYLEOP_Sub; + BlendOp = STYLEOP_Shadow; } - else if (BlendOp == STYLEOP_FuzzOrRevSub) + else { - BlendOp = (r_drawfuzz || !r_drawtrans) ? STYLEOP_Fuzz : STYLEOP_RevSub; + BlendOp = STYLEOP_Fuzz; } } diff --git a/src/r_interpolate.cpp b/src/r_interpolate.cpp index f2fba2f8..f145347a 100644 --- a/src/r_interpolate.cpp +++ b/src/r_interpolate.cpp @@ -826,16 +826,7 @@ void DPolyobjInterpolation::Serialize(FArchive &arc) arc << po << oldverts; poly = polyobjs + po; - if (SaveVersion >= 2448) - { - arc << oldcx << oldcy; - } - else - { - // This will glitch if an old savegame is loaded but at least it'll allow loading it. - oldcx = poly->CenterSpot.x; - oldcy = poly->CenterSpot.y; - } + arc << oldcx << oldcy; if (arc.IsLoading()) bakverts.Resize(oldverts.Size()); } diff --git a/src/r_local.h b/src/r_local.h index b4508a22..c666b1de 100644 --- a/src/r_local.h +++ b/src/r_local.h @@ -39,12 +39,6 @@ #include "r_things.h" #include "r_draw.h" -// r_anim.cpp - -void R_InitPicAnims (); -void R_AddSimpleAnim (FTextureID picnum, int animcount, int animtype, DWORD animspeed /* in ms */, DWORD speedrange=0); -void R_UpdateAnimations (DWORD mstime); - bool R_AlignFlat (int linenum, int side, int fc); #endif // __R_LOCAL_H__ diff --git a/src/r_main.cpp b/src/r_main.cpp index 823bda05..46d9b6b3 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1094,7 +1094,6 @@ void R_SetupFrame (AActor *actor) iview->otic = nowtic; } - R_UpdateAnimations (I_FPSTime()); r_TicFrac = I_GetTimeFrac (&r_FrameTime); if (cl_capfps || r_NoInterpolate) { diff --git a/src/r_main.h b/src/r_main.h index 1706ef93..d91450a3 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -190,7 +190,6 @@ void R_RenderViewToCanvas (AActor *actor, DCanvas *canvas, int x, int y, int wid void R_ResetViewInterpolation (); // Called by startup code. -int R_GuesstimateNumTextures (); void R_Init (void); void R_ExecuteSetViewSize (void); diff --git a/src/r_plane.cpp b/src/r_plane.cpp index cd0b9f4a..99872001 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -75,7 +75,7 @@ planefunction_t ceilingfunc; #define MAXVISPLANES 128 /* must be a power of 2 */ // Avoid infinite recursion with stacked sectors by limiting them. -#define MAX_SKYBOX_PLANES 100 +#define MAX_SKYBOX_PLANES 1000 // [RH] Allocate one extra for sky box planes. static visplane_t *visplanes[MAXVISPLANES+1]; // killough @@ -522,7 +522,7 @@ static visplane_t *new_visplane (unsigned hash) // killough 2/28/98: Add offsets //========================================================================== -visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightlevel, +visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightlevel, fixed_t alpha, fixed_t xoffs, fixed_t yoffs, fixed_t xscale, fixed_t yscale, angle_t angle, int sky, ASkyViewpoint *skybox) @@ -540,6 +540,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl xscale = 0; yscale = 0; angle = 0; + alpha = 0; plane.a = plane.b = plane.d = 0; // [RH] Map floor skies and ceiling skies to separate visplanes. This isn't // always necessary, but it is needed if a floor and ceiling sky are in the @@ -560,6 +561,8 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl plane = height; isskybox = false; sky = 0; // not skyflatnum so it can't be a sky + skybox = NULL; + alpha = FRACUNIT; } // New visplane algorithm uses hash table -- killough @@ -579,7 +582,27 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl check->viewx == stacked_viewx && check->viewy == stacked_viewy && check->viewz == stacked_viewz && - check->viewangle == stacked_angle) + ( + // headache inducing logic... :( + (!(skybox->flags & MF_JUSTATTACKED)) || + ( + check->alpha == alpha && + (alpha == 0 || // if alpha is > 0 everything needs to be checked + (plane == check->height && + picnum == check->picnum && + lightlevel == check->lightlevel && + xoffs == check->xoffs && // killough 2/28/98: Add offset checks + yoffs == check->yoffs && + basecolormap == check->colormap && // [RH] Add more checks + xscale == check->xscale && + yscale == check->yscale && + angle == check->angle + ) + ) && + check->viewangle == stacked_angle + ) + ) + ) { return check; } @@ -628,6 +651,7 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl check->viewy = stacked_viewy; check->viewz = stacked_viewz; check->viewangle = stacked_angle; + check->alpha = alpha; clearbufshort (check->top, viewwidth, 0x7fff); @@ -712,6 +736,7 @@ visplane_t *R_CheckPlane (visplane_t *pl, int start, int stop) new_pl->viewz = pl->viewz; new_pl->viewangle = pl->viewangle; new_pl->sky = pl->sky; + new_pl->alpha = pl->alpha; pl = new_pl; pl->minx = start; pl->maxx = stop; @@ -1034,26 +1059,19 @@ void R_DrawSinglePlane (visplane_t *pl, fixed_t alpha, bool masked) CVAR (Bool, r_skyboxes, true, 0) static int numskyboxes; -struct VisplaneAndAlpha -{ - visplane_t *Visplane; - fixed_t Alpha; -}; - void R_DrawSkyBoxes () { static TArray interestingStack; static TArray drawsegStack; static TArray visspriteStack; static TArray viewxStack, viewyStack, viewzStack; - static TArray visplaneStack; + static TArray visplaneStack; numskyboxes = 0; if (visplanes[MAXVISPLANES] == NULL) return; - VisplaneAndAlpha vaAdder = { 0 }; int savedextralight = extralight; fixed_t savedx = viewx; fixed_t savedy = viewy; @@ -1169,9 +1187,7 @@ void R_DrawSkyBoxes () viewxStack.Push (viewx); viewyStack.Push (viewy); viewzStack.Push (viewz); - vaAdder.Visplane = pl; - vaAdder.Alpha = sky->PlaneAlpha; - visplaneStack.Push (vaAdder); + visplaneStack.Push (pl); R_RenderBSPNode (nodes + numnodes - 1); R_DrawPlanes (); @@ -1200,13 +1216,13 @@ void R_DrawSkyBoxes () ds_p = firstdrawseg; vissprite_p = firstvissprite; - visplaneStack.Pop (vaAdder); - if (vaAdder.Alpha > 0) + visplaneStack.Pop (pl); + if (pl->alpha > 0) { - R_DrawSinglePlane (vaAdder.Visplane, vaAdder.Alpha, true); + R_DrawSinglePlane (pl, pl->alpha, true); } - *freehead = vaAdder.Visplane; - freehead = &vaAdder.Visplane->next; + *freehead = pl; + freehead = &pl->next; } firstvissprite = vissprites; vissprite_p = vissprites + savedvissprite_p; diff --git a/src/r_plane.h b/src/r_plane.h index 369083ba..2df6b1fd 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -54,6 +54,7 @@ struct visplane_s float visibility; fixed_t viewx, viewy, viewz; angle_t viewangle; + fixed_t alpha; unsigned short *bottom; // [RH] bottom and top arrays are dynamically unsigned short pad; // allocated immediately after the @@ -92,6 +93,7 @@ visplane_t *R_FindPlane ( const secplane_t &height, FTextureID picnum, int lightlevel, + fixed_t alpha, fixed_t xoffs, // killough 2/28/98: add x-y offsets fixed_t yoffs, fixed_t xscale, diff --git a/src/r_segs.cpp b/src/r_segs.cpp index eed5d78a..55f80649 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -1295,6 +1295,7 @@ void R_NewWall (bool needlights) // killough 3/7/98: Add checks for (x,y) offsets || backsector->GetXOffset(sector_t::floor) != frontsector->GetXOffset(sector_t::floor) || backsector->GetYOffset(sector_t::floor) != frontsector->GetYOffset(sector_t::floor) + || backsector->GetAlpha(sector_t::floor) != frontsector->GetAlpha(sector_t::floor) // killough 4/15/98: prevent 2s normals // from bleeding through deep water @@ -1326,6 +1327,7 @@ void R_NewWall (bool needlights) // killough 3/7/98: Add checks for (x,y) offsets || backsector->GetXOffset(sector_t::ceiling) != frontsector->GetXOffset(sector_t::ceiling) || backsector->GetYOffset(sector_t::ceiling) != frontsector->GetYOffset(sector_t::ceiling) + || backsector->GetAlpha(sector_t::ceiling) != frontsector->GetAlpha(sector_t::ceiling) // killough 4/15/98: prevent 2s normals // from bleeding through fake ceilings diff --git a/src/r_sky.cpp b/src/r_sky.cpp index 544c1ded..e9c319de 100644 --- a/src/r_sky.cpp +++ b/src/r_sky.cpp @@ -137,3 +137,20 @@ void R_InitSkyMap () sky2cyl = MAX(skytex2->GetWidth(), skytex2->xScale >> (16 - 10)); } + +//========================================================================== +// +// R_UpdateSky +// +// Performs sky scrolling +// +//========================================================================== + +void R_UpdateSky (DWORD mstime) +{ + // Scroll the sky + double ms = (double)mstime * FRACUNIT; + sky1pos = ms * level.skyspeed1; + sky2pos = ms * level.skyspeed2; +} + diff --git a/src/r_sky.h b/src/r_sky.h index 3e836ec3..f285c426 100644 --- a/src/r_sky.h +++ b/src/r_sky.h @@ -38,5 +38,6 @@ extern bool skystretch; // Called whenever the sky changes. void R_InitSkyMap (); +void R_UpdateSky (DWORD mstime); #endif //__R_SKY_H__ diff --git a/src/r_state.h b/src/r_state.h index 9044da72..65296838 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -55,6 +55,8 @@ extern DWORD NumStdSprites; extern int numvertexes; extern vertex_t* vertexes; +extern int numvertexdatas; +extern vertexdata_t* vertexdatas; extern int numsegs; extern seg_t* segs; diff --git a/src/r_things.cpp b/src/r_things.cpp index 1bc81ce4..ad2b6e83 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -66,7 +66,7 @@ extern fixed_t globaluclip, globaldclip; #define BASEYCENTER (100) EXTERN_CVAR (Bool, st_scale) -CVAR (Bool, r_drawfuzz, true, CVAR_ARCHIVE) +CVAR (Int, r_drawfuzz, 1, CVAR_ARCHIVE) // @@ -1290,7 +1290,10 @@ void R_InitSprites () numskins++; } + SpriteFrames.Clear(); + // [RH] Do some preliminary setup + if (skins != NULL) delete [] skins; skins = new FPlayerSkin[numskins]; memset (skins, 0, sizeof(*skins) * numskins); for (i = 0; i < numskins; i++) @@ -2818,8 +2821,8 @@ void R_DrawSprite (vissprite_t *spr) } if (neardepth > spr->depth || (fardepth > spr->depth && // Check if sprite is in front of draw seg: - DMulScale24 (spr->depth - ds->cy, ds->cdx, ds->cdy, ds->cx - spr->cx) < 0)) - + DMulScale32(spr->gy - ds->curline->v1->y, ds->curline->v2->x - ds->curline->v1->x, + ds->curline->v1->x - spr->gx, ds->curline->v2->y - ds->curline->v1->y) <= 0)) { // seg is behind sprite, so draw the mid texture if it has one if (ds->maskedtexturecol != -1 || ds->bFogBoundary) @@ -2968,6 +2971,7 @@ void R_InitParticles () if ( NumParticles < 100 ) NumParticles = 100; + R_DeinitParticles(); Particles = new particle_t[NumParticles]; R_ClearParticles (); atterm (R_DeinitParticles); diff --git a/src/r_translate.cpp b/src/r_translate.cpp index eef8c1c1..d7e42384 100644 --- a/src/r_translate.cpp +++ b/src/r_translate.cpp @@ -869,7 +869,9 @@ void R_DeinitTranslationTables() translationtables[i][j] = NULL; } } + translationtables[i].Clear(); } + BloodTranslationColors.Clear(); } //---------------------------------------------------------------------------- diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 240498f0..3245c20f 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -149,6 +149,7 @@ enum SICommands SI_IfStrife, SI_Rolloff, SI_Volume, + SI_MusicAlias, }; // Blood was a cool game. If Monolith ever releases the source for it, @@ -183,6 +184,7 @@ struct FSavedPlayerSoundInfo }; // This specifies whether Timidity or Windows playback is preferred for a certain song (only useful for Windows.) +MusicAliasMap MusicAliases; MidiDeviceMap MidiDevices; // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- @@ -241,6 +243,7 @@ static const char *SICommandStrings[] = "$ifstrife", "$rolloff", "$volume", + "$musicalias", NULL }; @@ -254,6 +257,7 @@ static bool PlayerClassesIsSorted; static TArray PlayerClassLookups; static TArray PlayerSounds; + static FString DefPlayerClassName; static int DefPlayerClass; @@ -853,6 +857,8 @@ static void S_ClearSoundData() PlayerSounds.Clear(); DefPlayerClass = 0; DefPlayerClassName = ""; + MusicAliases.Clear(); + MidiDevices.Clear(); } //========================================================================== @@ -863,10 +869,11 @@ static void S_ClearSoundData() // Also registers Blood SFX files and Strife's voices. //========================================================================== -void S_ParseSndInfo () +void S_ParseSndInfo (bool redefine) { int lump; + if (!redefine) SavedPlayerSounds.Clear(); // clear skin sounds only for initial parsing. atterm (S_ClearSoundData); S_ClearSoundData(); // remove old sound data first! @@ -1285,6 +1292,32 @@ static void S_AddSNDINFO (int lump) } break; + case SI_MusicAlias: { + sc.MustGetString(); + int lump = Wads.CheckNumForName(sc.String, ns_music); + if (lump >= 0) + { + // do not set the alias if a later WAD defines its own music of this name + int file = Wads.GetLumpFile(lump); + int sndifile = Wads.GetLumpFile(sc.LumpNum); + if (file > sndifile) + { + sc.MustGetString(); + continue; + } + } + FName alias = sc.String; + sc.MustGetString(); + FName mapped = sc.String; + + // only set the alias if the lump it maps to exists. + if (mapped == NAME_None || Wads.CheckNumForName(sc.String, ns_music) >= 0) + { + MusicAliases[alias] = mapped; + } + } + break; + case SI_MidiDevice: { sc.MustGetString(); FName nm = sc.String; @@ -1986,10 +2019,6 @@ void AAmbientSound::Serialize (FArchive &arc) { Super::Serialize (arc); arc << bActive << NextCheck; - if (SaveVersion < 2798) - { - NextCheck += level.maptime; - } } //========================================================================== diff --git a/src/s_environment.cpp b/src/s_environment.cpp index d59d1c04..001b3d4e 100644 --- a/src/s_environment.cpp +++ b/src/s_environment.cpp @@ -587,6 +587,7 @@ void S_ParseReverbDef () int lump, lastlump = 0; atterm (S_UnloadReverbDef); + S_UnloadReverbDef (); while ((lump = Wads.FindLump ("REVERBS", &lastlump)) != -1) { @@ -597,15 +598,21 @@ void S_ParseReverbDef () void S_UnloadReverbDef () { ReverbContainer *probe = Environments; + ReverbContainer **pNext = NULL; while (probe != NULL) { ReverbContainer *next = probe->Next; if (!probe->Builtin) { + if (pNext != NULL) *pNext = probe->Next; delete[] const_cast(probe->Name); delete probe; } + else + { + pNext = &probe->Next; + } probe = next; } Environments = &Off; diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 19076055..da02bcab 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -502,6 +502,24 @@ static void AssignHexenTranslations (void) } } +//========================================================================== +// +// S_ClearSndSeq +// +//========================================================================== + +void S_ClearSndSeq() +{ + for (unsigned int i = 0; i < Sequences.Size(); i++) + { + if (Sequences[i]) + { + M_Free(Sequences[i]); + } + } + Sequences.Clear(); +} + //========================================================================== // // S_ParseSndSeq @@ -523,14 +541,7 @@ void S_ParseSndSeq (int levellump) // First free the old SNDSEQ data. This allows us to reload this for each level // and specify a level specific SNDSEQ lump! - for (unsigned int i = 0; i < Sequences.Size(); i++) - { - if (Sequences[i]) - { - M_Free(Sequences[i]); - } - } - Sequences.Clear(); + S_ClearSndSeq(); // be gone, compiler warnings stopsound = 0; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 95130d30..4c405389 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -292,6 +292,7 @@ void S_Init () if (S_SoundCurve != NULL) { delete[] S_SoundCurve; + S_SoundCurve = NULL; } // Heretic and Hexen have sound curve lookup tables. Doom does not. @@ -322,7 +323,7 @@ void S_Init () void S_InitData () { LastLocalSndInfo = LastLocalSndSeq = ""; - S_ParseSndInfo (); + S_ParseSndInfo (false); S_ParseSndSeq (-1); S_ParseMusInfo(); } @@ -408,7 +409,7 @@ void S_Start () } // Parse the global SNDINFO - S_ParseSndInfo(); + S_ParseSndInfo(true); if (*LocalSndInfo) { @@ -2386,8 +2387,16 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) int offset = 0, length = 0; int device = MDEV_DEFAULT; MusInfo *handle = NULL; + FName musicasname = musicname; - int *devp = MidiDevices.CheckKey(FName(musicname)); + FName *aliasp = MusicAliases.CheckKey(musicasname); + if (aliasp != NULL) + { + musicname = (musicasname = *aliasp).GetChars(); + if (musicasname == NAME_None) return true; + } + + int *devp = MidiDevices.CheckKey(musicasname); if (devp != NULL) device = *devp; // Strip off any leading file:// component. diff --git a/src/s_sound.h b/src/s_sound.h index 5c2796d5..12e7ee3c 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -331,7 +331,7 @@ void S_UpdateSounds (AActor *listener); void S_RestoreEvictedChannels(); // [RH] S_sfx "maintenance" routines -void S_ParseSndInfo (); +void S_ParseSndInfo (bool redefine); void S_ParseReverbDef (); void S_UnloadReverbDef (); @@ -382,8 +382,10 @@ enum EMidiDevice MDEV_GUS = 5, }; +typedef TMap MusicAliasMap; typedef TMap MidiDeviceMap; +extern MusicAliasMap MusicAliases; extern MidiDeviceMap MidiDevices; #endif diff --git a/src/sdl/crashcatcher.c b/src/sdl/crashcatcher.c index 7dc92840..53f3c6a6 100644 --- a/src/sdl/crashcatcher.c +++ b/src/sdl/crashcatcher.c @@ -97,8 +97,7 @@ static void gdb_info(pid_t pid) strcpy(respfile, "gdb-respfile-XXXXXX"); if((fd = mkstemp(respfile)) >= 0 && (f = fdopen(fd, "w"))) { - fprintf(f, "signal SIGCHLD\n" - "shell echo \"\"\n" + fprintf(f, "shell echo \"\"\n" "shell echo \"* Loaded Libraries\"\n" "info sharedlibrary\n" "shell echo \"\"\n" @@ -115,36 +114,8 @@ static void gdb_info(pid_t pid) "x/x $eip-3\nx/x $eip\n" "shell echo \"\"\n" "shell echo \"* Backtrace\"\n" - "backtrace full\n" -#if 0 /* This sorta works to print out the core, but is too slow and skips 0's.. */ - "shell echo \"\"\n" - "shell echo \"* Stack\"\n" - "set var $_sp = $esp\n" - "while $_sp <= $ebp - 12\n" - " printf \"%%08x: \", $_sp\n" - " set var $_i = $_sp\n" - " while $_i < $_sp + 16\n" - " printf \"%%08x \", {int} $_i\n" - " set $_i += 4\n" - " end\n" - " set var $_i = $_sp\n" - " while $_i < $_sp + 16\n" - " printf \"%%c\", {int} $_i\n" - " set ++$_i\n" - " end\n" - " set var $_sp += 16\n" - " printf \"\\n\"\n" - "end\n" - "if $_sp <= $ebp\n" - " printf \"%%08x: \", $esp\n" - " while $_sp <= $ebp\n" - " printf \"%%08x \", {int} $_i\n" - " set $_sp += 4\n" - " end\n" - " printf \"\\n\"\n" - "end\n" -#endif - "kill\n" + "thread apply all backtrace full\n" + "detach\n" "quit\n"); fclose(f); @@ -152,8 +123,8 @@ static void gdb_info(pid_t pid) snprintf(buf, sizeof(buf), "gdb --quiet --batch --command=%s --pid=%i", respfile, pid); printf("Executing: %s\n", buf); fflush(stdout); - system(buf); + system(buf); /* Clean up */ remove(respfile); } @@ -168,6 +139,7 @@ static void gdb_info(pid_t pid) printf("Could not create gdb command file\n"); } fflush(stdout); + kill(pid, SIGKILL); } @@ -267,8 +239,8 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context) /* Make sure the effective uid is the real uid */ if (getuid() != geteuid()) { - fprintf(stderr, "%s (signal %i)\ngetuid() does not match geteuid().\n", sigdesc, signum); - _exit(-1); + raise(signum); + return; } #endif @@ -325,48 +297,18 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context) } gdb_info(pid); -#if 0 /* Why won't this work? */ - if(ucontext) - { - unsigned char *ptr = ucontext->uc_stack.ss_sp; - size_t len; - - fprintf(f, "\n* Stack\n"); - for(len = ucontext->uc_stack.ss_size/4;len > 0; len -= 4) - { - fprintf(f, "0x%08x:", (int)ptr); - for(i = 0;i < ((len < 4) ? len : 4);++i) - { - fprintf(f, " %02x%02x%02x%02x", ptr[i*4 + 0], ptr[i*4 + 1], - ptr[i*4 + 2], ptr[i*4 + 3]); - } - fputc(' ', f); - fflush(f); - for(i = 0;i < ((len < 4) ? len : 4);++i) - { - fprintf(f, "%c", *(ptr++)); - fprintf(f, "%c", *(ptr++)); - fprintf(f, "%c", *(ptr++)); - fprintf(f, "%c", *(ptr++)); - } - fputc('\n', f); - fflush(f); - } - } -#endif - if(f != stderr) { fclose(f); #if (defined __unix__) if(cc_logfile) { - char buf[256]; + char buf[512]; snprintf(buf, sizeof(buf), - "if (which gxmessage > /dev/null 2>&1);" - "then gxmessage -buttons \"Damn it:0\" -center -title \"Very Fatal Error\" -file %s;" - "elif (which xmessage > /dev/null 2>&1);" - "then xmessage -buttons \"Damn it:0\" -center -file %s -geometry 600x400;" + "if (which gxmessage > /dev/null 2>&1) ; then\n" + " gxmessage -buttons \"Damn it:0\" -center -title \"Very Fatal Error\" -file %s\n" + "elif (which xmessage > /dev/null 2>&1) ; then\n" + " xmessage -buttons \"Damn it:0\" -center -file %s -geometry 600x400\n" "fi", cc_logfile, cc_logfile); system(buf); } @@ -376,8 +318,8 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context) _exit(0); default: - /* Wait and let the child attach gdb */ - waitpid(dbg_pid, NULL, 0); + /* Wait indefinitely; we'll be killed when gdb is done */ + while(1) usleep(1000000); } } @@ -388,12 +330,13 @@ int cc_install_handlers(int num_signals, int *signals, const char *logfile, int memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = crash_catcher; - -#if !defined(__FreeBSD__) && !defined(__APPLE__) + +#ifdef SA_ONESHOT sa.sa_flags = SA_ONESHOT | SA_NODEFER | SA_SIGINFO; #else sa.sa_flags = SA_NODEFER | SA_SIGINFO; #endif + sigemptyset(&sa.sa_mask); cc_logfile = logfile; cc_user_info = user_info; diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 1a681fd6..6fc29665 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -511,7 +511,7 @@ int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad) gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, filepart, - 1, wads[i].Name, + 1, wads[i].Name.GetChars(), 2, i, -1); if (i == defaultiwad) @@ -625,7 +625,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) filepart = wads[i].Path; else filepart++; - printf ("%d. %s (%s)\n", i+1, wads[i].Name, filepart); + printf ("%d. %s (%s)\n", i+1, wads[i].Name.GetChars(), filepart); } printf ("Which one? "); scanf ("%d", &i); diff --git a/src/sdl/iwadpicker_cocoa.mm b/src/sdl/iwadpicker_cocoa.mm index a835c6df..1a1fa8b8 100644 --- a/src/sdl/iwadpicker_cocoa.mm +++ b/src/sdl/iwadpicker_cocoa.mm @@ -48,7 +48,7 @@ enum static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; // Class to convert the IWAD data into a form that Cocoa can use. -@interface IWADTableData : NSObject +@interface IWADTableData : NSObject// { NSMutableArray *data; } @@ -81,8 +81,8 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; filename = wads[i].Path; else filename++; - [record setObject:[NSString stringWithCString:filename] forKey:[NSString stringWithCString:tableHeaders[COLUMN_IWAD]]]; - [record setObject:[NSString stringWithCString:IWADInfos[wads[i].Type].Name] forKey:[NSString stringWithCString:tableHeaders[COLUMN_GAME]]]; + [record setObject:[NSString stringWithUTF8String:filename] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_IWAD]]]; + [record setObject:[NSString stringWithUTF8String:wads[i].Name] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_GAME]]]; [data addObject:record]; [record release]; } @@ -144,7 +144,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; // little more automated. - (void)makeLabel:(NSTextField *)label:(const char*) str { - [label setStringValue:[NSString stringWithCString:str]]; + [label setStringValue:[NSString stringWithUTF8String:str]]; [label setBezeled:NO]; [label setDrawsBackground:NO]; [label setEditable:NO]; @@ -156,7 +156,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; cancelled = false; app = [NSApplication sharedApplication]; - id windowTitle = [NSString stringWithCString:GAMESIG " " DOTVERSIONSTR ": Select an IWAD to use"]; + id windowTitle = [NSString stringWithUTF8String:GAMESIG " " DOTVERSIONSTR ": Select an IWAD to use"]; NSRect frame = NSMakeRect(0, 0, 440, 450); window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]; @@ -174,7 +174,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; IWADTableData *tableData = [[IWADTableData alloc] init:wads:numwads]; for(int i = 0;i < NUM_COLUMNS;i++) { - NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:[NSString stringWithCString:tableHeaders[i]]]; + NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:[NSString stringWithUTF8String:tableHeaders[i]]]; [[column headerCell] setStringValue:[column identifier]]; if(i == 0) [column setMaxWidth:110]; @@ -211,7 +211,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [[window contentView] addSubview:dontAsk];*/ okButton = [[NSButton alloc] initWithFrame:NSMakeRect(236, 12, 96, 32)]; - [okButton setTitle:[NSString stringWithCString:"OK"]]; + [okButton setTitle:[NSString stringWithUTF8String:"OK"]]; [okButton setBezelStyle:NSRoundedBezelStyle]; [okButton setAction:@selector(buttonPressed:)]; [okButton setTarget:self]; @@ -219,7 +219,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; [[window contentView] addSubview:okButton]; cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(332, 12, 96, 32)]; - [cancelButton setTitle:[NSString stringWithCString:"Cancel"]]; + [cancelButton setTitle:[NSString stringWithUTF8String:"Cancel"]]; [cancelButton setBezelStyle:NSRoundedBezelStyle]; [cancelButton setAction:@selector(buttonPressed:)]; [cancelButton setTarget:self]; diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index ba98b470..0eedfbdc 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -477,8 +477,6 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); if (miditype != MIDI_NOTMIDI) { - TArray midi; - EMidiDevice devtype = (EMidiDevice)device; retry_as_fmod: diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 29b655d1..4ce8a7b0 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -202,7 +202,6 @@ protected: #ifdef _WIN32 HANDLE ReadWavePipe; HANDLE WriteWavePipe; - HANDLE KillerEvent; HANDLE ChildProcess; bool Validated; bool ValidateTimidity(); diff --git a/src/sound/music_gme.cpp b/src/sound/music_gme.cpp index 08700c8b..0c3d8c8c 100644 --- a/src/sound/music_gme.cpp +++ b/src/sound/music_gme.cpp @@ -349,6 +349,7 @@ bool GMESong::Read(SoundStream *stream, void *buff, int len, void *userdata) else { memset(buff, 0, len); + song->CritSec.Leave(); return false; } } diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index dcaa934b..bb897bef 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -20,8 +20,10 @@ void ChildSigHandler (int signum) #endif #ifdef _WIN32 -const char TimidityPPMIDIDevice::EventName[] = "TiMidity Killer"; +BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode); + static char TimidityTitle[] = "TiMidity (ZDoom Launched)"; +const char TimidityPPMIDIDevice::EventName[] = "TiMidity Killer"; CVAR (String, timidity_exe, "timidity.exe", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) #else @@ -71,7 +73,6 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice() : DiskName("zmid"), #ifdef _WIN32 ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE), - KillerEvent(INVALID_HANDLE_VALUE), ChildProcess(INVALID_HANDLE_VALUE), Validated(false) #else @@ -108,11 +109,6 @@ TimidityPPMIDIDevice::~TimidityPPMIDIDevice () CloseHandle (ReadWavePipe); ReadWavePipe = INVALID_HANDLE_VALUE; } - if (KillerEvent != INVALID_HANDLE_VALUE) - { - CloseHandle (KillerEvent); - KillerEvent = INVALID_HANDLE_VALUE; - } #else if (WavePipe[1] != -1) { @@ -186,12 +182,6 @@ int TimidityPPMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO } Validated = true; - KillerEvent = CreateEvent(NULL, FALSE, FALSE, EventName); - if (KillerEvent == INVALID_HANDLE_VALUE) - { - Printf(PRINT_BOLD, "Could not create TiMidity++ kill event.\n"); - return 102; - } #endif // WIN32 CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ", @@ -398,11 +388,11 @@ bool TimidityPPMIDIDevice::LaunchTimidity () startup.wShowWindow = SW_SHOWMINNOACTIVE; if (CreateProcess(NULL, CommandLine.LockBuffer(), NULL, NULL, TRUE, - /*HIGH_PRIORITY_CLASS|*/DETACHED_PROCESS, NULL, NULL, &startup, &procInfo)) + DETACHED_PROCESS, NULL, NULL, &startup, &procInfo)) { ChildProcess = procInfo.hProcess; //SetThreadPriority (procInfo.hThread, THREAD_PRIORITY_HIGHEST); - CloseHandle (procInfo.hThread); // Don't care about the created thread + CloseHandle(procInfo.hThread); // Don't care about the created thread CommandLine.UnlockBuffer(); return true; } @@ -647,10 +637,8 @@ void TimidityPPMIDIDevice::Stop () #ifdef _WIN32 if (ChildProcess != INVALID_HANDLE_VALUE) { - SetEvent(KillerEvent); - if (WaitForSingleObject(ChildProcess, 500) != WAIT_OBJECT_0) + if (!SafeTerminateProcess(ChildProcess, 666) && GetLastError() != ERROR_PROCESS_ABORTED) { - ResetEvent(KillerEvent); TerminateProcess(ChildProcess, 666); } CloseHandle(ChildProcess); @@ -670,3 +658,68 @@ void TimidityPPMIDIDevice::Stop () } Started = false; } + +#ifdef _WIN32 +/* + Safely terminate a process by creating a remote thread + in the process that calls ExitProcess + + Source is a Dr Dobbs article circa 1999. +*/ +typedef HANDLE (WINAPI *CreateRemoteThreadProto)(HANDLE,LPSECURITY_ATTRIBUTES,SIZE_T,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPDWORD); + +BOOL SafeTerminateProcess(HANDLE hProcess, UINT uExitCode) +{ + DWORD dwTID, dwCode; + HRESULT dwErr = 0; + HANDLE hRT = NULL; + HINSTANCE hKernel = GetModuleHandle("Kernel32"); + BOOL bSuccess = FALSE; + + // Detect the special case where the process is already dead... + if ( GetExitCodeProcess(hProcess, &dwCode) && (dwCode == STILL_ACTIVE) ) + { + FARPROC pfnExitProc; + CreateRemoteThreadProto pfCreateRemoteThread; + + pfnExitProc = GetProcAddress(hKernel, "ExitProcess"); + + // CreateRemoteThread does not exist on 9x systems. + pfCreateRemoteThread = (CreateRemoteThreadProto)GetProcAddress(hKernel, "CreateRemoteThread"); + + if (pfCreateRemoteThread == NULL) + { + dwErr = ERROR_INVALID_FUNCTION; + } + else + { + hRT = pfCreateRemoteThread(hProcess, + NULL, + 0, + (LPTHREAD_START_ROUTINE)pfnExitProc, + (PVOID)(UINT_PTR)uExitCode, 0, &dwTID); + + if ( hRT == NULL ) + dwErr = GetLastError(); + } + } + else + { + dwErr = ERROR_PROCESS_ABORTED; + } + + if ( hRT ) + { + // Must wait process to terminate to guarantee that it has exited... + WaitForSingleObject(hProcess, INFINITE); + + CloseHandle(hRT); + bSuccess = TRUE; + } + + if ( !bSuccess ) + SetLastError(dwErr); + + return bSuccess; +} +#endif diff --git a/src/st_start.h b/src/st_start.h index 3b90aa06..4ba475e7 100644 --- a/src/st_start.h +++ b/src/st_start.h @@ -42,15 +42,15 @@ public: FStartupScreen(int max_progress); virtual ~FStartupScreen(); - virtual void Progress() = 0; + virtual void Progress(); virtual void LoadingStatus(const char *message, int colors); // Used by Heretic only virtual void AppendStatusLine(const char *status); // Used by Heretic only - virtual void NetInit(const char *message, int num_players) = 0; - virtual void NetProgress(int count) = 0; - virtual void NetMessage(const char *format, ...) = 0; // cover for printf - virtual void NetDone() = 0; - virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata) = 0; + virtual void NetInit(const char *message, int num_players); + virtual void NetProgress(int count); + virtual void NetMessage(const char *format, ...); // cover for printf + virtual void NetDone(); + virtual bool NetLoop(bool (*timer_callback)(void *), void *userdata); protected: int MaxPos, CurPos, NotchPos; }; diff --git a/src/statistics.cpp b/src/statistics.cpp index 276090eb..fe72f766 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -130,6 +130,7 @@ extern TArray wadlevelinfos; static void ParseStatistics(const char *fn, TArray &statlist) { + statlist.Clear(); try { FScanner sc; diff --git a/src/svnrevision.h b/src/svnrevision.h index cd8368a1..4d49adb0 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 "2941" -#define ZD_SVN_REVISION_NUMBER 2941 +#define ZD_SVN_REVISION_STRING "3080" +#define ZD_SVN_REVISION_NUMBER 3080 diff --git a/src/teaminfo.cpp b/src/teaminfo.cpp index c54b2f9d..f5c3c35e 100644 --- a/src/teaminfo.cpp +++ b/src/teaminfo.cpp @@ -131,6 +131,7 @@ void FTeam::ParseTeamInfo () { int iLump, iLastLump = 0; + Teams.Clear(); while ((iLump = Wads.FindLump ("TEAMINFO", &iLastLump)) != -1) { FScanner Scan (iLump); diff --git a/src/textures/anim_switches.cpp b/src/textures/anim_switches.cpp new file mode 100644 index 00000000..014e879f --- /dev/null +++ b/src/textures/anim_switches.cpp @@ -0,0 +1,419 @@ +/* +** p_switch.cpp +** Switch and button maintenance and animation +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "templates.h" +#include "textures/textures.h" +#include "doomdef.h" +#include "g_game.h" +#include "s_sound.h" +#include "doomstat.h" +#include "r_state.h" +#include "w_wad.h" +#include "cmdlib.h" +#include "sc_man.h" +#include "gi.h" + +static int STACK_ARGS SortSwitchDefs (const void *a, const void *b) +{ + return (*(FSwitchDef **)a)->PreTexture - (*(FSwitchDef **)b)->PreTexture; +} + +//========================================================================== +// +// P_InitSwitchList +// Only called at game initialization. +// +// [RH] Rewritten to use a BOOM-style SWITCHES lump and remove the +// MAXSWITCHES limit. +// +//========================================================================== + +void FTextureManager::InitSwitchList () +{ + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + int lump = Wads.CheckNumForName ("SWITCHES"); + + if (lump != -1) + { + FMemLump lumpdata = Wads.ReadLump (lump); + const char *alphSwitchList = (const char *)lumpdata.GetMem(); + const char *list_p; + FSwitchDef *def1, *def2; + + for (list_p = alphSwitchList; list_p[18] || list_p[19]; list_p += 20) + { + // [RH] Check for switches that aren't really switches + if (stricmp (list_p, list_p+9) == 0) + { + Printf ("Switch %s in SWITCHES has the same 'on' state\n", list_p); + continue; + } + // [RH] Skip this switch if its textures can't be found. + if (CheckForTexture (list_p /* .name1 */, FTexture::TEX_Wall, texflags).Exists() && + CheckForTexture (list_p + 9 /* .name2 */, FTexture::TEX_Wall, texflags).Exists()) + { + def1 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); + def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); + def1->PreTexture = def2->frames[0].Texture = CheckForTexture (list_p /* .name1 */, FTexture::TEX_Wall, texflags); + def2->PreTexture = def1->frames[0].Texture = CheckForTexture (list_p + 9, FTexture::TEX_Wall, texflags); + def1->Sound = def2->Sound = 0; + def1->NumFrames = def2->NumFrames = 1; + def1->frames[0].TimeMin = def2->frames[0].TimeMin = 0; + def1->frames[0].TimeRnd = def2->frames[0].TimeRnd = 0; + AddSwitchPair(def1, def2); + } + } + } + + mSwitchDefs.ShrinkToFit (); + qsort (&mSwitchDefs[0], mSwitchDefs.Size(), sizeof(FSwitchDef *), SortSwitchDefs); +} + +//========================================================================== +// +// Parse a switch block in ANIMDEFS and add the definitions to mSwitchDefs +// +//========================================================================== + +void FTextureManager::ProcessSwitchDef (FScanner &sc) +{ + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + FString picname; + FSwitchDef *def1, *def2; + FTextureID picnum; + int gametype; + bool quest = false; + + def1 = def2 = NULL; + sc.MustGetString (); + if (sc.Compare ("doom")) + { + gametype = GAME_DoomChex; + sc.CheckNumber(); // skip the gamemission filter + } + else if (sc.Compare ("heretic")) + { + gametype = GAME_Heretic; + } + else if (sc.Compare ("hexen")) + { + gametype = GAME_Hexen; + } + else if (sc.Compare ("strife")) + { + gametype = GAME_Strife; + } + else if (sc.Compare ("any")) + { + gametype = GAME_Any; + } + else + { + // There is no game specified; just treat as any + //max = 240; + gametype = GAME_Any; + sc.UnGet (); + } + + sc.MustGetString (); + picnum = CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); + picname = sc.String; + while (sc.GetString ()) + { + if (sc.Compare ("quest")) + { + quest = true; + } + else if (sc.Compare ("on")) + { + if (def1 != NULL) + { + sc.ScriptError ("Switch already has an on state"); + } + def1 = ParseSwitchDef (sc, !picnum.Exists()); + } + else if (sc.Compare ("off")) + { + if (def2 != NULL) + { + sc.ScriptError ("Switch already has an off state"); + } + def2 = ParseSwitchDef (sc, !picnum.Exists()); + } + else + { + sc.UnGet (); + break; + } + } + + if (def1 == NULL || !picnum.Exists() || + (gametype != GAME_Any && !(gametype & gameinfo.gametype))) + { + if (def2 != NULL) + { + M_Free (def2); + } + if (def1 != NULL) + { + M_Free (def1); + } + return; + } + + // If the switch did not have an off state, create one that just returns + // it to the original texture without doing anything interesting + if (def2 == NULL) + { + def2 = (FSwitchDef *)M_Malloc (sizeof(FSwitchDef)); + def2->Sound = def1->Sound; + def2->NumFrames = 1; + def2->frames[0].TimeMin = 0; + def2->frames[0].TimeRnd = 0; + def2->frames[0].Texture = picnum; + } + + def1->PreTexture = picnum; + def2->PreTexture = def1->frames[def1->NumFrames-1].Texture; + if (def1->PreTexture == def2->PreTexture) + { + sc.ScriptError ("The on state for switch %s must end with a texture other than %s", picname.GetChars(), picname.GetChars()); + } + AddSwitchPair(def1, def2); + def1->QuestPanel = def2->QuestPanel = quest; +} + +//========================================================================== +// +// Parse one switch frame +// +//========================================================================== + +FSwitchDef *FTextureManager::ParseSwitchDef (FScanner &sc, bool ignoreBad) +{ + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + FSwitchDef *def; + TArray frames; + FSwitchDef::frame thisframe; + FTextureID picnum; + bool bad; + FSoundID sound; + + bad = false; + + while (sc.GetString ()) + { + if (sc.Compare ("sound")) + { + if (sound != 0) + { + sc.ScriptError ("Switch state already has a sound"); + } + sc.MustGetString (); + sound = sc.String; + } + else if (sc.Compare ("pic")) + { + sc.MustGetString (); + picnum = CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); + if (!picnum.Exists() && !ignoreBad) + { + //Printf ("Unknown switch texture %s\n", sc.String); + bad = true; + } + thisframe.Texture = picnum; + sc.MustGetString (); + if (sc.Compare ("tics")) + { + sc.MustGetNumber (); + thisframe.TimeMin = sc.Number & 65535; + thisframe.TimeRnd = 0; + } + else if (sc.Compare ("rand")) + { + int min, max; + + sc.MustGetNumber (); + min = sc.Number & 65535; + sc.MustGetNumber (); + max = sc.Number & 65535; + if (min > max) + { + swapvalues (min, max); + } + thisframe.TimeMin = min; + thisframe.TimeRnd = (max - min + 1); + } + else + { + thisframe.TimeMin = 0; // Shush, GCC. + thisframe.TimeRnd = 0; + sc.ScriptError ("Must specify a duration for switch frame"); + } + frames.Push(thisframe); + } + else + { + sc.UnGet (); + break; + } + } + if (frames.Size() == 0) + { + sc.ScriptError ("Switch state needs at least one frame"); + } + if (bad) + { + return NULL; + } + + def = (FSwitchDef *)M_Malloc (myoffsetof (FSwitchDef, frames[0]) + frames.Size()*sizeof(frames[0])); + def->Sound = sound; + def->NumFrames = frames.Size(); + memcpy (&def->frames[0], &frames[0], frames.Size() * sizeof(frames[0])); + def->PairDef = NULL; + return def; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FTextureManager::AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2) +{ + unsigned int i; + FSwitchDef *sw1 = NULL; + FSwitchDef *sw2 = NULL; + unsigned int index1 = 0xffffffff, index2 = 0xffffffff; + + for (i = mSwitchDefs.Size (); i-- > 0; ) + { + if (mSwitchDefs[i]->PreTexture == def1->PreTexture) + { + index1 = i; + sw1 = mSwitchDefs[index1]; + if (index2 != 0xffffffff) break; + } + if (mSwitchDefs[i]->PreTexture == def2->PreTexture) + { + index2 = i; + sw2 = mSwitchDefs[index2]; + if (index1 != 0xffffffff) break; + } + } + + def1->PairDef = def2; + def2->PairDef = def1; + + if (sw1 != NULL && sw2 != NULL && sw1->PairDef == sw2 && sw2->PairDef == sw1) + { + //We are replacing an existing pair so we can safely delete the old definitions + M_Free(sw1); + M_Free(sw2); + mSwitchDefs[index1] = def1; + mSwitchDefs[index2] = def2; + } + else + { + // This new switch will not or only partially replace an existing pair. + // We should not break up an old pair if the new one only redefined one + // of the two textures. These paired definitions will only be used + // as the return animation so their names don't matter. Better clear them to be safe. + if (sw1 != NULL) sw1->PreTexture.SetInvalid(); + if (sw2 != NULL) sw2->PreTexture.SetInvalid(); + sw1 = NULL; + sw2 = NULL; + unsigned int pos = mSwitchDefs.Reserve(2); + mSwitchDefs[pos] = def1; + mSwitchDefs[pos+1] = def2; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FSwitchDef *FTextureManager::FindSwitch (FTextureID texture) +{ + int mid, low, high; + + high = (int)(mSwitchDefs.Size () - 1); + if (high >= 0) + { + low = 0; + do + { + mid = (high + low) / 2; + if (mSwitchDefs[mid]->PreTexture == texture) + { + return mSwitchDefs[mid]; + } + else if (texture < mSwitchDefs[mid]->PreTexture) + { + high = mid - 1; + } + else + { + low = mid + 1; + } + } while (low <= high); + } + return NULL; +} + +//========================================================================== +// +// operator<< +// +//========================================================================== + +template<> FArchive &operator<< (FArchive &arc, FSwitchDef* &Switch) +{ + if (arc.IsStoring()) + { + arc << Switch->PreTexture; + } + else + { + FTextureID tex; + arc << tex; + Switch = TexMan.FindSwitch(tex); + } + return arc; +} + diff --git a/src/r_anim.cpp b/src/textures/animations.cpp similarity index 60% rename from src/r_anim.cpp rename to src/textures/animations.cpp index cac36186..65405e5c 100644 --- a/src/r_anim.cpp +++ b/src/textures/animations.cpp @@ -49,69 +49,91 @@ // TYPES ------------------------------------------------------------------- -// -// Animating textures and planes -// -// [RH] Expanded to work with a Hexen ANIMDEFS lump -// - -struct FAnimDef -{ - FTextureID BasePic; - WORD NumFrames; - WORD CurFrame; - BYTE AnimType; - DWORD SwitchTime; // Time to advance to next frame - struct FAnimFrame - { - DWORD SpeedMin; // Speeds are in ms, not tics - DWORD SpeedRange; - FTextureID FramePic; - } Frames[1]; - enum - { - ANIM_Forward, - ANIM_Backward, - ANIM_OscillateUp, - ANIM_OscillateDown, - ANIM_DiscreteFrames - }; - - void SetSwitchTime (DWORD mstime); -}; - -// This is an array of pointers to animation definitions. -// When it is destroyed, it deletes any animations it points to as well. -class AnimArray : public TArray -{ -public: - ~AnimArray(); - void AddAnim (FAnimDef *anim); - void FixAnimations (); -}; - // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- -static void R_InitAnimDefs (); -static void R_AddComplexAnim (FTextureID picnum, const TArray &frames); -static void ParseAnim (FScanner &sc, bool istex); -static void ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing); -static void ParsePicAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing, TArray &frames); -static FTextureID ParseFramenum (FScanner &sc, FTextureID basepicnum, int usetype, bool allowMissing); -static void ParseTime (FScanner &sc, DWORD &min, DWORD &max); - // PUBLIC DATA DEFINITIONS ------------------------------------------------- // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static AnimArray Anims; static FRandom pr_animatepictures ("AnimatePics"); // CODE -------------------------------------------------------------------- //========================================================================== // -// R_InitPicAnims +// FTextureManager :: AddAnim +// +// Adds a new animation to the array. If one with the same basepic as the +// new one already exists, it is replaced. +// +//========================================================================== + +void FTextureManager::AddAnim (FAnimDef *anim) +{ + // Search for existing duplicate. + for (unsigned int i = 0; i < mAnimations.Size(); ++i) + { + if (mAnimations[i]->BasePic == anim->BasePic) + { + // Found one! + free (mAnimations[i]); + mAnimations[i] = anim; + return; + } + } + // Didn't find one, so add it at the end. + mAnimations.Push (anim); +} + +//========================================================================== +// +// FTextureManager :: AddSimpleAnim +// +// Creates an animation with simple characteristics. This is used for +// original Doom (non-ANIMDEFS-style) animations and Build animations. +// +//========================================================================== + +void FTextureManager::AddSimpleAnim (FTextureID picnum, int animcount, int animtype, DWORD speedmin, DWORD speedrange) +{ + if (AreTexturesCompatible(picnum, picnum + (animcount - 1))) + { + FAnimDef *anim = (FAnimDef *)M_Malloc (sizeof(FAnimDef)); + anim->CurFrame = 0; + anim->BasePic = picnum; + anim->NumFrames = animcount; + anim->AnimType = animtype; + anim->SwitchTime = 0; + anim->Frames[0].SpeedMin = speedmin; + anim->Frames[0].SpeedRange = speedrange; + anim->Frames[0].FramePic = anim->BasePic; + AddAnim (anim); + } +} + +//========================================================================== +// +// FTextureManager :: AddComplexAnim +// +// Creates an animation with individually defined frames. +// +//========================================================================== + +void FTextureManager::AddComplexAnim (FTextureID picnum, const TArray &frames) +{ + FAnimDef *anim = (FAnimDef *)M_Malloc (sizeof(FAnimDef) + (frames.Size()-1) * sizeof(frames[0])); + anim->BasePic = picnum; + anim->NumFrames = frames.Size(); + anim->CurFrame = 0; + anim->AnimType = FAnimDef::ANIM_DiscreteFrames; + anim->SwitchTime = 0; + memcpy (&anim->Frames[0], &frames[0], frames.Size() * sizeof(frames[0])); + AddAnim (anim); +} + +//========================================================================== +// +// FTextureManager :: Initanimated // // [description copied from BOOM] // Load the table of animation definitions, checking for existence of @@ -139,9 +161,9 @@ static FRandom pr_animatepictures ("AnimatePics"); CVAR(Bool, debuganimated, false, 0) -void R_InitPicAnims (void) +void FTextureManager::InitAnimated (void) { - const BITFIELD texflags = FTextureManager::TEXMAN_Overridable; + const BITFIELD texflags = TEXMAN_Overridable; // I think better not! This is only for old ANIMATED definition that // don't know about ZDoom's more flexible texture system. // | FTextureManager::TEXMAN_TryAny; @@ -163,17 +185,17 @@ void R_InitPicAnims (void) if (*anim_p /* .istexture */ & 1) { // different episode ? - if (!(pic1 = TexMan.CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Wall, texflags)).Exists() || - !(pic2 = TexMan.CheckForTexture (anim_p + 1 /* .endname */, FTexture::TEX_Wall, texflags)).Exists()) + if (!(pic1 = CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Wall, texflags)).Exists() || + !(pic2 = CheckForTexture (anim_p + 1 /* .endname */, FTexture::TEX_Wall, texflags)).Exists()) continue; // [RH] Bit 1 set means allow decals on walls with this texture - TexMan[pic2]->bNoDecals = TexMan[pic1]->bNoDecals = !(*anim_p & 2); + Texture(pic2)->bNoDecals = Texture(pic1)->bNoDecals = !(*anim_p & 2); } else { - if (!(pic1 = TexMan.CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Flat, texflags)).Exists() || - !(pic2 = TexMan.CheckForTexture (anim_p + 1 /* .startname */, FTexture::TEX_Flat, texflags)).Exists()) + if (!(pic1 = CheckForTexture (anim_p + 10 /* .startname */, FTexture::TEX_Flat, texflags)).Exists() || + !(pic2 = CheckForTexture (anim_p + 1 /* .startname */, FTexture::TEX_Flat, texflags)).Exists()) continue; } if (pic1 == pic2) @@ -183,8 +205,8 @@ void R_InitPicAnims (void) continue; } - FTexture *tex1 = TexMan[pic1]; - FTexture *tex2 = TexMan[pic2]; + FTexture *tex1 = Texture(pic1); + FTexture *tex2 = Texture(pic2); if (tex1->UseType != tex2->UseType) { @@ -213,71 +235,22 @@ void R_InitPicAnims (void) (BYTE(anim_p[21]) << 16) | (BYTE(anim_p[22]) << 24), 1000, 35); - R_AddSimpleAnim (pic1, pic2 - pic1 + 1, animtype, animspeed); + AddSimpleAnim (pic1, pic2 - pic1 + 1, animtype, animspeed); } } - // [RH] Load any ANIMDEFS lumps - R_InitAnimDefs (); - Anims.FixAnimations (); } //========================================================================== // -// R_AddSimpleAnim -// -// Creates an animation with simple characteristics. This is used for -// original Doom (non-ANIMDEFS-style) animations and Build animations. -// -//========================================================================== - -void R_AddSimpleAnim (FTextureID picnum, int animcount, int animtype, DWORD speedmin, DWORD speedrange) -{ - if (TexMan.AreTexturesCompatible(picnum, picnum + (animcount - 1))) - { - FAnimDef *anim = (FAnimDef *)M_Malloc (sizeof(FAnimDef)); - anim->CurFrame = 0; - anim->BasePic = picnum; - anim->NumFrames = animcount; - anim->AnimType = animtype; - anim->SwitchTime = 0; - anim->Frames[0].SpeedMin = speedmin; - anim->Frames[0].SpeedRange = speedrange; - anim->Frames[0].FramePic = anim->BasePic; - Anims.AddAnim (anim); - } -} - -//========================================================================== -// -// R_AddComplexAnim -// -// Creates an animation with individually defined frames. -// -//========================================================================== - -static void R_AddComplexAnim (FTextureID picnum, const TArray &frames) -{ - FAnimDef *anim = (FAnimDef *)M_Malloc (sizeof(FAnimDef) + (frames.Size()-1) * sizeof(frames[0])); - anim->BasePic = picnum; - anim->NumFrames = frames.Size(); - anim->CurFrame = 0; - anim->AnimType = FAnimDef::ANIM_DiscreteFrames; - anim->SwitchTime = 0; - memcpy (&anim->Frames[0], &frames[0], frames.Size() * sizeof(frames[0])); - Anims.AddAnim (anim); -} - -//========================================================================== -// -// R_InitAnimDefs +// FTextureManager :: InitAnimDefs // // This uses a Hexen ANIMDEFS lump to define the animation sequences // //========================================================================== -static void R_InitAnimDefs () +void FTextureManager::InitAnimDefs () { - const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; int lump, lastlump = 0; while ((lump = Wads.FindLump ("ANIMDEFS", &lastlump)) != -1) @@ -288,132 +261,37 @@ static void R_InitAnimDefs () { if (sc.Compare ("flat")) { - ParseAnim (sc, false); + ParseAnim (sc, FTexture::TEX_Flat); } else if (sc.Compare ("texture")) { - ParseAnim (sc, true); + ParseAnim (sc, FTexture::TEX_Wall); } else if (sc.Compare ("switch")) { - P_ProcessSwitchDef (sc); + ProcessSwitchDef (sc); } // [GRB] Added warping type 2 else if (sc.Compare ("warp") || sc.Compare ("warp2")) { - bool isflat = false; - bool type2 = sc.Compare ("warp2"); // [GRB] - sc.MustGetString (); - if (sc.Compare ("flat")) - { - isflat = true; - sc.MustGetString (); - } - else if (sc.Compare ("texture")) - { - isflat = false; - sc.MustGetString (); - } - else - { - sc.ScriptError (NULL); - } - FTextureID picnum = TexMan.CheckForTexture (sc.String, isflat ? FTexture::TEX_Flat : FTexture::TEX_Wall, texflags); - if (picnum.isValid()) - { - FTexture * warper = TexMan[picnum]; - - // don't warp a texture more than once - if (!warper->bWarped) - { - if (type2) // [GRB] - warper = new FWarp2Texture (warper); - else - warper = new FWarpTexture (warper); - TexMan.ReplaceTexture (picnum, warper, false); - } - - if (sc.CheckFloat()) - { - static_cast(warper)->SetSpeed(float(sc.Float)); - } - - // No decals on warping textures, by default. - // Warping information is taken from the last warp - // definition for this texture. - warper->bNoDecals = true; - if (sc.GetString ()) - { - if (sc.Compare ("allowdecals")) - { - warper->bNoDecals = false; - } - else - { - sc.UnGet (); - } - } - } + ParseWarp(sc); } else if (sc.Compare ("cameratexture")) { - int width, height; - int fitwidth, fitheight; - FString picname; - - sc.MustGetString (); - picname = sc.String; - sc.MustGetNumber (); - width = sc.Number; - sc.MustGetNumber (); - height = sc.Number; - FTextureID picnum = TexMan.CheckForTexture (picname, FTexture::TEX_Flat, texflags); - FTexture *viewer = new FCanvasTexture (picname, width, height); - if (picnum.Exists()) - { - FTexture *oldtex = TexMan[picnum]; - fitwidth = oldtex->GetScaledWidth (); - fitheight = oldtex->GetScaledHeight (); - viewer->UseType = oldtex->UseType; - TexMan.ReplaceTexture (picnum, viewer, true); - } - else - { - fitwidth = width; - fitheight = height; - // [GRB] No need for oldtex - viewer->UseType = FTexture::TEX_Wall; - TexMan.AddTexture (viewer); - } - if (sc.GetString()) - { - if (sc.Compare ("fit")) - { - sc.MustGetNumber (); - fitwidth = sc.Number; - sc.MustGetNumber (); - fitheight = sc.Number; - } - else - { - sc.UnGet (); - } - } - viewer->SetScaledSize(fitwidth, fitheight); + ParseCameraTexture(sc); } else if (sc.Compare ("animatedDoor")) { - P_ParseAnimatedDoor (sc); + ParseAnimatedDoor (sc); } else if (sc.Compare("skyoffset")) { sc.MustGetString (); - FTextureID picnum = TexMan.CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); + FTextureID picnum = CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); sc.MustGetNumber(); if (picnum.Exists()) { - FTexture *tex = TexMan[picnum]; - tex->SkyOffset = sc.Number; + Texture(picnum)->SkyOffset = sc.Number; } } else @@ -426,31 +304,28 @@ static void R_InitAnimDefs () //========================================================================== // -// ParseAnim +// FTextureManager :: ParseAnim // // Parse a single animation definition out of an ANIMDEFS lump and // create the corresponding animation structure. // //========================================================================== -static void ParseAnim (FScanner &sc, bool istex) +void FTextureManager::ParseAnim (FScanner &sc, int usetype) { - const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; TArray frames (32); FTextureID picnum; - int usetype; int defined = 0; bool optional = false, missing = false; - usetype = istex ? FTexture::TEX_Wall : FTexture::TEX_Flat; - sc.MustGetString (); if (sc.Compare ("optional")) { optional = true; sc.MustGetString (); } - picnum = TexMan.CheckForTexture (sc.String, usetype, texflags); + picnum = CheckForTexture (sc.String, usetype, texflags); if (!picnum.Exists()) { @@ -467,7 +342,7 @@ static void ParseAnim (FScanner &sc, bool istex) // no decals on animating textures, by default if (picnum.isValid()) { - TexMan[picnum]->bNoDecals = true; + Texture(picnum)->bNoDecals = true; } while (sc.GetString ()) @@ -476,7 +351,7 @@ static void ParseAnim (FScanner &sc, bool istex) { if (picnum.isValid()) { - TexMan[picnum]->bNoDecals = false; + Texture(picnum)->bNoDecals = false; } continue; } @@ -517,20 +392,20 @@ static void ParseAnim (FScanner &sc, bool istex) { sc.ScriptError ("Animation needs at least 2 frames"); } - R_AddComplexAnim (picnum, frames); + AddComplexAnim (picnum, frames); } } //========================================================================== // -// ParseRangeAnim +// FTextureManager :: ParseRangeAnim // // Parse an animation defined using "range". Not that one range entry is // enough to define a complete animation, unlike "pic". // //========================================================================== -static void ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing) +void FTextureManager::ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing) { int type; FTextureID framenum; @@ -547,7 +422,7 @@ static void ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool m if (framenum < picnum) { type = FAnimDef::ANIM_Backward; - TexMan[framenum]->bNoDecals = TexMan[picnum]->bNoDecals; + Texture(framenum)->bNoDecals = Texture(picnum)->bNoDecals; swapvalues (framenum, picnum); } if (sc.GetString()) @@ -561,18 +436,18 @@ static void ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool m sc.UnGet (); } } - R_AddSimpleAnim (picnum, framenum - picnum + 1, type, min, max - min); + AddSimpleAnim (picnum, framenum - picnum + 1, type, min, max - min); } //========================================================================== // -// ParsePicAnim +// FTextureManager :: ParsePicAnim // // Parse a single frame from ANIMDEFS defined using "pic". // //========================================================================== -static void ParsePicAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing, TArray &frames) +void FTextureManager::ParsePicAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing, TArray &frames) { FTextureID framenum; DWORD min, max; @@ -593,16 +468,16 @@ static void ParsePicAnim (FScanner &sc, FTextureID picnum, int usetype, bool mis //========================================================================== // -// ParseFramenum +// FTextureManager :: ParseFramenum // // Reads a frame's texture from ANIMDEFS. It can either be an integral // offset from basepicnum or a specific texture name. // //========================================================================== -static FTextureID ParseFramenum (FScanner &sc, FTextureID basepicnum, int usetype, bool allowMissing) +FTextureID FTextureManager::ParseFramenum (FScanner &sc, FTextureID basepicnum, int usetype, bool allowMissing) { - const BITFIELD texflags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny; + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; FTextureID framenum; sc.MustGetString (); @@ -612,7 +487,7 @@ static FTextureID ParseFramenum (FScanner &sc, FTextureID basepicnum, int usetyp } else { - framenum = TexMan.CheckForTexture (sc.String, usetype, texflags); + framenum = CheckForTexture (sc.String, usetype, texflags); if (!framenum.Exists() && !allowMissing) { sc.ScriptError ("Unknown texture %s", sc.String); @@ -623,13 +498,13 @@ static FTextureID ParseFramenum (FScanner &sc, FTextureID basepicnum, int usetyp //========================================================================== // -// ParseTime +// FTextureManager :: ParseTime // // Reads a tics or rand time definition from ANIMDEFS. // //========================================================================== -static void ParseTime (FScanner &sc, DWORD &min, DWORD &max) +void FTextureManager::ParseTime (FScanner &sc, DWORD &min, DWORD &max) { sc.MustGetString (); if (sc.Compare ("tics")) @@ -652,53 +527,128 @@ static void ParseTime (FScanner &sc, DWORD &min, DWORD &max) //========================================================================== // -// AnimArray :: ~AnimArray +// FTextureManager :: ParseWarp // -// Frees all animations held in this array before freeing the array. +// Parses a warping texture definition // //========================================================================== -AnimArray::~AnimArray() +void FTextureManager::ParseWarp(FScanner &sc) { - for (unsigned i = 0; i < Size(); i++) + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + bool isflat = false; + bool type2 = sc.Compare ("warp2"); // [GRB] + sc.MustGetString (); + if (sc.Compare ("flat")) { - if ((*this)[i] != NULL) + isflat = true; + sc.MustGetString (); + } + else if (sc.Compare ("texture")) + { + isflat = false; + sc.MustGetString (); + } + else + { + sc.ScriptError (NULL); + } + FTextureID picnum = CheckForTexture (sc.String, isflat ? FTexture::TEX_Flat : FTexture::TEX_Wall, texflags); + if (picnum.isValid()) + { + FTexture *warper = Texture(picnum); + + // don't warp a texture more than once + if (!warper->bWarped) { - M_Free ((*this)[i]); - (*this)[i] = NULL; + if (type2) warper = new FWarp2Texture (warper); + else warper = new FWarpTexture (warper); + + ReplaceTexture (picnum, warper, false); + } + + if (sc.CheckFloat()) + { + static_cast(warper)->SetSpeed(float(sc.Float)); + } + + // No decals on warping textures, by default. + // Warping information is taken from the last warp + // definition for this texture. + warper->bNoDecals = true; + if (sc.GetString ()) + { + if (sc.Compare ("allowdecals")) + { + warper->bNoDecals = false; + } + else + { + sc.UnGet (); + } } } } //========================================================================== // -// AnimArray :: AddAnim +// ParseCameraTexture // -// Adds a new animation to the array. If one with the same basepic as the -// new one already exists, it is replaced. +// Parses a camera texture definition // //========================================================================== -void AnimArray::AddAnim (FAnimDef *anim) +void FTextureManager::ParseCameraTexture(FScanner &sc) { - // Search for existing duplicate. - for (unsigned int i = 0; i < Anims.Size(); ++i) + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + int width, height; + int fitwidth, fitheight; + FString picname; + + sc.MustGetString (); + picname = sc.String; + sc.MustGetNumber (); + width = sc.Number; + sc.MustGetNumber (); + height = sc.Number; + FTextureID picnum = CheckForTexture (picname, FTexture::TEX_Flat, texflags); + FTexture *viewer = new FCanvasTexture (picname, width, height); + if (picnum.Exists()) { - if ((*this)[i]->BasePic == anim->BasePic) + FTexture *oldtex = Texture(picnum); + fitwidth = oldtex->GetScaledWidth (); + fitheight = oldtex->GetScaledHeight (); + viewer->UseType = oldtex->UseType; + ReplaceTexture (picnum, viewer, true); + } + else + { + fitwidth = width; + fitheight = height; + // [GRB] No need for oldtex + viewer->UseType = FTexture::TEX_Wall; + AddTexture (viewer); + } + if (sc.GetString()) + { + if (sc.Compare ("fit")) { - // Found one! - free ((*this)[i]); - (*this)[i] = anim; - return; + sc.MustGetNumber (); + fitwidth = sc.Number; + sc.MustGetNumber (); + fitheight = sc.Number; + } + else + { + sc.UnGet (); } } - // Didn't find one, so add it at the end. - Push (anim); + viewer->SetScaledSize(fitwidth, fitheight); } //========================================================================== // -// AnimArray :: FixAnimations +// FTextureManager :: FixAnimations // // Copy the "front sky" flag from an animated texture to the rest // of the textures in the animation, and make every texture in an @@ -706,21 +656,21 @@ void AnimArray::AddAnim (FAnimDef *anim) // //========================================================================== -void AnimArray::FixAnimations () +void FTextureManager::FixAnimations () { unsigned int i; int j; - for (i = 0; i < Size(); ++i) + for (i = 0; i < mAnimations.Size(); ++i) { - FAnimDef *anim = operator[] (i); + FAnimDef *anim = mAnimations[i]; if (anim->AnimType == FAnimDef::ANIM_DiscreteFrames) { - if (TexMan[anim->BasePic]->bNoRemap0) + if (Texture(anim->BasePic)->bNoRemap0) { for (j = 0; j < anim->NumFrames; ++j) { - TexMan[anim->Frames[j].FramePic]->SetFrontSkyLayer (); + Texture(anim->Frames[j].FramePic)->SetFrontSkyLayer (); } } } @@ -730,11 +680,11 @@ void AnimArray::FixAnimations () bool noremap = false; const char *name; - name = TexMan[anim->BasePic]->Name; - nodecals = TexMan[anim->BasePic]->bNoDecals; + name = Texture(anim->BasePic)->Name; + nodecals = Texture(anim->BasePic)->bNoDecals; for (j = 0; j < anim->NumFrames; ++j) { - FTexture *tex = TexMan[anim->BasePic + j]; + FTexture *tex = Texture(anim->BasePic + j); noremap |= tex->bNoRemap0; tex->bNoDecals = nodecals; } @@ -742,13 +692,100 @@ void AnimArray::FixAnimations () { for (j = 0; j < anim->NumFrames; ++j) { - TexMan[anim->BasePic + j]->SetFrontSkyLayer (); + Texture(anim->BasePic + j)->SetFrontSkyLayer (); } } } } } +//========================================================================== +// +// ParseAnimatedDoor +// +// Parses an animated door definition +// +//========================================================================== + +void FTextureManager::ParseAnimatedDoor(FScanner &sc) +{ + const BITFIELD texflags = TEXMAN_Overridable | TEXMAN_TryAny; + FDoorAnimation anim; + TArray frames; + bool error = false; + FTextureID v; + + sc.MustGetString(); + anim.BaseTexture = CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); + + if (!anim.BaseTexture.Exists()) + { + error = true; + } + + while (sc.GetString ()) + { + if (sc.Compare ("opensound")) + { + sc.MustGetString (); + anim.OpenSound = sc.String; + } + else if (sc.Compare ("closesound")) + { + sc.MustGetString (); + anim.CloseSound = sc.String; + } + else if (sc.Compare ("pic")) + { + sc.MustGetString (); + if (IsNum (sc.String)) + { + v = anim.BaseTexture + (atoi(sc.String) - 1); + } + else + { + v = CheckForTexture (sc.String, FTexture::TEX_Wall, texflags); + if (!v.Exists() && anim.BaseTexture.Exists() && !error) + { + sc.ScriptError ("Unknown texture %s", sc.String); + } + frames.Push (v); + } + } + else + { + sc.UnGet (); + break; + } + } + if (!error) + { + anim.TextureFrames = new FTextureID[frames.Size()]; + memcpy (anim.TextureFrames, &frames[0], sizeof(FTextureID) * frames.Size()); + anim.NumTextureFrames = frames.Size(); + mAnimatedDoors.Push (anim); + } +} + +//========================================================================== +// +// Return index into "DoorAnimations" array for which door type to use +// +//========================================================================== + +FDoorAnimation *FTextureManager::FindAnimatedDoor (FTextureID picnum) +{ + unsigned int i; + + for (i = 0; i < mAnimatedDoors.Size(); ++i) + { + if (picnum == mAnimatedDoors[i].BaseTexture) + return &mAnimatedDoors[i]; + } + + return NULL; +} + //========================================================================== // // FAnimDef :: SetSwitchTime @@ -768,19 +805,41 @@ void FAnimDef::SetSwitchTime (DWORD mstime) } } + //========================================================================== // -// R_UpdateAnimations +// FTextureManager :: SetTranslation +// +// Sets animation translation for a texture +// +//========================================================================== + +void FTextureManager::SetTranslation (FTextureID fromtexnum, FTextureID totexnum) +{ + if ((size_t)fromtexnum.texnum < Translation.Size()) + { + if ((size_t)totexnum.texnum >= Textures.Size()) + { + totexnum.texnum = fromtexnum.texnum; + } + Translation[fromtexnum.texnum] = totexnum.texnum; + } +} + + +//========================================================================== +// +// FTextureManager :: UpdateAnimations // // Updates texture translations for each animation and scrolls the skies. // //========================================================================== -void R_UpdateAnimations (DWORD mstime) +void FTextureManager::UpdateAnimations (DWORD mstime) { - for (unsigned int j = 0; j < Anims.Size(); ++j) + for (unsigned int j = 0; j < mAnimations.Size(); ++j) { - FAnimDef *anim = Anims[j]; + FAnimDef *anim = mAnimations[j]; // If this is the first time through R_UpdateAnimations, just // initialize the anim's switch time without actually animating. @@ -832,19 +891,36 @@ void R_UpdateAnimations (DWORD mstime) if (anim->AnimType == FAnimDef::ANIM_DiscreteFrames) { - TexMan.SetTranslation (anim->BasePic, anim->Frames[anim->CurFrame].FramePic); + SetTranslation (anim->BasePic, anim->Frames[anim->CurFrame].FramePic); } else { for (unsigned int i = 0; i < anim->NumFrames; i++) { - TexMan.SetTranslation (anim->BasePic + i, anim->BasePic + (i + anim->CurFrame) % anim->NumFrames); + SetTranslation (anim->BasePic + i, anim->BasePic + (i + anim->CurFrame) % anim->NumFrames); } } } - - // Scroll the sky - double ms = (double)mstime * FRACUNIT; - sky1pos = ms * level.skyspeed1; - sky2pos = ms * level.skyspeed2; } + +//========================================================================== +// +// operator<< +// +//========================================================================== + +template<> FArchive &operator<< (FArchive &arc, FDoorAnimation* &Doorani) +{ + if (arc.IsStoring()) + { + arc << Doorani->BaseTexture; + } + else + { + FTextureID tex; + arc << tex; + Doorani = TexMan.FindAnimatedDoor(tex); + } + return arc; +} + diff --git a/src/textures/buildtexture.cpp b/src/textures/buildtexture.cpp index 8d7e6281..836cc2da 100644 --- a/src/textures/buildtexture.cpp +++ b/src/textures/buildtexture.cpp @@ -41,8 +41,6 @@ #include "cmdlib.h" #include "st_start.h" -static TArray BuildTileFiles; - //========================================================================== // // A texture defined in a Build TILESxxx.ART file @@ -158,7 +156,7 @@ const BYTE *FBuildTexture::GetColumn (unsigned int column, const Span **spans_ou // //=========================================================================== -void AddTiles (void *tiles) +void FTextureManager::AddTiles (void *tiles) { // int numtiles = LittleLong(((DWORD *)tiles)[1]); // This value is not reliable int tilestart = LittleLong(((DWORD *)tiles)[2]); @@ -183,7 +181,7 @@ void AddTiles (void *tiles) if (width <= 0 || height <= 0) continue; tex = new FBuildTexture (i, tiledata, width, height, xoffs, yoffs); - texnum = TexMan.AddTexture (tex); + texnum = AddTexture (tex); while (size > 0) { *tiledata = 255 - *tiledata; @@ -207,7 +205,7 @@ void AddTiles (void *tiles) speed = (anm >> 24) & 15; speed = MAX (1, (1 << speed) * 1000 / 120); // Convert from 120 Hz to 1000 Hz. - R_AddSimpleAnim (texnum, picanm[pic] & 63, type, speed); + AddSimpleAnim (texnum, picanm[pic] & 63, type, speed); } // Blood's rotation types: @@ -264,7 +262,7 @@ void AddTiles (void *tiles) // //=========================================================================== -static int CountTiles (void *tiles) +int FTextureManager::CountTiles (void *tiles) { int version = LittleLong(*(DWORD *)tiles); if (version != 1) @@ -287,7 +285,7 @@ static int CountTiles (void *tiles) // //=========================================================================== -int R_CountBuildTiles () +int FTextureManager::CountBuildTiles () { int numartfiles = 0; char artfile[] = "tilesXXX.art"; @@ -375,25 +373,10 @@ int R_CountBuildTiles () // //=========================================================================== -void R_InitBuildTiles () +void FTextureManager::InitBuildTiles () { for (unsigned int i = 0; i < BuildTileFiles.Size(); ++i) { AddTiles (BuildTileFiles[i]); } } - -//=========================================================================== -// -// R_DeinitBuildTiles -// -//=========================================================================== - -void R_DeinitBuildTiles () -{ - for (unsigned int i = 0; i < BuildTileFiles.Size(); ++i) - { - delete[] BuildTileFiles[i]; - } - BuildTileFiles.Clear(); -} diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index e562923d..72eb59f2 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -48,9 +48,6 @@ #include "cmdlib.h" #include "g_level.h" -extern void R_InitBuildTiles(); - - FTextureManager TexMan; //========================================================================== @@ -62,8 +59,6 @@ FTextureManager TexMan; FTextureManager::FTextureManager () { memset (HashFirst, -1, sizeof(HashFirst)); - // Texture 0 is a dummy texture used to indicate "no texture" - AddTexture (new FDummyTexture); } @@ -74,11 +69,63 @@ FTextureManager::FTextureManager () //========================================================================== FTextureManager::~FTextureManager () +{ + DeleteAll(); +} + +//========================================================================== +// +// FTextureManager :: DeleteAll +// +//========================================================================== + +void FTextureManager::DeleteAll() { for (unsigned int i = 0; i < Textures.Size(); ++i) { delete Textures[i].Texture; } + Textures.Clear(); + Translation.Clear(); + FirstTextureForFile.Clear(); + memset (HashFirst, -1, sizeof(HashFirst)); + DefaultTexture.SetInvalid(); + + for (unsigned i = 0; i < mAnimations.Size(); i++) + { + if (mAnimations[i] != NULL) + { + M_Free (mAnimations[i]); + mAnimations[i] = NULL; + } + } + mAnimations.Clear(); + + for (unsigned i = 0; i < mSwitchDefs.Size(); i++) + { + if (mSwitchDefs[i] != NULL) + { + M_Free (mSwitchDefs[i]); + mSwitchDefs[i] = NULL; + } + } + mSwitchDefs.Clear(); + + for (unsigned i = 0; i < mAnimatedDoors.Size(); i++) + { + if (mAnimatedDoors[i].TextureFrames != NULL) + { + delete mAnimatedDoors[i].TextureFrames; + mAnimatedDoors[i].TextureFrames = NULL; + } + } + mAnimatedDoors.Clear(); + + for (unsigned int i = 0; i < BuildTileFiles.Size(); ++i) + { + delete[] BuildTileFiles[i]; + } + BuildTileFiles.Clear(); } //========================================================================== @@ -896,8 +943,14 @@ void FTextureManager::SortTexturesByType(int start, int end) void FTextureManager::Init() { + DeleteAll(); + // Init Build Tile data if it hasn't been done already + if (BuildTileFiles.Size() == 0) CountBuildTiles (); FTexture::InitGrayMap(); + // Texture 0 is a dummy texture used to indicate "no texture" + AddTexture (new FDummyTexture); + int wadcnt = Wads.GetNumWads(); for(int i = 0; i< wadcnt; i++) { @@ -907,7 +960,7 @@ void FTextureManager::Init() // Add one marker so that the last WAD is easier to handle and treat // Build tiles as a completely separate block. FirstTextureForFile.Push(Textures.Size()); - R_InitBuildTiles (); + InitBuildTiles (); FirstTextureForFile.Push(Textures.Size()); DefaultTexture = CheckForTexture ("-NOFLAT-", FTexture::TEX_Override, 0); @@ -938,6 +991,11 @@ void FTextureManager::Init() } } } + + InitAnimated(); + InitAnimDefs(); + FixAnimations(); + InitSwitchList(); } //========================================================================== @@ -988,6 +1046,104 @@ int FTextureManager::ReadTexture (FArchive &arc) else return -1; } +//=========================================================================== +// +// R_GuesstimateNumTextures +// +// Returns an estimate of the number of textures R_InitData will have to +// process. Used by D_DoomMain() when it calls ST_Init(). +// +//=========================================================================== + +int FTextureManager::GuesstimateNumTextures () +{ + int numtex = 0; + + for(int i = Wads.GetNumLumps()-1; i>=0; i--) + { + int space = Wads.GetLumpNamespace(i); + switch(space) + { + case ns_flats: + case ns_sprites: + case ns_newtextures: + case ns_hires: + case ns_patches: + case ns_graphics: + numtex++; + break; + + default: + if (Wads.GetLumpFlags(i) & LUMPF_MAYBEFLAT) numtex++; + + break; + } + } + + numtex += CountBuildTiles (); + numtex += CountTexturesX (); + return numtex; +} + +//=========================================================================== +// +// R_CountTexturesX +// +// See R_InitTextures() for the logic in deciding what lumps to check. +// +//=========================================================================== + +int FTextureManager::CountTexturesX () +{ + int count = 0; + int wadcount = Wads.GetNumWads(); + for (int wadnum = 0; wadnum < wadcount; wadnum++) + { + // Use the most recent PNAMES for this WAD. + // Multiple PNAMES in a WAD will be ignored. + int pnames = Wads.CheckNumForName("PNAMES", ns_global, wadnum, false); + + // should never happen except for zdoom.pk3 + if (pnames < 0) continue; + + // Only count the patches if the PNAMES come from the current file + // Otherwise they have already been counted. + if (Wads.GetLumpFile(pnames) == wadnum) + { + count += CountLumpTextures (pnames); + } + + int texlump1 = Wads.CheckNumForName ("TEXTURE1", ns_global, wadnum); + int texlump2 = Wads.CheckNumForName ("TEXTURE2", ns_global, wadnum); + + count += CountLumpTextures (texlump1) - 1; + count += CountLumpTextures (texlump2) - 1; + } + return count; +} + +//=========================================================================== +// +// R_CountLumpTextures +// +// Returns the number of patches in a PNAMES/TEXTURE1/TEXTURE2 lump. +// +//=========================================================================== + +int FTextureManager::CountLumpTextures (int lumpnum) +{ + if (lumpnum >= 0) + { + FWadLump file = Wads.OpenLumpNum (lumpnum); + DWORD numtex; + + file >> numtex; + return numtex >= 0 ? numtex : 0; + } + return 0; +} + + //========================================================================== // // operator<< diff --git a/src/textures/textures.h b/src/textures/textures.h index 5da615d9..1d74442d 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -64,8 +64,6 @@ protected: FTextureID(int num) { texnum = num; } private: int texnum; - - friend void AddTiles (void *tiles); }; class FNullTextureID : public FTextureID @@ -76,6 +74,62 @@ public: FArchive &operator<< (FArchive &arc, FTextureID &tex); +// +// Animating textures and planes +// +// [RH] Expanded to work with a Hexen ANIMDEFS lump +// + +struct FAnimDef +{ + FTextureID BasePic; + WORD NumFrames; + WORD CurFrame; + BYTE AnimType; + DWORD SwitchTime; // Time to advance to next frame + struct FAnimFrame + { + DWORD SpeedMin; // Speeds are in ms, not tics + DWORD SpeedRange; + FTextureID FramePic; + } Frames[1]; + enum + { + ANIM_Forward, + ANIM_Backward, + ANIM_OscillateUp, + ANIM_OscillateDown, + ANIM_DiscreteFrames + }; + + void SetSwitchTime (DWORD mstime); +}; + +struct FSwitchDef +{ + FTextureID PreTexture; // texture to switch from + FSwitchDef *PairDef; // switch def to use to return to PreTexture + WORD NumFrames; // # of animation frames + bool QuestPanel; // Special texture for Strife mission + int Sound; // sound to play at start of animation. Changed to int to avoiud having to include s_sound here. + struct frame // Array of times followed by array of textures + { // actual length of each array is + WORD TimeMin; + WORD TimeRnd; + FTextureID Texture; + } frames[1]; +}; + +struct FDoorAnimation +{ + FTextureID BaseTexture; + FTextureID *TextureFrames; + int NumTextureFrames; + FName OpenSound; + FName CloseSound; +}; + + // Patches. // A patch holds one or more columns. @@ -205,13 +259,13 @@ public: int GetScaledWidth () { int foo = (Width << 17) / xScale; return (foo >> 1) + (foo & 1); } int GetScaledHeight () { int foo = (Height << 17) / yScale; return (foo >> 1) + (foo & 1); } - double GetScaledWidthDouble () { return (Width * 65536.f) / xScale; } - double GetScaledHeightDouble () { return (Height * 65536.f) / yScale; } + double GetScaledWidthDouble () { return (Width * 65536.) / xScale; } + double GetScaledHeightDouble () { return (Height * 65536.) / yScale; } int GetScaledLeftOffset () { int foo = (LeftOffset << 17) / xScale; return (foo >> 1) + (foo & 1); } int GetScaledTopOffset () { int foo = (TopOffset << 17) / yScale; return (foo >> 1) + (foo & 1); } - double GetScaledLeftOffsetDouble() { return (LeftOffset * 65536.f) / xScale; } - double GetScaledTopOffsetDouble() { return (TopOffset * 65536.f) / yScale; } + double GetScaledLeftOffsetDouble() { return (LeftOffset * 65536.) / xScale; } + double GetScaledTopOffsetDouble() { return (TopOffset * 65536.) / yScale; } virtual void SetFrontSkyLayer(); @@ -362,18 +416,6 @@ public: return Textures[Translation[i]].Texture; } - void SetTranslation (FTextureID fromtexnum, FTextureID totexnum) - { - if ((size_t)fromtexnum.texnum < Translation.Size()) - { - if ((size_t)totexnum.texnum >= Textures.Size()) - { - totexnum.texnum = fromtexnum.texnum; - } - Translation[fromtexnum.texnum] = totexnum.texnum; - } - } - enum { TEXMAN_TryAny = 1, @@ -390,7 +432,6 @@ public: void AddTexturesLumps (int lump1, int lump2, int patcheslump); void AddGroup(int wadnum, int ns, int usetype); void AddPatches (int lumpnum); - void AddTiles (void *tileFile); void AddHiresTextures (int wadnum); void LoadTextureDefs(int wadnum, const char *lumpname); void ParseXTexture(FScanner &sc, int usetype); @@ -404,6 +445,7 @@ public: void LoadTextureX(int wadnum); void AddTexturesForWad(int wadnum); void Init(); + void DeleteAll(); // Replaces one texture with another. The new texture will be assigned // the same name, slot, and use type as the texture it is replacing. @@ -421,8 +463,49 @@ public: void WriteTexture (FArchive &arc, int picnum); int ReadTexture (FArchive &arc); + void UpdateAnimations (DWORD mstime); + int GuesstimateNumTextures (); + + FSwitchDef *FindSwitch (FTextureID texture); + FDoorAnimation *FindAnimatedDoor (FTextureID picnum); private: + + // texture counting + int CountTexturesX (); + int CountLumpTextures (int lumpnum); + + // Build tiles + void AddTiles (void *tiles); + int CountTiles (void *tiles); + int CountBuildTiles (); + void InitBuildTiles (); + + // Animation stuff + void AddAnim (FAnimDef *anim); + void FixAnimations (); + void InitAnimated (); + void InitAnimDefs (); + void AddSimpleAnim (FTextureID picnum, int animcount, int animtype, DWORD speedmin, DWORD speedrange=0); + void AddComplexAnim (FTextureID picnum, const TArray &frames); + void ParseAnim (FScanner &sc, int usetype); + void ParseRangeAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing); + void ParsePicAnim (FScanner &sc, FTextureID picnum, int usetype, bool missing, TArray &frames); + void ParseWarp(FScanner &sc); + void ParseCameraTexture(FScanner &sc); + FTextureID ParseFramenum (FScanner &sc, FTextureID basepicnum, int usetype, bool allowMissing); + void ParseTime (FScanner &sc, DWORD &min, DWORD &max); + FTexture *Texture(FTextureID id) { return Textures[id.GetIndex()].Texture; } + void SetTranslation (FTextureID fromtexnum, FTextureID totexnum); + void ParseAnimatedDoor(FScanner &sc); + + // Switches + + void InitSwitchList (); + void ProcessSwitchDef (FScanner &sc); + FSwitchDef *ParseSwitchDef (FScanner &sc, bool ignoreBad); + void AddSwitchPair (FSwitchDef *def1, FSwitchDef *def2); + struct TextureHash { FTexture *Texture; @@ -434,6 +517,11 @@ private: int HashFirst[HASH_SIZE]; FTextureID DefaultTexture; TArray FirstTextureForFile; + + TArray mAnimations; + TArray mSwitchDefs; + TArray mAnimatedDoors; + TArray BuildTileFiles; }; extern FTextureManager TexMan; diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 6362c62f..0d9dfad3 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -337,6 +337,9 @@ void LoadActors () { int lastlump, lump; + StateParams.Clear(); + GlobalSymbols.ReleaseSymbols(); + DropItemList.Clear(); FScriptPosition::ResetErrorCounter(); InitThingdef(); lastlump = 0; diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 6b212414..41925b71 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -123,7 +123,8 @@ class FStateExpressions TArray expressions; public: - ~FStateExpressions(); + ~FStateExpressions() { Clear(); } + void Clear(); int Add(FxExpression *x, const PClass *o, bool c); int Reserve(int num, const PClass *cls); void Set(int num, FxExpression *x, bool cloned = false); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 1ac84d38..a40c4946 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -2020,6 +2020,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo) } } +//=========================================================================== +// +// A_Scale(float scalex, optional float scaley) +// +// Scales the actor's graphics. If scaley is 0, use scalex. +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetScale) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_FIXED(scalex, 0); + ACTION_PARAM_FIXED(scaley, 1); + + self->scaleX = scalex; + self->scaleY = scaley ? scaley : scalex; +} + //=========================================================================== // // A_SpawnDebris @@ -2632,6 +2649,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2))) { + return; // [KS] Outside of FOV - return } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 54de97aa..f85d5cd6 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -279,12 +279,13 @@ static FFlagDef InventoryFlags[] = DEFINE_FLAG(IF, UNDROPPABLE, AInventory, ItemFlags), DEFINE_FLAG(IF, INVBAR, AInventory, ItemFlags), DEFINE_FLAG(IF, HUBPOWER, AInventory, ItemFlags), + DEFINE_FLAG(IF, UNTOSSABLE, AInventory, ItemFlags), + DEFINE_FLAG(IF, ADDITIVETIME, AInventory, ItemFlags), DEFINE_FLAG(IF, ALWAYSPICKUP, AInventory, ItemFlags), DEFINE_FLAG(IF, FANCYPICKUPSOUND, AInventory, ItemFlags), DEFINE_FLAG(IF, BIGPOWERUP, AInventory, ItemFlags), DEFINE_FLAG(IF, KEEPDEPLETED, AInventory, ItemFlags), DEFINE_FLAG(IF, IGNORESKILL, AInventory, ItemFlags), - DEFINE_FLAG(IF, ADDITIVETIME, AInventory, ItemFlags), DEFINE_FLAG(IF, NOATTENPICKUPSOUND, AInventory, ItemFlags), DEFINE_FLAG(IF, PERSISTENTPOWER, AInventory, ItemFlags), @@ -584,6 +585,7 @@ void InitThingdef() } // Create a sorted list of properties + if (properties.Size() == 0) { FAutoSegIterator probe(GRegHead, GRegTail); @@ -596,6 +598,7 @@ void InitThingdef() } // Create a sorted list of native action functions + if (AFTable.Size() == 0) { FAutoSegIterator probe(ARegHead, ARegTail); @@ -608,6 +611,7 @@ void InitThingdef() } // Create a sorted list of native variables + if (variables.Size() == 0) { FAutoSegIterator probe(MRegHead, MRegTail); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 9440a05b..5f7238e2 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -77,6 +77,8 @@ DEFINE_MEMBER_VARIABLE(velz, AActor) DEFINE_MEMBER_VARIABLE_ALIAS(momx, velx, AActor) DEFINE_MEMBER_VARIABLE_ALIAS(momy, vely, AActor) DEFINE_MEMBER_VARIABLE_ALIAS(momz, velz, AActor) +DEFINE_MEMBER_VARIABLE(scaleX, AActor) +DEFINE_MEMBER_VARIABLE(scaleY, AActor) DEFINE_MEMBER_VARIABLE(Damage, AActor) DEFINE_MEMBER_VARIABLE(Score, AActor) @@ -675,6 +677,7 @@ FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx) { CHECKRESOLVED(); if (Operand) + { Operand = Operand->ResolveAsBoolean(ctx); } @@ -2762,7 +2765,7 @@ FStateExpressions StateParams; // //========================================================================== -FStateExpressions::~FStateExpressions() +void FStateExpressions::Clear() { for(unsigned i=0; i= 0 && Wads.LumpLength (lump) >= 768) { @@ -780,6 +781,7 @@ static void FreeSpecialLights() delete[] colormap->Maps; delete colormap; } + NormalLight.Next = NULL; } // Builds NUMCOLORMAPS colormaps lit with the specified color diff --git a/src/v_text.h b/src/v_text.h index 494ebb31..29dfa627 100644 --- a/src/v_text.h +++ b/src/v_text.h @@ -67,6 +67,7 @@ struct FBrokenLines #define TEXTCOLOR_DARKBROWN "\034S" #define TEXTCOLOR_PURPLE "\034T" #define TEXTCOLOR_DARKGRAY "\034U" +#define TEXTCOLOR_CYAN "\034V" #define TEXTCOLOR_NORMAL "\034-" #define TEXTCOLOR_BOLD "\034+" diff --git a/src/v_video.cpp b/src/v_video.cpp index c2709c62..25b3a89c 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1399,6 +1399,16 @@ int DFrameBuffer::GetMaxViewPitch(bool down) return down? MAX_DN_ANGLE*ANGLE_1 : -MAX_UP_ANGLE*ANGLE_1; } +//========================================================================== +// +// DFrameBuffer :: GameRestart +// +//========================================================================== + +void DFrameBuffer::GameRestart() +{ +} + //=========================================================================== // // @@ -1620,7 +1630,7 @@ CCMD (vid_setmode) // V_Init // -void V_Init (void) +void V_Init (bool restart) { const char *i; int width, height, bits; @@ -1630,40 +1640,43 @@ void V_Init (void) // [RH] Initialize palette management InitPalette (); - width = height = bits = 0; - - if ( (i = Args->CheckValue ("-width")) ) - width = atoi (i); - - if ( (i = Args->CheckValue ("-height")) ) - height = atoi (i); - - if ( (i = Args->CheckValue ("-bits")) ) - bits = atoi (i); - - if (width == 0) + if (!restart) { - if (height == 0) + width = height = bits = 0; + + if ( (i = Args->CheckValue ("-width")) ) + width = atoi (i); + + if ( (i = Args->CheckValue ("-height")) ) + height = atoi (i); + + if ( (i = Args->CheckValue ("-bits")) ) + bits = atoi (i); + + if (width == 0) { - width = vid_defwidth; - height = vid_defheight; + if (height == 0) + { + width = vid_defwidth; + height = vid_defheight; + } + else + { + width = (height * 8) / 6; + } } - else + else if (height == 0) { - width = (height * 8) / 6; + height = (width * 6) / 8; } - } - else if (height == 0) - { - height = (width * 6) / 8; + + if (bits == 0) + { + bits = vid_defbits; + } + screen = new DDummyFrameBuffer (width, height); } - if (bits == 0) - { - bits = vid_defbits; - } - - screen = new DDummyFrameBuffer (width, height); BuildTransTable (GPalette.BaseColors); } @@ -1708,10 +1721,7 @@ void V_Shutdown() s->ObjectFlags |= OF_YesReallyDelete; delete s; } - while (FFont::FirstFont != NULL) - { - delete FFont::FirstFont; - } + V_ClearFonts(); } EXTERN_CVAR (Bool, vid_tft) diff --git a/src/v_video.h b/src/v_video.h index 684b5e36..2c0861c5 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -410,6 +410,9 @@ public: virtual void GetHitlist(BYTE *hitlist); virtual void PrecacheTexture(FTexture *tex, int cache); + // Report a game restart + virtual void GameRestart(); + // Screen wiping virtual bool WipeStartScreen(int type); virtual void WipeEndScreen(); @@ -476,7 +479,7 @@ extern "C" DWORD Col2RGB8_Inverse[65][256]; // --111111111111111111111111111111 = 0x3FFFFFFF // Allocates buffer screens, call before R_Init. -void V_Init (); +void V_Init (bool restart); // Initializes graphics mode for the first time. void V_Init2 (); diff --git a/src/version.h b/src/version.h index cf688125..6677e016 100644 --- a/src/version.h +++ b/src/version.h @@ -41,15 +41,15 @@ /** Lots of different version numbers **/ -#define DOTVERSIONSTR_NOREV "1.5.3" +#define DOTVERSIONSTR_NOREV "1.5.6" #define ZDVER_STRING "2.5.0" // The version string the user actually sees. #define DOTVERSIONSTR DOTVERSIONSTR_NOREV " (r" SVN_REVISION_STRING ") / ZDoom " ZDVER_STRING " (r" ZD_SVN_REVISION_STRING ")" // The version as seen in the Windows resource -#define RC_FILEVERSION 1,5,3,SVN_REVISION_NUMBER -#define RC_PRODUCTVERSION 1,5,3,0 +#define RC_FILEVERSION 1,5,6,SVN_REVISION_NUMBER +#define RC_PRODUCTVERSION 1,5,6,0 #define RC_FILEVERSION2 DOTVERSIONSTR #define RC_PRODUCTVERSION2 "1.5" @@ -77,17 +77,21 @@ // SAVESIG should match SAVEVER. // MINSAVEVER is the minimum level snapshot version that can be loaded. -#define MINSAVEVER 1848 +#define MINSAVEVER 3030 #if ZD_SVN_REVISION_NUMBER < MINSAVEVER -// Never write a savegame with a version lower than what we need -#define SAVEVER MINSAVEVER +// If we don't know the current revision write something very high to ensure that +// the reesulting executable can read its own savegames but no regular engine can. +#define SAVEVER 999999 #define SAVESIG MakeSaveSig() static inline const char *MakeSaveSig() { static char foo[] = { 'Z','D','O','O','M','S','A','V','E', +#if SAVEVER > 99999 + '0' + (SAVEVER / 100000), +#endif #if SAVEVER > 9999 - '0' + (SAVEVER / 10000), + '0' + ((SAVEVER / 10000) % 10), #endif #if SAVEVER > 999 '0' + ((SAVEVER / 1000) % 10), diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 7c07ae78..dbf8446a 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -47,6 +47,7 @@ #include "gi.h" #include "r_translate.h" #include "templates.h" +#include "gstrings.h" // States for the intermission typedef enum @@ -79,7 +80,7 @@ void WI_unloadData (); // NET GAME STUFF #define NG_STATSY 50 -#define NG_STATSX (32 + star->GetWidth()/2 + 32*!dofrags) +#define NG_STATSX (32 + star->GetScaledWidth()/2 + 32*!dofrags) #define NG_SPACINGX 64 @@ -206,10 +207,39 @@ static bool noautostartmap; // GRAPHICS // +struct FPatchInfo +{ + FFont *mFont; + FTexture *mPatch; + EColorRange mColor; + + void Init(FGIFont &gifont) + { + if (gifont.color == NAME_Null) + { + mPatch = TexMan[gifont.fontname]; // "entering" + mColor = mPatch == NULL? CR_UNTRANSLATED : CR_UNDEFINED; + mFont = NULL; + } + else + { + mFont = V_GetFont(gifont.fontname); + mColor = V_FindFontColor(gifont.color); + mPatch = NULL; + } + if (mFont == NULL) + { + mFont = BigFont; + } + } +}; + +static FPatchInfo mapname; +static FPatchInfo finished; +static FPatchInfo entering; + static TArray yah; // You Are Here graphic static FTexture* splat; // splat -static FTexture* finished; // "Finished!" graphics -static FTexture* entering; // "Entering" graphic static FTexture* sp_secret; // "secret" static FTexture* kills; // "Kills", "Scrt", "Items", "Frags" static FTexture* secret; @@ -606,8 +636,8 @@ void WI_drawBackground() // scale all animations below to fit the size of the base pic // The base pic is always scaled to fit the screen so this allows // placing the animations precisely where they belong on the base pic - animwidth = background->GetScaledWidth(); - animheight = background->GetScaledHeight(); + animwidth = background->GetScaledWidthDouble(); + animheight = background->GetScaledHeightDouble(); screen->FillBorder (NULL); screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE); } @@ -697,34 +727,67 @@ static int WI_DrawCharPatch (FFont *font, int charcode, int x, int y, EColorRang // //==================================================================== -int WI_DrawName(int y, const char *levelname) +int WI_DrawName(int y, FTexture *tex, const char *levelname) { - int i; - size_t l; - const char *p; - int h = 0; - int lumph; - - lumph = BigFont->GetHeight() * CleanYfac; - - p = levelname; - if (!p) return 0; - l = strlen(p); - if (!l) return 0; - - FBrokenLines *lines = V_BreakLines(BigFont, screen->GetWidth() / CleanXfac, p); - - if (lines) + // draw + if (tex) { - for (i = 0; lines[i].Width >= 0; i++) - { - screen->DrawText(BigFont, CR_UNTRANSLATED, (SCREENWIDTH - lines[i].Width * CleanXfac) / 2, y + h, - lines[i].Text, DTA_CleanNoMove, true, TAG_DONE); - h += lumph; - } - V_FreeBrokenLines(lines); + screen->DrawTexture(tex, (screen->GetWidth() - tex->GetScaledWidth()*CleanXfac) /2, y, DTA_CleanNoMove, true, TAG_DONE); + return y + (tex->GetScaledHeight() + BigFont->GetHeight()/4) * CleanYfac; + } + else + { + int i; + size_t l; + const char *p; + int h = 0; + int lumph; + + lumph = mapname.mFont->GetHeight() * CleanYfac; + + p = levelname; + if (!p) return 0; + l = strlen(p); + if (!l) return 0; + + FBrokenLines *lines = V_BreakLines(mapname.mFont, screen->GetWidth() / CleanXfac, p); + + if (lines) + { + for (i = 0; lines[i].Width >= 0; i++) + { + screen->DrawText(mapname.mFont, mapname.mColor, (SCREENWIDTH - lines[i].Width * CleanXfac) / 2, y + h, + lines[i].Text, DTA_CleanNoMove, true, TAG_DONE); + h += lumph; + } + V_FreeBrokenLines(lines); + } + return y + h + lumph/4; + } +} + +//==================================================================== +// +// Draws a text, either as patch or as string from the string table +// +//==================================================================== + +int WI_DrawPatchText(int y, FPatchInfo *pinfo, const char *stringname) +{ + const char *string = GStrings(stringname); + int midx = screen->GetWidth() / 2; + + if (pinfo->mPatch != NULL) + { + screen->DrawTexture(pinfo->mPatch, midx - pinfo->mPatch->GetScaledWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE); + return y + (pinfo->mPatch->GetScaledHeight() * CleanYfac); + } + else + { + screen->DrawText(pinfo->mFont, pinfo->mColor, midx - pinfo->mFont->StringWidth(string)*CleanXfac/2, + y, string, DTA_CleanNoMove, true, TAG_DONE); + return y + pinfo->mFont->GetHeight() * CleanYfac; } - return h + lumph/4; } @@ -736,41 +799,21 @@ int WI_DrawName(int y, const char *levelname) // A level name patch can be specified for all games now, not just Doom. // //==================================================================== + int WI_drawLF () { int y = WI_TITLEY * CleanYfac; - int midx = screen->GetWidth() / 2; - FTexture *tex = wbs->LName0; - - // draw - if (tex) - { - screen->DrawTexture(tex, midx - tex->GetWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE); - y += (tex->GetHeight() + BigFont->GetHeight()/4) * CleanYfac; - } - else - { - y += WI_DrawName(y, lnametexts[0]); - } + y = WI_DrawName(y, wbs->LName0, lnametexts[0]); + // Adjustment for different font sizes for map name and 'finished'. + y -= ((mapname.mFont->GetHeight() - finished.mFont->GetHeight()) * CleanYfac) / 4; + // draw "Finished!" - FFont *font = gameinfo.gametype & GAME_Raven ? SmallFont : BigFont; - if (y < (NG_STATSY - font->GetHeight()*3/4) * CleanYfac) + if (y < (NG_STATSY - finished.mFont->GetHeight()*3/4) * CleanYfac) { - // don't draw 'finished' if the level name is too high! - if (gameinfo.gametype & GAME_DoomChex) - { - screen->DrawTexture(finished, midx - finished->GetWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE); - return y + finished->GetHeight() * CleanYfac; - } - else - { - screen->DrawText(font, CR_WHITE, - midx - font->StringWidth("finished")*CleanXfac/2, y - 4*CleanYfac, "finished", - DTA_CleanNoMove, true, TAG_DONE); - return y + font->GetHeight() * CleanYfac; - } + // don't draw 'finished' if the level name is too tall + y = WI_DrawPatchText(y, &finished, "WI_FINISHED"); } return y; } @@ -784,36 +827,14 @@ int WI_drawLF () // A level name patch can be specified for all games now, not just Doom. // //==================================================================== + void WI_drawEL () { int y = WI_TITLEY * CleanYfac; - FFont *font = gameinfo.gametype & GAME_Raven ? SmallFont : BigFont; - // draw "entering" - // be careful with the added height so that it works for oversized 'entering' patches! - if (gameinfo.gametype & GAME_DoomChex) - { - screen->DrawTexture(entering, (SCREENWIDTH - entering->GetWidth() * CleanXfac) / 2, y, DTA_CleanNoMove, true, TAG_DONE); - y += (entering->GetHeight() + font->GetHeight()/4) * CleanYfac; - } - else - { - screen->DrawText(font, CR_WHITE, - (SCREENWIDTH - font->StringWidth("now entering:") * CleanXfac) / 2, y, - "now entering:", DTA_CleanNoMove, true, TAG_DONE); - y += font->GetHeight()*5*CleanYfac/4; - } - - // draw - FTexture *tex = wbs->LName1; - if (tex) - { - screen->DrawTexture(tex, (SCREENWIDTH - tex->GetWidth() * CleanXfac) / 2, y, DTA_CleanNoMove, true, TAG_DONE); - } - else - { - WI_DrawName(y, lnametexts[1]); - } + y = WI_DrawPatchText(y, &entering, "WI_ENTERING"); + y += entering.mFont->GetHeight() * CleanYfac / 4; + WI_DrawName(y, wbs->LName1, lnametexts[1]); } @@ -853,10 +874,10 @@ void WI_drawOnLnode( int n, FTexture * c[] ,int numc) int bottom; - right = c[i]->GetWidth(); - bottom = c[i]->GetHeight(); - left = lnodes[n].x - c[i]->LeftOffset; - top = lnodes[n].y - c[i]->TopOffset; + right = c[i]->GetScaledWidth(); + bottom = c[i]->GetScaledHeight(); + left = lnodes[n].x - c[i]->GetScaledLeftOffset(); + top = lnodes[n].y - c[i]->GetScaledTopOffset(); right += left; bottom += top; @@ -980,7 +1001,7 @@ void WI_drawTime (int x, int y, int t, bool no_sucks=false) { // "sucks" if (sucks != NULL) { - screen->DrawTexture (sucks, x - sucks->GetWidth(), y - IntermissionFont->GetHeight() - 2, + screen->DrawTexture (sucks, x - sucks->GetScaledWidth(), y - IntermissionFont->GetHeight() - 2, DTA_Clean, true, TAG_DONE); } else @@ -1905,12 +1926,15 @@ void WI_Ticker(void) } } + void WI_loadData(void) { + entering.Init(gameinfo.mStatscreenEnteringFont); + finished.Init(gameinfo.mStatscreenFinishedFont); + mapname.Init(gameinfo.mStatscreenMapNameFont); + if (gameinfo.gametype & GAME_DoomChex) { - finished = TexMan["WIF"]; // "finished" - entering = TexMan["WIENTER"]; // "entering" kills = TexMan["WIOSTK"]; // "kills" secret = TexMan["WIOSTS"]; // "scrt" sp_secret = TexMan["WISCRT2"]; // "secret" diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 7453571e..b0f25bbe 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -2763,7 +2763,7 @@ void D3DFB::Clear (int left, int top, int right, int bottom, int palcolor, uint3 { return; } - if (palcolor >= 0) + if (palcolor >= 0 && color == 0) { color = GPalette.BaseColors[palcolor]; } @@ -3677,6 +3677,14 @@ bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR & alpha = clamp (parms.alpha, 0, FRACUNIT) / 65536.f; } + style.CheckFuzz(); + if (style.BlendOp == STYLEOP_Shadow) + { + style = LegacyRenderStyles[STYLE_TranslucentStencil]; + alpha = 0.3f; + parms.fillcolor = 0; + } + // FIXME: Fuzz effect is not written if (style.BlendOp == STYLEOP_FuzzOrAdd || style.BlendOp == STYLEOP_Fuzz) { diff --git a/src/win32/i_mouse.cpp b/src/win32/i_mouse.cpp index 873b9271..4ed34723 100644 --- a/src/win32/i_mouse.cpp +++ b/src/win32/i_mouse.cpp @@ -118,7 +118,6 @@ extern int BlockMouseMove; // PRIVATE DATA DEFINITIONS ------------------------------------------------ -static bool NativeMouse; static EMouseMode MouseMode = MM_None; static FMouse *(*MouseFactory[])() = { @@ -130,6 +129,7 @@ static FMouse *(*MouseFactory[])() = // PUBLIC DATA DEFINITIONS ------------------------------------------------- FMouse *Mouse; +bool NativeMouse; bool CursorState; diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index b585be71..1da4855c 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -131,6 +131,7 @@ extern HANDLE StdOut; extern bool FancyStdOut; extern HINSTANCE g_hInst; extern FILE *Logfile; +extern bool NativeMouse; // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -1214,6 +1215,23 @@ bool I_SetCursor(FTexture *cursorpic) cursor = LoadCursor(NULL, IDC_ARROW); } SetClassLongPtr(Window, GCLP_HCURSOR, (LONG_PTR)cursor); + if (NativeMouse) + { + POINT pt; + RECT client; + + // If the mouse pointer is within the window's client rect, set it now. + if (GetCursorPos(&pt) && GetClientRect(Window, &client) && + ClientToScreen(Window, (LPPOINT)&client.left) && + ClientToScreen(Window, (LPPOINT)&client.right)) + { + if (pt.x >= client.left && pt.x < client.right && + pt.y >= client.top && pt.y < client.bottom) + { + SetCursor(cursor); + } + } + } return true; } diff --git a/src/win32/zdoom.rc b/src/win32/zdoom.rc index d6602a10..881166a8 100644 --- a/src/win32/zdoom.rc +++ b/src/win32/zdoom.rc @@ -71,7 +71,7 @@ BEGIN " VALUE ""FileDescription"", ""GZDoom""\r\n" " VALUE ""FileVersion"", RC_FILEVERSION2\r\n" " VALUE ""InternalName"", ""GZDoom""\r\n" - " VALUE ""LegalCopyright"", ""Copyright © 1993-1996, id Software, 1998-2005, Randy Heit, 2002-2006 Christoph Oelckers""\r\n" + " VALUE ""LegalCopyright"", ""Copyright © 1993-1996, id Software, 1998-2010, Randy Heit, 2002-2010 Christoph Oelckers""\r\n" " VALUE ""LegalTrademarks"", ""Doom® is a Registered Trademark of id Software, Inc.""\r\n" " VALUE ""OriginalFilename"", ""gzdoom.exe""\r\n" " VALUE ""ProductName"", ""GZDoom""\r\n" @@ -490,7 +490,7 @@ BEGIN VALUE "FileDescription", "GZDoom" VALUE "FileVersion", RC_FILEVERSION2 VALUE "InternalName", "GZDoom" - VALUE "LegalCopyright", "Copyright © 1993-1996, id Software, 1998-2005, Randy Heit, 2002-2006 Christoph Oelckers" + VALUE "LegalCopyright", "Copyright © 1993-1996, id Software, 1998-2010, Randy Heit, 2002-2010 Christoph Oelckers" VALUE "LegalTrademarks", "Doom® is a Registered Trademark of id Software, Inc." VALUE "OriginalFilename", "gzdoom.exe" VALUE "ProductName", "GZDoom" diff --git a/src/xlat/parse_xlat.cpp b/src/xlat/parse_xlat.cpp index 6221c549..5edcde58 100644 --- a/src/xlat/parse_xlat.cpp +++ b/src/xlat/parse_xlat.cpp @@ -156,16 +156,23 @@ struct XlatParseContext : public FParseContext // //========================================================================== +void P_ClearTranslator() +{ + SimpleLineTranslations.Clear(); + NumBoomish = 0; + SectorTranslations.Clear(); + SectorMasks.Clear(); + memset(LineFlagTranslations, 0, sizeof(LineFlagTranslations)); + LastTranslator = ""; +} + void P_LoadTranslator(const char *lumpname) { // Only read the lump if it differs from the previous one. if (LastTranslator.CompareNoCase(lumpname)) { // Clear the old data before parsing the lump. - SimpleLineTranslations.Clear(); - NumBoomish = 0; - SectorTranslations.Clear(); - SectorMasks.Clear(); + P_ClearTranslator(); void *pParser = XlatParseAlloc(malloc); @@ -179,3 +186,5 @@ void P_LoadTranslator(const char *lumpname) LastTranslator = lumpname; } } + + diff --git a/tools/zipdir/zipdir.c b/tools/zipdir/zipdir.c index 62c62a5a..ae4738b0 100644 --- a/tools/zipdir/zipdir.c +++ b/tools/zipdir/zipdir.c @@ -610,6 +610,7 @@ dir_tree_t *add_dirs(char **argv) { // Skip hidden directories. (Prevents SVN bookkeeping // info from being included.) + // [BL] Also skip backup files. fts_set(fts, ent, FTS_SKIP); } if (ent->fts_info == FTS_D && ent->fts_level == 0) @@ -628,6 +629,11 @@ dir_tree_t *add_dirs(char **argv) // We're only interested in remembering files. continue; } + else if(ent->fts_name[strlen(ent->fts_name)-1] == '~') + { + // Don't remember backup files. + continue; + } file = alloc_file_entry("", ent->fts_path, ent->fts_statp->st_mtime); if (file == NULL) { diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index fb065552..f8dd3d86 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -47,6 +47,8 @@ ACTOR Actor native //: Thinker native fixed_t momx; // alias for velx native fixed_t momy; // alias for vely native fixed_t momz; // alias for velz + native fixed_t scaleX; + native fixed_t scaleY; native int score; // Meh, MBF redundant functions. Only for DeHackEd support. @@ -204,6 +206,7 @@ ACTOR Actor native //: Thinker action native A_FadeIn(float reduce = 0.1); action native A_FadeOut(float reduce = 0.1, bool remove = true); action native A_FadeTo(float target, float amount = 0.1, bool remove = false); + action native A_SetScale(float scalex, float scaley = 0); action native A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); action native A_CheckSight(state label); action native A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); diff --git a/wadsrc/static/actors/shared/soundsequence.txt b/wadsrc/static/actors/shared/soundsequence.txt index 871bd724..ff240ba9 100644 --- a/wadsrc/static/actors/shared/soundsequence.txt +++ b/wadsrc/static/actors/shared/soundsequence.txt @@ -6,6 +6,11 @@ ACTOR AmbientSound 14065 native +DONTSPLASH } +ACTOR AmbientSoundNoGravity : AmbientSound 14067 +{ + +NOGRAVITY +} + ACTOR SoundSequenceSlot native { +NOSECTOR diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 98528363..14cda796 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -53,6 +53,7 @@ F84AB4557464A383E93F37CD3A82AC48 // MM2 map03 } 2FE901F659A16E58D7BCD7C30021C238 // AV map15 +74AF92E96FE10D039D31C1F6526D7D7C // Real World map11 { trace } @@ -135,3 +136,7 @@ DCE862393CAAA6FF1294FB7056B53057 // UAC Ultra map07: Contains a scroller dependi setlinespecial 391 Sector_CopyScroller 99 6 0 0 0 } +1D9E43988940CCD3555724E15DD8B1AB // Happy Time Circus map01 has bad teleporters +{ + ignoreteleporttags +} diff --git a/wadsrc/static/fontdefs.txt b/wadsrc/static/fontdefs.txt index 19e53eff..a8e99bb3 100644 --- a/wadsrc/static/fontdefs.txt +++ b/wadsrc/static/fontdefs.txt @@ -4,6 +4,7 @@ HUDFONT_DOOM { - STTMINUS + % STTPRCNT 0 STTNUM0 1 STTNUM1 2 STTNUM2 diff --git a/wadsrc/static/iwadinfo.txt b/wadsrc/static/iwadinfo.txt index 47001257..efdf836a 100644 --- a/wadsrc/static/iwadinfo.txt +++ b/wadsrc/static/iwadinfo.txt @@ -25,7 +25,7 @@ IWad Name = "Action Doom 2: Urban Brawl" Game = "Doom" Config = "UrbanBrawl" - Mapinfo = "mapinfo/doom2.txt" + Mapinfo = "mapinfo/urbanbrawl.txt" MustContain = "MAP01", "AD2LIB" BannerColors = "a8 a8 00", "a8 00 00" } @@ -216,7 +216,7 @@ IWad Autoname = "Doom1" Game = "Doom" Config = "Doom" - Mapinfo = "mapinfo/doom1.txt" + Mapinfo = "mapinfo/ultdoom.txt" Compatibility = "Shorttex" MustContain = "E1M1","E2M1","E2M2","E2M3","E2M4","E2M5","E2M6","E2M7","E2M8","E2M9", "E3M1","E3M2","E3M3","E3M4","E3M5","E3M6","E3M7","E3M8","E3M9", diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index f3fb2bce..3acfe404 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -737,7 +737,7 @@ OB_MPCROSSBOW = "%o was pegged by %k's ethereal crossbow."; OB_MPBLASTER = "%o was blasted a new one by %k's dragon claw."; OB_MPSKULLROD = "%o got sent down under by %k's hellstaff."; OB_MPPHOENIXROD = "%o was scorched to cinders by %k's phoenix rod."; -OB_MPMACE = "%o was bounced by $k's firemace."; +OB_MPMACE = "%o was bounced by %k's firemace."; OB_MPPSTAFF = "%o got clapped by %k's charged staff."; OB_MPPGAUNTLETS = "%o was bled dry by %k's gauntlets."; @@ -1563,6 +1563,9 @@ $ifgame(heretic) SWSTRING = "ONLY AVAILABLE IN THE REGISTERED VERSION"; MNU_EPISODE = "Select Episode"; +WI_FINISHED = "finished"; +WI_ENTERING = "Now entering:"; + // Bloodbath announcer BBA_BONED = "%k boned %o like a fish"; diff --git a/wadsrc/static/maparrows/arrow.txt b/wadsrc/static/maparrows/arrow.txt new file mode 100644 index 00000000..742d344e --- /dev/null +++ b/wadsrc/static/maparrows/arrow.txt @@ -0,0 +1,7 @@ +(-0.875, 0), (1, 0) // ----- +(1, 0), (0.5, 0.25) // -----> +(1, 0), (0.5, -0.25) +(-0.875, 0), (-1.125, -0.25) // >----> +(-0.875, 0), (-1.125, 0.25) +(-0.625, 0), (-0.875, -0.25) // >>---> +(-0.625, 0), (-0.875, 0.25) diff --git a/wadsrc/static/maparrows/dagger.txt b/wadsrc/static/maparrows/dagger.txt new file mode 100644 index 00000000..0c16efc5 --- /dev/null +++ b/wadsrc/static/maparrows/dagger.txt @@ -0,0 +1,10 @@ +(-0.75, 0), (0, 0) // center line. +(-0.75, 0.125), (1, 0) // blade +(-0.75, -0.125), (1, 0 ) +(-0.75, -0.25), (-0.75, 0.25 ) // crosspiece +(-0.875, -0.25), (-0.875, 0.25 ) +(-0.875, -0.25), (-0.75, -0.25) //crosspiece connectors +(-0.875, 0.25), (-0.75, 0.25) +(-1.125, 0.125), (-1.125, -0.125 ) //pommel +(-1.125, 0.125), (-0.875, 0.125 ) +(-1.125, -0.125), (-0.875, -0.125) diff --git a/wadsrc/static/maparrows/ddtarrow.txt b/wadsrc/static/maparrows/ddtarrow.txt new file mode 100644 index 00000000..51919c72 --- /dev/null +++ b/wadsrc/static/maparrows/ddtarrow.txt @@ -0,0 +1,16 @@ +(-0.875, 0), (1, 0) // ----- +(1, 0), (0.5, 0.167) // -----> +(1, 0), (0.5, -0.167) +(-0.875, 0), (-1.125, -0.167) // >----> +(-0.875, 0), (-1.125, 0.167) +(-0.625, 0), (-0.875, -0.167) // >>---> +(-0.625, 0), (-0.875, 0.167) +(-0.5, 0), (-0.5, -0.167) // >>-d---> +(-0.5, -0.167), (-0.333, -0.167) +(-0.333, -0.167), (-0.333, 0.25) +(-0.167, 0), (-0.167, -0.167) // >>-dd--> +(-0.167, -0.167), (0, -0.167) +(0, -0.167), (0, 0.25) +(0.167, 0.25), (0.167, -0.143) // >>-ddt-> +(0.167, -0.143), (0.198, -0.174) +(0.198, -0.174), (0.267, -0.143) diff --git a/wadsrc/static/maparrows/key.txt b/wadsrc/static/maparrows/key.txt new file mode 100644 index 00000000..f252d0bf --- /dev/null +++ b/wadsrc/static/maparrows/key.txt @@ -0,0 +1,12 @@ +(-2, 0), (-1.7, -0.5) +(-1.7, -0.5), (-1.5, -0.7) +(-1.5, -0.7), (-0.8, -0.5) +(-0.8, -0.5), (-0.6, 0) +(-0.6, 0), (-0.8, 0.5) +(-1.5, 0.7), (-0.8, 0.5) +(-1.7, 0.5), (-1.5, 0.7) +(-2, 0), (-1.7, 0.5) +(-0.6, 0), (2, 0) +(1.7, 0), (1.7, -1) +(1.5, 0), (1.5, -1) +(1.3, 0), (1.3, -1) diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index 7ff6e2d6..acc4462b 100644 --- a/wadsrc/static/mapinfo/chex.txt +++ b/wadsrc/static/mapinfo/chex.txt @@ -60,6 +60,10 @@ gameinfo textscreenx = 10 textscreeny = 10 defaultendsequence = "Inter_Pic1" + maparrow = "maparrows/arrow.txt", "maparrows/ddtarrow.txt" + statscreen_mapnamefont = "BigFont" + statscreen_finishedpatch = "WIF" + statscreen_enteringpatch = "WIENTER" } skill baby diff --git a/wadsrc/static/mapinfo/doomcommon.txt b/wadsrc/static/mapinfo/doomcommon.txt index 0ad964ca..f152aa73 100644 --- a/wadsrc/static/mapinfo/doomcommon.txt +++ b/wadsrc/static/mapinfo/doomcommon.txt @@ -61,6 +61,10 @@ gameinfo textscreenx = 10 textscreeny = 10 defaultendsequence = "Inter_Cast" + maparrow = "maparrows/arrow.txt", "maparrows/ddtarrow.txt" + statscreen_mapnamefont = "BigFont" + statscreen_finishedpatch = "WIF" + statscreen_enteringpatch = "WIENTER" } skill baby diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index 0e269c8f..33ab5819 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -60,6 +60,10 @@ gameinfo textscreenx = 20 textscreeny = 5 defaultendsequence = "Inter_Pic1" + maparrow = "maparrows/dagger.txt" + statscreen_mapnamefont = "BigFont" + statscreen_finishedfont = "SmallFont" + statscreen_enteringfont = "SmallFont" } skill baby diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt index 6022c541..83202485 100644 --- a/wadsrc/static/mapinfo/hexen.txt +++ b/wadsrc/static/mapinfo/hexen.txt @@ -58,6 +58,10 @@ gameinfo textscreenx = 10 textscreeny = 5 defaultendsequence = "Inter_Chess" + maparrow = "maparrows/dagger.txt" + statscreen_mapnamefont = "BigFont" + statscreen_finishedfont = "SmallFont" + statscreen_enteringfont = "SmallFont" } skill baby diff --git a/wadsrc/static/mapinfo/strife.txt b/wadsrc/static/mapinfo/strife.txt index aed50b22..7791d736 100644 --- a/wadsrc/static/mapinfo/strife.txt +++ b/wadsrc/static/mapinfo/strife.txt @@ -60,6 +60,10 @@ gameinfo textscreenx = 10 textscreeny = 10 defaultendsequence = "Inter_Strife" + maparrow = "maparrows/arrow.txt", "maparrows/ddtarrow.txt" + statscreen_mapnamefont = "BigFont" + statscreen_finishedfont = "BigFont", "white" + statscreen_enteringfont = "BigFont", "white" } Intermission Inter_Strife_Good diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index db8d4bd4..4ddf8dfb 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -640,6 +640,13 @@ OptionValue Contrast 2.0, "Smooth" } +OptionValue Fuzziness +{ + 0.0, "Translucent" + 1.0, "Fuzz" + 2.0, "Shadow" +} + OptionMenu "VideoOptions" { Title "DISPLAY OPTIONS" @@ -662,7 +669,7 @@ OptionMenu "VideoOptions" } Option "Stretch short skies", "r_stretchsky", "OnOff" - Option "Use fuzz effect", "r_drawfuzz", "YesNo" + Option "Use fuzz effect", "r_drawfuzz", "Fuzziness" Slider "Lost Soul translucency", "transsouls", 0.25, 1.0, 0.05, 2 Option "Use fake contrast", "r_fakecontrast", "Contrast" Option "Rocket Trails", "cl_rockettrails", "RocketTrailTypes" @@ -736,6 +743,7 @@ OptionMenu "HUDOptions" Option "Display nametags", "displaynametags", "DisplayTagsTypes" Option "Nametag color", "nametagcolor", "TextColors", "displaynametags" Option "Stretch status bar", "st_scale", "OnOff" + Option "Use old ouch mug shot formula", "st_oldouch", "OnOff" } //------------------------------------------------------------------------------------------- @@ -794,9 +802,9 @@ OptionMenu "MiscOptions" { Option "Merge left+right Alt/Ctrl/Shift", "k_mergekeys", "OnOff" Option "Alt-Enter toggles fullscreen", "k_allowfullscreentoggle", "OnOff" - Option "Show IWAD selection dialog", "queryiwad", "OnOff" - StaticText " " } + Option "Show IWAD selection dialog", "queryiwad", "OnOff" + StaticText " " Option "Enable cheats from all games", "allcheats", "OnOff" Option "Enable autosaves", "disableautosave", "OffOn" Slider "Number of autosaves", "autosavecount", 1, 32, 1, 0 @@ -841,6 +849,13 @@ OptionValue OverlayTypes 2, "Overlay Only" } +OptionValue MaplabelTypes +{ + 0, "Never" + 1, "Always" + 2, "Not for hubs" +} + OptionMenu AutomapOptions { Title "AUTOMAP OPTIONS" @@ -851,6 +866,7 @@ OptionMenu AutomapOptions Option "Rotate automap", "am_rotate", "RotateTypes" Option "Overlay automap", "am_overlay", "OverlayTypes" Option "Enable textured display", "am_textured", "OnOff" + Option "Follow player", "am_followplayer", "OnOff" StaticText " " Option "Show item counts", "am_showitems", "OnOff" Option "Show monster counts", "am_showmonsters", "OnOff" @@ -858,8 +874,10 @@ OptionMenu AutomapOptions Option "Show time elapsed", "am_showtime", "OnOff" Option "Show total time elapsed", "am_showtotaltime", "OnOff" Option "Show secrets on map", "am_map_secrets", "SecretTypes" + Option "Show map label", "am_showmaplabel", "MaplabelTypes" Option "Draw map background", "am_drawmapback", "OnOff" Option "Show keys (cheat)", "am_showkeys", "OnOff" + Option "Show trigger lines", "am_showtriggerlines", "OnOff" } //------------------------------------------------------------------------------------------- @@ -912,6 +930,7 @@ OptionMenu MapColorMenu ColorPicker "Teleporter to the same map", "am_intralevelcolor" ColorPicker "Teleporter to a different map", "am_interlevelcolor" ColorPicker "Secret sector", "am_secretsectorcolor" + ColorPicker "Special trigger lines", "am_specialwallcolor" StaticText " " StaticText "Cheat Mode", 1 ColorPicker "Invisible 2-sided walls", "am_tswallcolor" @@ -929,6 +948,7 @@ OptionMenu MapColorMenu ColorPicker "Not-yet-seen walls", "am_ovunseencolor" ColorPicker "Teleporter", "am_ovtelecolor" ColorPicker "Secret sector", "am_ovsecretsectorcolor" + ColorPicker "Special trigger lines", "am_ovspecialwallcolor" StaticText " " StaticText "Overlay Cheat Mode", 1 ColorPicker "Actors", "am_ovthingcolor" @@ -1094,12 +1114,12 @@ OptionMenu GameplayOptions StaticText "Deathmatch Settings",1 Option "Weapons stay", "sv_weaponstay", "YesNo" Option "Allow powerups", "sv_noitems", "NoYes" - Option "Allow health", "sv_nohealth", "YesNo" - Option "Allow armor", "sv_noarmor", "YesNo" + Option "Allow health", "sv_nohealth", "NoYes" + Option "Allow armor", "sv_noarmor", "NoYes" Option "Spawn farthest", "sv_spawnfarthest", "YesNo" Option "Same map", "sv_samelevel", "YesNo" Option "Force respawn", "sv_forcerespawn", "YesNo" - Option "Allow exit", "sv_noexit", "YesNo" + Option "Allow exit", "sv_noexit", "NoYes" Option "Barrels respawn", "sv_barrelrespawn", "YesNo" Option "Respawn protection", "sv_respawnprotect", "YesNo" Option "Lose frag if fragged", "sv_losefrag", "YesNo" diff --git a/wadsrc/static/menudef.z b/wadsrc/static/menudef.z index 53ff7f61..e495e5da 100644 --- a/wadsrc/static/menudef.z +++ b/wadsrc/static/menudef.z @@ -124,6 +124,18 @@ OptionValue "FogMode" 2, "Radial" } +OptionValue "FuzzStyle" +{ + 0, "Shadow" + 1, "Pixel fuzz" + 2, "Smooth fuzz" + 3, "Swirly fuzz" + 4, "Translucent fuzz" + 6, "Noise" + 7, "Smooth Noise" + //5, "Jagged fuzz" I can't see any difference between this and 4 so it's disabled for now. +} + OptionMenu "GLTextureGLOptions" { Title "TEXTURE OPTIONS" @@ -166,6 +178,7 @@ OptionMenu "GLPrefOptions" Option "Force brightness in fog", gl_spritebrightfog, "OnOff" Option "Adjust sprite clipping", gl_spriteclip, "SpriteclipModes" Option "Smooth sprite edges", gl_sprite_blend, "OnOff" + Option "Fuzz Style", gl_fuzztype, "FuzzStyle" Option "Sprite billboard", gl_billboard_mode, "BillboardModes" Option "Particle style", gl_particles_style, "Particles" Slider "Ambient light level", gl_light_ambient, 1.0, 255.0, 5.0 @@ -216,7 +229,7 @@ OptionMenu "VideoOptions" } Option "Stretch short skies", "r_stretchsky", "OnOff" - Option "Use fuzz effect", "r_drawfuzz", "YesNo" + Option "Use fuzz effect", "r_drawfuzz", "Fuzziness" Slider "Lost Soul translucency", "transsouls", 0.25, 1.0, 0.05, 2 Option "Use fake contrast", "r_fakecontrast", "Contrast" Option "Rocket Trails", "cl_rockettrails", "RocketTrailTypes" diff --git a/wadsrc/static/sbarinfo/hexen.txt b/wadsrc/static/sbarinfo/hexen.txt index f1c29452..e7a4c6c4 100644 --- a/wadsrc/static/sbarinfo/hexen.txt +++ b/wadsrc/static/sbarinfo/hexen.txt @@ -59,7 +59,7 @@ statusbar Normal gamemode deathmatch, teamgame { drawimage "KILLS", 38, 163; - drawnumber 3, HUDFONT_RAVEN, untranslated, frags, 58, 163, 1; + drawnumber 3, HUDFONT_RAVEN, untranslated, frags, 65, 176, 1; } else { @@ -114,29 +114,26 @@ statusbar Normal drawimage "ARMCLS", 255, 178; drawnumber 2, HUDFONT_RAVEN, untranslated, armorclass, 275, 176, 1; - playerclass Cleric + playertype ClericPlayer { drawimage "WPSLOT1", 190, 162; - hasweaponpiece CWeapWraithverge, 1 + ininventory CWeapWraithverge { - drawimage "WPIECEC1", 190, 162; + drawimage "WPFULL1", 190, 162; } - hasweaponpiece CWeapWraithverge, 2 - { - drawimage "WPIECEC2", 212, 162; - } - hasweaponpiece CWeapWraithverge, 3 - { - drawimage "WPIECEC3", 225, 162; - } - hasweaponpiece CWeapWraithverge, 1 + else { + hasweaponpiece CWeapWraithverge, 1 + { + drawimage "WPIECEC1", 190, 162; + } hasweaponpiece CWeapWraithverge, 2 { - hasweaponpiece CWeapWraithverge, 3 - { - drawimage "WPFULL1", 190, 162; - } + drawimage "WPIECEC2", 212, 162; + } + hasweaponpiece CWeapWraithverge, 3 + { + drawimage "WPIECEC3", 225, 162; } } @@ -145,29 +142,26 @@ statusbar Normal else drawgem translatable, interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; } - else playerclass Mage + else playertype MagePlayer { drawimage "WPSLOT2", 190, 162; - hasweaponpiece MWeapBloodscourge, 1 + ininventory MWeapBloodscourge { - drawimage "WPIECEM1", 190, 162; + drawimage "WPFULL2", 190, 162; } - hasweaponpiece MWeapBloodscourge, 2 - { - drawimage "WPIECEM2", 205, 162; - } - hasweaponpiece MWeapBloodscourge, 3 - { - drawimage "WPIECEM3", 224, 162; - } - hasweaponpiece MWeapBloodscourge, 1 + else { + hasweaponpiece MWeapBloodscourge, 1 + { + drawimage "WPIECEM1", 190, 162; + } hasweaponpiece MWeapBloodscourge, 2 { - hasweaponpiece MWeapBloodscourge, 3 - { - drawimage "WPFULL2", 190, 162; - } + drawimage "WPIECEM2", 205, 162; + } + hasweaponpiece MWeapBloodscourge, 3 + { + drawimage "WPIECEM3", 224, 162; } } @@ -179,26 +173,23 @@ statusbar Normal else { drawimage "WPSLOT0", 190, 162; - hasweaponpiece FWeapQuietus, 1 + ininventory FWeapQuietus { - drawimage "WPIECEF1", 190, 162; + drawimage "WPFULL0", 190, 162; } - hasweaponpiece FWeapQuietus, 2 - { - drawimage "WPIECEF2", 225, 162; - } - hasweaponpiece FWeapQuietus, 3 - { - drawimage "WPIECEF3", 234, 162; - } - hasweaponpiece FWeapQuietus, 1 + else { + hasweaponpiece FWeapQuietus, 1 + { + drawimage "WPIECEF1", 190, 162; + } hasweaponpiece FWeapQuietus, 2 { - hasweaponpiece FWeapQuietus, 3 - { - drawimage "WPFULL0", 190, 162; - } + drawimage "WPIECEF2", 225, 162; + } + hasweaponpiece FWeapQuietus, 3 + { + drawimage "WPIECEF3", 234, 162; } } @@ -222,21 +213,21 @@ statusbar Automap drawimage hexenarmor amulet, "ARMSLOT4", 243, 164; // Also draw the life gem here - playerclass Fighter + playertype FighterPlayer { gamemode singleplayer drawgem interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; else drawgem translatable, interpolate(6), "CHAIN", "LIFEGMF2", -23, 49, 15, 30, 193; } - else playerclass Cleric + else playertype ClericPlayer { gamemode singleplayer drawgem interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; else drawgem translatable, interpolate(6), "CHAIN2", "LIFEGMC2", -23, 49, 15, 30, 193; } - else playerclass Mage + else playertype MagePlayer { gamemode singleplayer drawgem interpolate(6), "CHAIN3", "LIFEGMM2", -23, 49, 15, 30, 193; diff --git a/wadsrc/static/shaders/glsl/fuzz_jagged.fp b/wadsrc/static/shaders/glsl/fuzz_jagged.fp new file mode 100644 index 00000000..6f44a012 --- /dev/null +++ b/wadsrc/static/shaders/glsl/fuzz_jagged.fp @@ -0,0 +1,25 @@ +//created by Evil Space Tomato +uniform float timer; + +vec4 Process(vec4 color) +{ + vec2 texCoord = gl_TexCoord[0].st; + + vec2 texSplat; + const float pi = 3.14159265358979323846; + texSplat.x = texCoord.x + mod(sin(pi * 2.0 * (texCoord.y + timer * 2.0)),0.1) * 0.1; + texSplat.y = texCoord.y + mod(cos(pi * 2.0 * (texCoord.x + timer * 2.0)),0.1) * 0.1; + + vec4 basicColor = getTexel(texSplat) * color; + + float texX = sin(texCoord.x * 100 + timer*5); + float texY = cos(texCoord.x * 100 + timer*5); + float vX = (texX/texY)*21.0f; + float vY = (texY/texX)*13.0f; + + float test = mod(timer*2.0f+(vX + vY), 0.5f); + + basicColor.a = basicColor.a * test; + + return basicColor; +} diff --git a/wadsrc/static/shaders/glsl/fuzz_noise.fp b/wadsrc/static/shaders/glsl/fuzz_noise.fp new file mode 100644 index 00000000..3f452e72 --- /dev/null +++ b/wadsrc/static/shaders/glsl/fuzz_noise.fp @@ -0,0 +1,22 @@ +//created by Evil Space Tomato +uniform float timer; + +vec4 Process(vec4 color) +{ + vec2 texCoord = gl_TexCoord[0].st; + vec4 basicColor = getTexel(texCoord) * color; + + texCoord.x = int(texCoord.x * 128) / 128.0f; + texCoord.y = int(texCoord.y * 128) / 128.0f; + + float texX = sin(mod(texCoord.x * 100 + timer*5, 3.489)) + texCoord.x / 4; + float texY = cos(mod(texCoord.y * 100 + timer*5, 3.489)) + texCoord.y / 4; + float vX = (texX/texY)*21.0f; + float vY = (texY/texX)*13.0f; + + + float test = mod(timer*2.0f+(vX + vY), 0.5f); + basicColor.a = basicColor.a * test; + basicColor.rgb = vec3(0.0f,0.0f,0.0f); + return basicColor; +} diff --git a/wadsrc/static/shaders/glsl/fuzz_smooth.fp b/wadsrc/static/shaders/glsl/fuzz_smooth.fp new file mode 100644 index 00000000..2cfb9157 --- /dev/null +++ b/wadsrc/static/shaders/glsl/fuzz_smooth.fp @@ -0,0 +1,22 @@ +//created by Evil Space Tomato +uniform float timer; + +vec4 Process(vec4 color) +{ + vec2 texCoord = gl_TexCoord[0].st; + vec4 basicColor = getTexel(texCoord) * color; + + float texX = texCoord.x / 3.0f + 0.66f; + float texY = 0.34 - texCoord.y / 3.0f; + float vX = (texX/texY)*21.0f; + float vY = (texY/texX)*13.0f; + + + float test = mod(timer*2.0f+(vX + vY), 0.5f); + +// float test = mod(timer*2.0f+((texCoord.x/texCoord.y*abs(basicColor.r + basicColor.g/2))*21.0f + (texCoord.y/texCoord.x*abs(basicColor.b + basicColor.g/2))*13.0f), 0.3f); + basicColor.a = basicColor.a * test; + + basicColor.r = basicColor.g = basicColor.b = 0.0f;//(basicColor.r + basicColor.g + basicColor.b) / 3.0f; + return basicColor; +} diff --git a/wadsrc/static/shaders/glsl/fuzz_smoothnoise.fp b/wadsrc/static/shaders/glsl/fuzz_smoothnoise.fp new file mode 100644 index 00000000..fb4c1e69 --- /dev/null +++ b/wadsrc/static/shaders/glsl/fuzz_smoothnoise.fp @@ -0,0 +1,20 @@ +//created by Evil Space Tomato +uniform float timer; + +vec4 Process(vec4 color) +{ + vec2 texCoord = gl_TexCoord[0].st; + vec4 basicColor = getTexel(texCoord) * color; + + float texX = sin(mod(texCoord.x * 100 + timer*5, 3.489)) + texCoord.x / 4; + float texY = cos(mod(texCoord.y * 100 + timer*5, 3.489)) + texCoord.y / 4; + float vX = (texX/texY)*21.0f; + float vY = (texY/texX)*13.0f; + + + float test = mod(timer*2.0f+(vX + vY), 0.5f); + basicColor.a = basicColor.a * test; + + basicColor.rgb = vec3(0.0f,0.0f,0.0f); + return basicColor; +} diff --git a/wadsrc/static/shaders/glsl/fuzz_smoothtranslucent.fp b/wadsrc/static/shaders/glsl/fuzz_smoothtranslucent.fp new file mode 100644 index 00000000..eca5601f --- /dev/null +++ b/wadsrc/static/shaders/glsl/fuzz_smoothtranslucent.fp @@ -0,0 +1,19 @@ +//created by Evil Space Tomato +uniform float timer; + +vec4 Process(vec4 color) +{ + vec2 texCoord = gl_TexCoord[0].st; + vec4 basicColor = getTexel(texCoord) * color; + + float texX = sin(texCoord.x * 100 + timer*5); + float texY = cos(texCoord.x * 100 + timer*5); + float vX = (texX/texY)*21.0f; + float vY = (texY/texX)*13.0f; + + float test = mod(timer*2.0f+(vX + vY), 0.5f); + + basicColor.a = basicColor.a * test; + + return basicColor; +} diff --git a/wadsrc/static/shaders/glsl/fuzz_standard.fp b/wadsrc/static/shaders/glsl/fuzz_standard.fp new file mode 100644 index 00000000..315ce842 --- /dev/null +++ b/wadsrc/static/shaders/glsl/fuzz_standard.fp @@ -0,0 +1,25 @@ +//created by Evil Space Tomato +uniform float timer; + +vec4 Process(vec4 color) +{ + vec2 texCoord = gl_TexCoord[0].st; + vec4 basicColor = getTexel(texCoord) * color; + + texCoord.x = int(texCoord.x * 128) / 128.0f; + texCoord.y = int(texCoord.y * 128) / 128.0f; + + float texX = texCoord.x / 3.0f + 0.66f; + float texY = 0.34 - texCoord.y / 3.0f; + float vX = (texX/texY)*21.0f; + float vY = (texY/texX)*13.0f; + + + float test = mod(timer*2.0f+(vX + vY), 0.5f); + +// float test = mod(timer*2.0f+((texCoord.x/texCoord.y*abs(basicColor.r + basicColor.g/2))*21.0f + (texCoord.y/texCoord.x*abs(basicColor.b + basicColor.g/2))*13.0f), 0.3f); + basicColor.a = basicColor.a * test; + + basicColor.r = basicColor.g = basicColor.b = 0.0f;//(basicColor.r + basicColor.g + basicColor.b) / 3.0f; + return basicColor; +} diff --git a/wadsrc/static/shaders/glsl/fuzz_swirly.fp b/wadsrc/static/shaders/glsl/fuzz_swirly.fp new file mode 100644 index 00000000..7c75d7ad --- /dev/null +++ b/wadsrc/static/shaders/glsl/fuzz_swirly.fp @@ -0,0 +1,22 @@ +//created by Evil Space Tomato +uniform float timer; + +vec4 Process(vec4 color) +{ + vec2 texCoord = gl_TexCoord[0].st; + vec4 basicColor = getTexel(texCoord) * color; + + float texX = sin(texCoord.x * 100 + timer*5); + float texY = cos(texCoord.x * 100 + timer*5); + float vX = (texX/texY)*21.0f; + float vY = (texY/texX)*13.0f; + + + float test = mod(timer*2.0f+(vX + vY), 0.5f); + +// float test = mod(timer*2.0f+((texCoord.x/texCoord.y*abs(basicColor.r + basicColor.g/2))*21.0f + (texCoord.y/texCoord.x*abs(basicColor.b + basicColor.g/2))*13.0f), 0.3f); + basicColor.a = basicColor.a * test; + + basicColor.r = basicColor.g = basicColor.b = 0.0f;//(basicColor.r + basicColor.g + basicColor.b) / 3.0f; + return basicColor; +} diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 551ef1f0..07c5628b 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -66,7 +66,7 @@ vec4 getLightColor(float fogdist, float fogfactor) // if (fogenabled > 0) { - #if !defined NO_SM4 || defined DOOMLIGHT + #if !defined(NO_SM4) || defined(DOOMLIGHT) // special lighting mode 'Doom' not available on older cards for performance reasons. if (fogdist < fogparm.y) { @@ -170,7 +170,7 @@ void main() { fogdist = max(16.0, distance(pixelpos.xyz, camerapos)); } - #elif !defined FOG_RADIAL + #elif !defined(FOG_RADIAL) fogdist = pixelpos.w; #else fogdist = max(16.0, distance(pixelpos.xyz, camerapos)); diff --git a/wadsrc/static/xlat/base.txt b/wadsrc/static/xlat/base.txt index cc287a60..80ae814d 100644 --- a/wadsrc/static/xlat/base.txt +++ b/wadsrc/static/xlat/base.txt @@ -54,8 +54,8 @@ include "xlat/defines.i" 52 = WALK, Exit_Normal (0) 53 = WALK, Plat_PerpetualRaiseLip (tag, P_SLOW, PLATWAIT, 0) 54 = WALK, Plat_Stop (tag) - 55 = USE, Floor_RaiseAndCrush (tag, F_SLOW, 10) - 56 = WALK, Floor_RaiseAndCrush (tag, F_SLOW, 10) + 55 = USE, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) + 56 = WALK, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) 57 = WALK, Ceiling_CrushStop (tag) 58 = WALK, Floor_RaiseByValue (tag, F_SLOW, 24) 59 = WALK, Floor_RaiseByValueTxTy (tag, F_SLOW, 24) @@ -64,7 +64,7 @@ include "xlat/defines.i" 62 = USE|REP, Plat_DownWaitUpStayLip (tag, P_FAST, PLATWAIT, 0) 63 = USE|REP, Door_Raise (tag, D_SLOW, VDOORWAIT) 64 = USE|REP, Floor_RaiseToLowestCeiling (tag, F_SLOW) - 65 = USE|REP, Floor_RaiseAndCrush (tag, F_SLOW, 10) + 65 = USE|REP, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) 66 = USE|REP, Plat_UpByValueStayTx (tag, P_SLOW/2, 3) 67 = USE|REP, Plat_UpByValueStayTx (tag, P_SLOW/2, 4) 68 = USE|REP, Plat_RaiseAndStayTx0 (tag, P_SLOW/2) @@ -93,7 +93,7 @@ include "xlat/defines.i" 91 = WALK|REP, Floor_RaiseToLowestCeiling (tag, F_SLOW) 92 = WALK|REP, Floor_RaiseByValue (tag, F_SLOW, 24) 93 = WALK|REP, Floor_RaiseByValueTxTy (tag, F_SLOW, 24) - 94 = WALK|REP, Floor_RaiseAndCrush (tag, F_SLOW, 10) + 94 = WALK|REP, Floor_RaiseAndCrush (tag, F_SLOW, 10, 2) 95 = WALK|REP, Plat_RaiseAndStayTx0 (tag, P_SLOW/2) 96 = WALK|REP, Floor_RaiseByTexture (tag, F_SLOW) 97 = WALK|REP|MONST, Teleport (0, tag) @@ -168,7 +168,7 @@ include "xlat/defines.i" 163 = USE, Plat_Stop (tag) 164 = USE, Ceiling_CrushAndRaiseA (tag, C_NORMAL, C_NORMAL, 10) 165 = USE, Ceiling_CrushAndRaiseSilentA (tag, C_SLOW, C_SLOW, 10) -166 = USE, FloorAndCeiling_LowerRaise (tag, F_SLOW, C_SLOW) +166 = USE, FloorAndCeiling_LowerRaise (tag, F_SLOW, C_SLOW, 1998) 167 = USE, Ceiling_LowerAndCrush (tag, C_SLOW, 0, 2) 168 = USE, Ceiling_CrushStop (tag) 169 = USE, Light_MaxNeighbor (tag) @@ -188,7 +188,7 @@ include "xlat/defines.i" 183 = USE|REP, Ceiling_CrushAndRaiseA (tag, C_NORMAL, C_NORMAL, 10) 184 = USE|REP, Ceiling_CrushAndRaiseA (tag, C_SLOW, C_SLOW, 10) 185 = USE|REP, Ceiling_CrushAndRaiseSilentA (tag, C_SLOW, C_SLOW, 10) -186 = USE|REP, FloorAndCeiling_LowerRaise (tag, F_SLOW, C_SLOW) +186 = USE|REP, FloorAndCeiling_LowerRaise (tag, F_SLOW, C_SLOW, 1998) 187 = USE|REP, Ceiling_LowerAndCrush (tag, C_SLOW, 0, 2) 188 = USE|REP, Ceiling_CrushStop (tag) 189 = USE, Floor_TransferTrigger (tag)