diff --git a/CMakeLists.txt b/CMakeLists.txt index fcd372d3c2..2ed3b4146d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,39 @@ cmake_minimum_required( VERSION 2.4 ) project(ZDoom) +# Generator expression are available some time in CMake 2.8. Due to +# cmake_minimum_required, we can assume a minor version of > 7 implies major >= 2 +if(${CMAKE_MAJOR_VERSION} GREATER 2 OR ${CMAKE_MINOR_VERSION} GREATER 7) + option( NO_GENERATOR_EXPRESSIONS "Disable generator expressions (for building pk3s with IDEs)." OFF ) +else(${CMAKE_MAJOR_VERSION} GREATER 2 OR ${CMAKE_MINOR_VERSION} GREATER 7) + set( NO_GENERATOR_EXPRESSIONS ON ) +endif(${CMAKE_MAJOR_VERSION} GREATER 2 OR ${CMAKE_MINOR_VERSION} GREATER 7) + +# Simplify pk3 building, add_pk3(filename srcdirectory) +function( add_pk3 PK3_NAME PK3_DIR ) + get_target_property(ZIPDIR_EXE zipdir LOCATION) + + # Generate target name. Just use "pk3" for main pk3 target. + string( REPLACE "." "_" PK3_TARGET ${PK3_NAME} ) + if( ${PK3_TARGET} STREQUAL "zdoom_pk3" ) + set( PK3_TARGET "pk3" ) + endif( ${PK3_TARGET} STREQUAL "zdoom_pk3" ) + + if( NO_GENERATOR_EXPRESSIONS ) + add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} + COMMAND ${ZIPDIR_EXE} -udf ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} $ + DEPENDS zipdir ${PK3_DIR} ) + else( NO_GENERATOR_EXPRESSIONS ) + add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} + COMMAND ${ZIPDIR_EXE} -udf ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR} + DEPENDS zipdir ${PK3_DIR} ) + endif( NO_GENERATOR_EXPRESSIONS ) + + add_custom_target( ${PK3_TARGET} ALL + DEPENDS ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ) +endfunction( add_pk3 ) + IF( NOT CMAKE_BUILD_TYPE ) SET( CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." diff --git a/dumb/include/dumb.h b/dumb/include/dumb.h index bcd2022987..cafcfea3b8 100644 --- a/dumb/include/dumb.h +++ b/dumb/include/dumb.h @@ -44,7 +44,7 @@ #define DUMB_VERSION_STR "0.9.3" -#define DUMB_NAME "DUMB v"DUMB_VERSION_STR +#define DUMB_NAME "DUMB v" DUMB_VERSION_STR #define DUMB_YEAR 2005 #define DUMB_MONTH 8 @@ -56,13 +56,13 @@ #define DUMB_DAY_STR1 "7" #if DUMB_MONTH < 10 -#define DUMB_MONTH_STR2 "0"DUMB_MONTH_STR1 +#define DUMB_MONTH_STR2 "0" DUMB_MONTH_STR1 #else #define DUMB_MONTH_STR2 DUMB_MONTH_STR1 #endif #if DUMB_DAY < 10 -#define DUMB_DAY_STR2 "0"DUMB_DAY_STR1 +#define DUMB_DAY_STR2 "0" DUMB_DAY_STR1 #else #define DUMB_DAY_STR2 DUMB_DAY_STR1 #endif @@ -74,7 +74,7 @@ */ #define DUMB_DATE (DUMB_YEAR*10000 + DUMB_MONTH*100 + DUMB_DAY) -#define DUMB_DATE_STR DUMB_DAY_STR1"."DUMB_MONTH_STR1"."DUMB_YEAR_STR4 +#define DUMB_DATE_STR DUMB_DAY_STR1 "." DUMB_MONTH_STR1 "." DUMB_YEAR_STR4 #undef MIN diff --git a/dumb/src/it/readmod.c b/dumb/src/it/readmod.c index 9d105f126d..801b1ce766 100644 --- a/dumb/src/it/readmod.c +++ b/dumb/src/it/readmod.c @@ -650,8 +650,8 @@ static DUMB_IT_SIGDATA *it_mod_load_sigdata(DUMBFILE *f, int rstrict) if ( ( rstrict & 2 ) ) { - long total_sample_size; - long remain; + int32 total_sample_size; + int32 remain; rem = f; f = dumbfile_buffer_mod_2(rem, sigdata->n_samples, sigdata->sample, &total_sample_size, &remain); if (!f) { diff --git a/dumb/src/it/readxm.c b/dumb/src/it/readxm.c index 25ca07108e..7b92cb9548 100644 --- a/dumb/src/it/readxm.c +++ b/dumb/src/it/readxm.c @@ -436,7 +436,7 @@ static int limit_xm_getc(void *f) -static long limit_xm_getnc(char *ptr, int32 n, void *f) +static int32 limit_xm_getnc(char *ptr, int32 n, void *f) { LIMITED_XM *lx = f; int left; diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index bdd70322eb..3241bf4c84 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -113,6 +113,7 @@ Note: All fields default to false unless mentioned otherwise. blockprojectiles = ;// Line blocks all projectiles blockuse = ; // Line blocks all use actions blocksight = ; // Line blocks monster line of sight + blockhitscan = ; // Line blocks hitscan attacks locknumber = ; // Line special is locked arg0str = ; // Alternate string-based version of arg0 @@ -186,6 +187,7 @@ Note: All fields default to false unless mentioned otherwise. soundsequence = ; // The sound sequence to play when this sector moves. Placing a // sound sequence thing in the sector will override this property. hidden = ; // if true this sector will not be drawn on the textured automap. + waterzone = ; // Sector is under water and swimmable * Note about dropactors @@ -203,6 +205,8 @@ Note: All fields default to false unless mentioned otherwise. // Parameter is the conversation ID, 0 meaning none. countsecret = ; // Picking up this actor counts as a secret. arg0str = ; // Alternate string-based version of arg0 + gravity = ; // Set per-actor gravity. Positive values are multiplied with the class's property, + // negative values are used as their absolute. Default = 1.0. * Note about arg0str @@ -328,6 +332,9 @@ Added back locknumber property. 1.20 25.02.2012 Added arg0str thing property. +1.21 09.08.2013 +Added waterzone sector property. + =============================================================================== EOF =============================================================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 786375b3bd..ed70bda4a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,7 +9,12 @@ include( CheckFunctionExists ) include( CheckCXXCompilerFlag ) include( FindPkgConfig ) -option( NO_ASM "Disable assembly code" ) +if( NOT APPLE ) + option( NO_ASM "Disable assembly code" OFF ) +else( NOT APPLE ) + # At the moment asm code doesn't work with OS X, so disable by default + option( NO_ASM "Disable assembly code" ON ) +endif( NOT APPLE ) if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) option( NO_STRIP "Do not strip Release or MinSizeRel builds" ) # At least some versions of Xcode fail if you strip with the linker @@ -71,8 +76,11 @@ if( WIN32 ) set( FMOD_SEARCH_PATHS "C:/Program Files/FMOD SoundSystem/FMOD Programmers API ${WIN_TYPE}/api" "C:/Program Files (x86)/FMOD SoundSystem/FMOD Programmers API ${WIN_TYPE}/api" - # This next one is for me. - "E:/Software/Dev/FMOD/${WIN_TYPE}/api" ) + # This next one is for Randy. + "E:/Software/Dev/FMOD/${WIN_TYPE}/api" + # .. and this one for Graf Zahl + "D:/portable/FMOD SoundSystem 4.26/FMOD Programmers API WIN32/api" + ) set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) set( NASM_NAMES nasmw nasm ) diff --git a/src/actor.h b/src/actor.h index 7ec6534473..7680081821 100644 --- a/src/actor.h +++ b/src/actor.h @@ -268,7 +268,7 @@ enum MF5_DONTDRAIN = 0x00000001, // cannot be drained health from. /* = 0x00000002, */ MF5_NODROPOFF = 0x00000004, // cannot drop off under any circumstances. - /* = 0x00000008, */ + MF5_NOFORWARDFALL = 0x00000008, // Does not make any actor fall forward by being damaged by this MF5_COUNTSECRET = 0x00000010, // From Doom 64: actor acts like a secret MF5_AVOIDINGDROPOFF = 0x00000020, // Used to move monsters away from dropoffs MF5_NODAMAGE = 0x00000040, // Actor can be shot and reacts to being shot but takes no damage @@ -331,6 +331,7 @@ enum MF6_DOHARMSPECIES = 0x08000000, // Do hurt one's own species with projectiles. MF6_INTRYMOVE = 0x10000000, // Executing P_TryMove MF6_NOTAUTOAIMED = 0x20000000, // Do not subject actor to player autoaim. + MF6_NOTONAUTOMAP = 0x40000000, // will not be shown on automap with the 'scanner' powerup. // --- mobj.renderflags --- diff --git a/src/am_map.cpp b/src/am_map.cpp index aa66341270..ad34995d0a 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -186,6 +186,9 @@ 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_ovefwallcolor, 0x008844, CVAR_ARCHIVE); +CVAR (Color, am_ovfdwallcolor, 0x008844, CVAR_ARCHIVE); +CVAR (Color, am_ovcdwallcolor, 0x008844, CVAR_ARCHIVE); CVAR (Color, am_ovunseencolor, 0x00226e, CVAR_ARCHIVE); CVAR (Color, am_ovtelecolor, 0xffff00, CVAR_ARCHIVE); CVAR (Color, am_intralevelcolor, 0x0000ff, CVAR_ARCHIVE); @@ -204,6 +207,7 @@ CVAR (Color, am_ovthingcolor_friend, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_monster, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE); CVAR (Color, am_ovthingcolor_citem, 0xe88800, CVAR_ARCHIVE); +CVAR (Int, am_showthingsprites, 0, CVAR_ARCHIVE); static int bigstate = 0; @@ -412,6 +416,9 @@ static bool stopped = true; static void AM_calcMinMaxMtoF(); +static void DrawMarker (FTexture *tex, fixed_t x, fixed_t y, int yadjust, + INTBOOL flip, fixed_t xscale, fixed_t yscale, int translation, fixed_t alpha, DWORD fillcolor, FRenderStyle renderstyle); + void AM_rotatePoint (fixed_t *x, fixed_t *y); void AM_rotate (fixed_t *x, fixed_t *y, angle_t an); void AM_doFollowPlayer (); @@ -917,7 +924,9 @@ static void AM_initColors (bool overlayed) ThingColor_Monster.FromCVar (am_ovthingcolor_monster); ThingColor.FromCVar (am_ovthingcolor); LockedColor.FromCVar (am_ovotherwallscolor); - EFWallColor = FDWallColor = CDWallColor = LockedColor; + EFWallColor.FromCVar (am_ovefwallcolor); + FDWallColor.FromCVar (am_ovfdwallcolor); + CDWallColor.FromCVar (am_ovcdwallcolor); TSWallColor.FromCVar (am_ovunseencolor); NotSeenColor = TSWallColor; InterTeleportColor.FromCVar (am_ovtelecolor); @@ -2193,6 +2202,12 @@ AM_drawLineCharacter void AM_drawPlayers () { + if (am_cheat >= 2 && am_showthingsprites > 0) + { + // Player sprites are drawn with the others + return; + } + mpoint_t pt; angle_t angle; int i; @@ -2328,7 +2343,6 @@ void AM_drawKeys () // // //============================================================================= - void AM_drawThings () { AMColor color; @@ -2342,75 +2356,116 @@ void AM_drawThings () t = sectors[i].thinglist; while (t) { - p.x = t->x >> FRACTOMAPBITS; - p.y = t->y >> FRACTOMAPBITS; - angle = t->angle; - - if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + if (am_cheat > 0 || !(t->flags6 & MF6_NOTONAUTOMAP)) { - AM_rotatePoint (&p.x, &p.y); - angle += ANG90 - players[consoleplayer].camera->angle; - } + p.x = t->x >> FRACTOMAPBITS; + p.y = t->y >> FRACTOMAPBITS; - color = ThingColor; - - // use separate colors for special thing types - if (t->flags3&MF3_ISMONSTER && !(t->flags&MF_CORPSE)) - { - if (t->flags & MF_FRIENDLY || !(t->flags & MF_COUNTKILL)) color = ThingColor_Friend; - else color = ThingColor_Monster; - } - else if (t->flags&MF_SPECIAL) - { - // Find the key's own color. - // Only works correctly if single-key locks have lower numbers than any-key locks. - // That is the case for all default keys, however. - if (t->IsKindOf(RUNTIME_CLASS(AKey))) + if (am_showthingsprites > 0 && t->sprite > 0) { - if (G_SkillProperty(SKILLP_EasyKey)) - { - // Already drawn by AM_drawKeys(), so don't draw again - color.Index = -1; - } - else if (am_showkeys) - { - int P_GetMapColorForKey (AInventory * key); - int c = P_GetMapColorForKey(static_cast(t)); + FTexture *texture = NULL; + spriteframe_t *frame; + angle_t rotation = 0; - if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); - else color = ThingColor_CountItem; - AM_drawLineCharacter(&CheatKey[0], CheatKey.Size(), 0, 0, color, p.x, p.y); - color.Index = -1; - } - else + // try all modes backwards until a valid texture has been found. + for(int show = am_showthingsprites; show > 0 && texture == NULL; show--) { - color = ThingColor_Item; + const spritedef_t& sprite = sprites[t->sprite]; + const size_t spriteIndex = sprite.spriteframes + (show > 1 ? t->frame : 0); + + frame = &SpriteFrames[spriteIndex]; + angle_t angle = ANGLE_270 - t->angle; + if (frame->Texture[0] != frame->Texture[1]) angle += (ANGLE_180 / 16); + if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + { + angle += players[consoleplayer].camera->angle - ANGLE_90; + } + rotation = angle >> 28; + + const FTextureID textureID = frame->Texture[show > 2 ? rotation : 0]; + texture = TexMan(textureID); + } + + if (texture == NULL) goto drawTriangle; // fall back to standard display if no sprite can be found. + + const fixed_t spriteXScale = FixedMul(t->scaleX, 10 * scale_mtof); + const fixed_t spriteYScale = FixedMul(t->scaleY, 10 * scale_mtof); + + DrawMarker (texture, p.x, p.y, 0, !!(frame->Flip & (1 << rotation)), + spriteXScale, spriteYScale, t->Translation, FRACUNIT, 0, LegacyRenderStyles[STYLE_Normal]); + } + else + { + drawTriangle: + angle = t->angle; + + if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + { + AM_rotatePoint (&p.x, &p.y); + angle += ANG90 - players[consoleplayer].camera->angle; + } + + color = ThingColor; + + // use separate colors for special thing types + if (t->flags3&MF3_ISMONSTER && !(t->flags&MF_CORPSE)) + { + if (t->flags & MF_FRIENDLY || !(t->flags & MF_COUNTKILL)) color = ThingColor_Friend; + else color = ThingColor_Monster; + } + else if (t->flags&MF_SPECIAL) + { + // Find the key's own color. + // Only works correctly if single-key locks have lower numbers than any-key locks. + // That is the case for all default keys, however. + if (t->IsKindOf(RUNTIME_CLASS(AKey))) + { + if (G_SkillProperty(SKILLP_EasyKey)) + { + // Already drawn by AM_drawKeys(), so don't draw again + color.Index = -1; + } + else if (am_showkeys) + { + int P_GetMapColorForKey (AInventory * key); + int c = P_GetMapColorForKey(static_cast(t)); + + if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); + else color = ThingColor_CountItem; + AM_drawLineCharacter(&CheatKey[0], CheatKey.Size(), 0, 0, color, p.x, p.y); + color.Index = -1; + } + else + { + color = ThingColor_Item; + } + } + else if (t->flags&MF_COUNTITEM) + color = ThingColor_CountItem; + else + color = ThingColor_Item; + } + + if (color.Index != -1) + { + AM_drawLineCharacter + (thintriangle_guy, NUMTHINTRIANGLEGUYLINES, + 16<= 3) + { + static const mline_t box[4] = + { + { { -MAPUNIT, -MAPUNIT }, { MAPUNIT, -MAPUNIT } }, + { { MAPUNIT, -MAPUNIT }, { MAPUNIT, MAPUNIT } }, + { { MAPUNIT, MAPUNIT }, { -MAPUNIT, MAPUNIT } }, + { { -MAPUNIT, MAPUNIT }, { -MAPUNIT, -MAPUNIT } }, + }; + + AM_drawLineCharacter (box, 4, t->radius >> FRACTOMAPBITS, angle - t->angle, color, p.x, p.y); } } - else if (t->flags&MF_COUNTITEM) - color = ThingColor_CountItem; - else - color = ThingColor_Item; - } - - if (color.Index != -1) - { - AM_drawLineCharacter - (thintriangle_guy, NUMTHINTRIANGLEGUYLINES, - 16<= 3) - { - static const mline_t box[4] = - { - { { -MAPUNIT, -MAPUNIT }, { MAPUNIT, -MAPUNIT } }, - { { MAPUNIT, -MAPUNIT }, { MAPUNIT, MAPUNIT } }, - { { MAPUNIT, MAPUNIT }, { -MAPUNIT, MAPUNIT } }, - { { -MAPUNIT, MAPUNIT }, { -MAPUNIT, -MAPUNIT } }, - }; - - AM_drawLineCharacter (box, 4, t->radius >> FRACTOMAPBITS, angle - t->angle, color, p.x, p.y); } t = t->snext; } diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index c3ffe0a5f1..cdf615ef49 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -51,6 +51,7 @@ #include "i_system.h" +#include "doomerrors.h" #include "doomstat.h" #include "gstrings.h" #include "s_sound.h" @@ -343,22 +344,30 @@ CCMD (changemap) if (argv.argc() > 1) { - if (!P_CheckMapData(argv[1])) + try { - Printf ("No map %s\n", argv[1]); - } - else - { - if (argv.argc() > 2) + if (!P_CheckMapData(argv[1])) { - Net_WriteByte (DEM_CHANGEMAP2); - Net_WriteByte (atoi(argv[2])); + Printf ("No map %s\n", argv[1]); } else { - Net_WriteByte (DEM_CHANGEMAP); + if (argv.argc() > 2) + { + Net_WriteByte (DEM_CHANGEMAP2); + Net_WriteByte (atoi(argv[2])); + } + else + { + Net_WriteByte (DEM_CHANGEMAP); + } + Net_WriteString (argv[1]); } - Net_WriteString (argv[1]); + } + catch(CRecoverableError &error) + { + if (error.GetMessage()) + Printf("%s", error.GetMessage()); } } else @@ -960,8 +969,8 @@ CCMD(nextmap) { if (netgame) { - Printf ("Use "TEXTCOLOR_BOLD"changemap"TEXTCOLOR_NORMAL" instead. "TEXTCOLOR_BOLD"Nextmap" - TEXTCOLOR_NORMAL" is for single-player only.\n"); + Printf ("Use " TEXTCOLOR_BOLD "changemap" TEXTCOLOR_NORMAL " instead. " TEXTCOLOR_BOLD "Nextmap" + TEXTCOLOR_NORMAL " is for single-player only.\n"); return; } char *next = NULL; @@ -988,8 +997,8 @@ CCMD(nextsecret) { if (netgame) { - Printf ("Use "TEXTCOLOR_BOLD"changemap"TEXTCOLOR_NORMAL" instead. "TEXTCOLOR_BOLD"Nextsecret" - TEXTCOLOR_NORMAL" is for single-player only.\n"); + Printf ("Use " TEXTCOLOR_BOLD "changemap" TEXTCOLOR_NORMAL " instead. " TEXTCOLOR_BOLD "Nextsecret" + TEXTCOLOR_NORMAL " is for single-player only.\n"); return; } char *next = NULL; @@ -1138,4 +1147,4 @@ CCMD(secret) else inlevel = false; } } -} \ No newline at end of file +} diff --git a/src/c_console.cpp b/src/c_console.cpp index 170cc97d44..e5d3d97ab1 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -2121,7 +2121,20 @@ static bool C_TabCompleteList () Printf (TEXTCOLOR_BLUE "Completions for %s:\n", CmdLine+2); for (i = TabPos; nummatches > 0; ++i, --nummatches) { - Printf ("%-*s", int(maxwidth), TabCommands[i].TabName.GetChars()); + // [Dusk] Print console commands blue, CVars green, aliases red. + const char* colorcode = ""; + FConsoleCommand* ccmd; + if (FindCVar (TabCommands[i].TabName, NULL)) + colorcode = TEXTCOLOR_GREEN; + else if ((ccmd = FConsoleCommand::FindByName (TabCommands[i].TabName)) != NULL) + { + if (ccmd->IsAlias()) + colorcode = TEXTCOLOR_RED; + else + colorcode = TEXTCOLOR_LIGHTBLUE; + } + + Printf ("%s%-*s", colorcode, int(maxwidth), TabCommands[i].TabName.GetChars()); x += maxwidth; if (x > ConCols - maxwidth) { diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 7b701bd534..2bd2554053 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -92,8 +92,8 @@ private: struct FActionMap { - unsigned int Key; // value from passing Name to MakeKey() FButtonStatus *Button; + unsigned int Key; // value from passing Name to MakeKey() char Name[12]; }; @@ -134,38 +134,38 @@ bool ParsingKeyConf; FActionMap ActionMaps[] = { - { 0x0d52d67b, &Button_AM_PanLeft, "am_panleft"}, - { 0x125f5226, &Button_User2, "user2" }, - { 0x1eefa611, &Button_Jump, "jump" }, - { 0x201f1c55, &Button_Right, "right" }, - { 0x20ccc4d5, &Button_Zoom, "zoom" }, - { 0x23a99cd7, &Button_Back, "back" }, - { 0x41df90c2, &Button_AM_ZoomIn, "am_zoomin"}, - { 0x426b69e7, &Button_Reload, "reload" }, - { 0x4463f43a, &Button_LookDown, "lookdown" }, - { 0x51f7a334, &Button_AM_ZoomOut, "am_zoomout"}, - { 0x534c30ee, &Button_User4, "user4" }, - { 0x5622bf42, &Button_Attack, "attack" }, - { 0x577712d0, &Button_User1, "user1" }, - { 0x57c25cb2, &Button_Klook, "klook" }, - { 0x59f3e907, &Button_Forward, "forward" }, - { 0x6167ce99, &Button_MoveDown, "movedown" }, - { 0x676885b8, &Button_AltAttack, "altattack" }, - { 0x6fa41b84, &Button_MoveLeft, "moveleft" }, - { 0x818f08e6, &Button_MoveRight, "moveright" }, - { 0x8197097b, &Button_AM_PanRight, "am_panright"}, - { 0x8d89955e, &Button_AM_PanUp, "am_panup"} , - { 0xa2b62d8b, &Button_Mlook, "mlook" }, - { 0xab2c3e71, &Button_Crouch, "crouch" }, - { 0xb000b483, &Button_Left, "left" }, - { 0xb62b1e49, &Button_LookUp, "lookup" }, - { 0xb6f8fe92, &Button_User3, "user3" }, - { 0xb7e6a54b, &Button_Strafe, "strafe" }, - { 0xce301c81, &Button_AM_PanDown, "am_pandown"}, - { 0xd5897c73, &Button_ShowScores, "showscores" }, - { 0xe0ccb317, &Button_Speed, "speed" }, - { 0xe0cfc260, &Button_Use, "use" }, - { 0xfdd701c7, &Button_MoveUp, "moveup" }, + { &Button_AM_PanLeft, 0x0d52d67b, "am_panleft"}, + { &Button_User2, 0x125f5226, "user2" }, + { &Button_Jump, 0x1eefa611, "jump" }, + { &Button_Right, 0x201f1c55, "right" }, + { &Button_Zoom, 0x20ccc4d5, "zoom" }, + { &Button_Back, 0x23a99cd7, "back" }, + { &Button_AM_ZoomIn, 0x41df90c2, "am_zoomin"}, + { &Button_Reload, 0x426b69e7, "reload" }, + { &Button_LookDown, 0x4463f43a, "lookdown" }, + { &Button_AM_ZoomOut, 0x51f7a334, "am_zoomout"}, + { &Button_User4, 0x534c30ee, "user4" }, + { &Button_Attack, 0x5622bf42, "attack" }, + { &Button_User1, 0x577712d0, "user1" }, + { &Button_Klook, 0x57c25cb2, "klook" }, + { &Button_Forward, 0x59f3e907, "forward" }, + { &Button_MoveDown, 0x6167ce99, "movedown" }, + { &Button_AltAttack, 0x676885b8, "altattack" }, + { &Button_MoveLeft, 0x6fa41b84, "moveleft" }, + { &Button_MoveRight, 0x818f08e6, "moveright" }, + { &Button_AM_PanRight, 0x8197097b, "am_panright"}, + { &Button_AM_PanUp, 0x8d89955e, "am_panup"} , + { &Button_Mlook, 0xa2b62d8b, "mlook" }, + { &Button_Crouch, 0xab2c3e71, "crouch" }, + { &Button_Left, 0xb000b483, "left" }, + { &Button_LookUp, 0xb62b1e49, "lookup" }, + { &Button_User3, 0xb6f8fe92, "user3" }, + { &Button_Strafe, 0xb7e6a54b, "strafe" }, + { &Button_AM_PanDown, 0xce301c81, "am_pandown"}, + { &Button_ShowScores, 0xd5897c73, "showscores" }, + { &Button_Speed, 0xe0ccb317, "speed" }, + { &Button_Use, 0xe0cfc260, "use" }, + { &Button_MoveUp, 0xfdd701c7, "moveup" }, }; #define NUM_ACTIONS countof(ActionMaps) @@ -627,7 +627,14 @@ void C_DoCommand (const char *cmd, int keynum) } else { - new DStoredCommand (com, beg); + if (len == 4 && strnicmp(beg, "warp", 4) == 0) + { + StoredWarp = beg; + } + else + { + new DStoredCommand (com, beg); + } } } else @@ -955,6 +962,11 @@ bool FConsoleCommand::AddToHash (FConsoleCommand **table) return true; } +FConsoleCommand* FConsoleCommand::FindByName (const char* name) +{ + return FindNameInHashTable (Commands, name, strlen (name)); +} + FConsoleCommand::FConsoleCommand (const char *name, CCmdRun runFunc) : m_RunFunc (runFunc) { diff --git a/src/c_dispatch.h b/src/c_dispatch.h index 12ea559de3..96dc50644e 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -93,6 +93,7 @@ public: void PrintCommand () { Printf ("%s\n", m_Name); } virtual void Run (FCommandLine &args, APlayerPawn *instigator, int key); + static FConsoleCommand* FindByName (const char* name); FConsoleCommand *m_Next, **m_Prev; char *m_Name; diff --git a/src/compatibility.cpp b/src/compatibility.cpp index 4a4f19d6be..dca0d34851 100644 --- a/src/compatibility.cpp +++ b/src/compatibility.cpp @@ -105,6 +105,7 @@ static FCompatOption Options[] = { "vileghosts", BCOMPATF_VILEGHOSTS, SLOT_BCOMPAT }, { "ignoreteleporttags", BCOMPATF_BADTELEPORTERS, SLOT_BCOMPAT }, { "rebuildnodes", BCOMPATF_REBUILDNODES, SLOT_BCOMPAT }, + { "linkfrozenprops", BCOMPATF_LINKFROZENPROPS, SLOT_BCOMPAT }, // list copied from g_mapinfo.cpp { "shorttex", COMPATF_SHORTTEX, SLOT_COMPAT }, @@ -540,7 +541,7 @@ CCMD (mapchecksum) } for (int i = 1; i < argv.argc(); ++i) { - map = P_OpenMapData(argv[i]); + map = P_OpenMapData(argv[i], true); if (map == NULL) { Printf("Cannot load %s as a map\n", argv[i]); diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index dd00000438..82ba21eba0 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2338,6 +2338,7 @@ int D_LoadDehLumps() count += D_LoadDehLump(lumpnum); } +#if 0 // commented out for 'maint' version. if (0 == PatchSize) { // No DEH/BEX patch is loaded yet, try to find lump(s) with specific extensions @@ -2358,6 +2359,7 @@ int D_LoadDehLumps() } } } +#endif return count; } diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index e53a1d3629..6b430fa038 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -367,7 +367,7 @@ int FIWadManager::CheckIWAD (const char *doomwaddir, WadStuff *wads) // Under UNIX OSes, the search path is: // 1. Current directory // 2. $DOOMWADDIR -// 3. $HOME/.zdoom +// 3. $HOME/.config/zdoom // 4. The share directory defined at compile time (/usr/local/share/zdoom) // // The search path can be altered by editing the IWADSearch.Directories @@ -516,9 +516,19 @@ int FIWadManager::IdentifyVersion (TArray &wadfiles, const char *iwad, I_FatalError ("Cannot find a game IWAD (doom.wad, doom2.wad, heretic.wad, etc.).\n" "Did you install ZDoom properly? You can do either of the following:\n" "\n" +#if defined(_WIN32) "1. Place one or more of these wads in the same directory as ZDoom.\n" "2. Edit your zdoom-username.ini and add the directories of your iwads\n" "to the list beneath [IWADSearch.Directories]"); +#elif defined(__APPLE__) + "1. Place one or more of these wads in ~/Library/Application Support/zdoom/\n" + "2. Edit your ~/Library/Preferences/zdoom.ini and add the directories\n" + "of your iwads to the list beneath [IWADSearch.Directories]"); +#else + "1. Place one or more of these wads in ~/.config/zdoom/.\n" + "2. Edit your ~/.config/zdoom/zdoom.ini and add the directories of your\n" + "iwads to the list beneath [IWADSearch.Directories]"); +#endif } pickwad = 0; diff --git a/src/d_main.cpp b/src/d_main.cpp index 6c92babe4a..f0e7e7676e 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -218,6 +218,7 @@ int NoWipe; // [RH] Allow wipe? (Needs to be set each time) bool singletics = false; // debug flag to cancel adaptiveness FString startmap; bool autostart; +FString StoredWarp; bool advancedemo; FILE *debugfile; event_t events[MAXEVENTS]; @@ -1300,7 +1301,7 @@ void D_DoAdvanceDemo (void) gamestate = GS_DEMOSCREEN; pagename = gameinfo.titlePage; pagetic = (int)(gameinfo.titleTime * TICRATE); - S_StartMusic (gameinfo.titleMusic); + S_ChangeMusic (gameinfo.titleMusic, gameinfo.titleOrder, false); demosequence = 3; pagecount = 0; C_HideConsole (); @@ -2081,7 +2082,7 @@ static void CheckCmdLine() { startmap = "&wt@01"; } - autostart = false; + autostart = StoredWarp.IsNotEmpty(); const char *val = Args->CheckValue ("-skill"); if (val) @@ -2281,8 +2282,6 @@ void D_DoomMain (void) execFiles = Args->GatherFiles ("-exec"); D_MultiExec (execFiles, true); - 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. @@ -2298,6 +2297,8 @@ void D_DoomMain (void) // Now that wads are loaded, define mod-specific cvars. ParseCVarInfo(); + C_ExecCmdLineParams (); // [RH] do all +set commands on the command line + // [RH] Initialize localizable strings. GStrings.LoadStrings (false); @@ -2529,6 +2530,11 @@ void D_DoomMain (void) if (demorecording) G_BeginRecording (startmap); G_InitNew (startmap, false); + if (StoredWarp.IsNotEmpty()) + { + AddCommandString(StoredWarp.LockBuffer()); + StoredWarp = NULL; + } } else { diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 7f94ef686e..12fb187aef 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -713,7 +713,7 @@ void D_WriteUserInfoStrings (int pnum, BYTE **stream, bool compact) if (!compact) { // In verbose mode, prepend the cvar's name - *stream += sprintf(*((char **)stream), "\\%s\\", pair->Key.GetChars()); + *stream += sprintf(*((char **)stream), "\\%s", pair->Key.GetChars()); } // A few of these need special handling for compatibility reasons. switch (pair->Key.GetIndex()) @@ -1048,3 +1048,15 @@ CCMD (playerinfo) } } } + +userinfo_t::~userinfo_t() +{ + TMapIterator it(*this); + TMap::Pair *pair; + + while (it.NextPair(pair)) + { + delete pair->Value; + } + this->Clear(); +} diff --git a/src/d_player.h b/src/d_player.h index 6169dcebfd..f6f7674d77 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -140,6 +140,8 @@ public: int SpawnMask; FNameNoInit MorphWeapon; fixed_t AttackZOffset; // attack height, relative to player center + fixed_t UseRange; // [NS] Distance at which player can +use + fixed_t AirCapacity; // Multiplier for air supply underwater. const PClass *FlechetteType; // [CW] Fades for when you are being damaged. @@ -260,6 +262,8 @@ enum struct userinfo_t : TMap { + ~userinfo_t(); + int GetAimDist() const { if (dmflags2 & DF2_NOAUTOAIM) @@ -321,6 +325,10 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_Gender)); } + bool GetNoAutostartMap() const + { + return *static_cast(*CheckKey(NAME_Wi_NoAutostartMap)); + } void Reset(); int TeamChanged(int team); @@ -344,6 +352,7 @@ class player_t { public: player_t(); + player_t &operator= (const player_t &p); void Serialize (FArchive &arc); size_t FixPointers (const DObject *obj, DObject *replacement); diff --git a/src/doomdata.h b/src/doomdata.h index eeff13e2e5..55903170a7 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -153,6 +153,7 @@ enum ELineFlags ML_BLOCKPROJECTILE = 0x01000000, ML_BLOCKUSE = 0x02000000, // blocks all use actions through this line ML_BLOCKSIGHT = 0x04000000, // blocks monster line of sight + ML_BLOCKHITSCAN = 0x08000000, // blocks hitscan attacks }; @@ -342,6 +343,7 @@ struct FMapThing int special; int args[5]; int Conversation; + fixed_t gravity; void Serialize (FArchive &); }; diff --git a/src/doomdef.h b/src/doomdef.h index 3a3c31e6ab..675923b4a4 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -349,6 +349,7 @@ enum BCOMPATF_BADTELEPORTERS = 1 << 3, // Ignore tags on Teleport specials BCOMPATF_BADPORTALS = 1 << 4, // Restores the old unstable portal behavior BCOMPATF_REBUILDNODES = 1 << 5, // Force node rebuild + BCOMPATF_LINKFROZENPROPS = 1 << 6, // Clearing PROP_TOTALLYFROZEN or PROP_FROZEN also clears the other }; // phares 3/20/98: diff --git a/src/doomstat.h b/src/doomstat.h index 2819f1bf0d..92ab5b8f82 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -59,6 +59,8 @@ extern FString startmap; // [RH] Actual map name now extern bool autostart; +extern FString StoredWarp; // [RH] +warp at the command line + // Selected by user. EXTERN_CVAR (Int, gameskill); extern int NextSkill; // [RH] Skill to use at next level load diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 15206dabdd..5405051e7a 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -357,12 +357,10 @@ void DThinker::DestroyThinkersInList (FThinkerList &list) { if (list.Sentinel != NULL) { - DThinker *node = list.Sentinel->NextThinker; - while (node != list.Sentinel) + for (DThinker *node = list.Sentinel->NextThinker; node != list.Sentinel; node = list.Sentinel->NextThinker) { - DThinker *next = node->NextThinker; + assert(node != NULL); node->Destroy(); - node = next; } list.Sentinel->Destroy(); list.Sentinel = NULL; @@ -380,9 +378,8 @@ void DThinker::DestroyMostThinkersInList (FThinkerList &list, int stat) // it from the list. G_FinishTravel() will find it later from // a players[].mo link and destroy it then, after copying various // information to a new player. - for (DThinker *probe = list.Sentinel->NextThinker, *next; probe != list.Sentinel; probe = next) + for (DThinker *probe = list.Sentinel->NextThinker; probe != list.Sentinel; probe = list.Sentinel->NextThinker) { - next = probe->NextThinker; if (!probe->IsKindOf(RUNTIME_CLASS(APlayerPawn)) || // <- should not happen static_cast(probe)->player == NULL || static_cast(probe)->player->mo != probe) diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index e2fb689c2a..8fce33324f 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -101,15 +101,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileTarget) // // A_VileAttack // + +// A_VileAttack flags +#define VAF_DMGTYPEAPPLYTODIRECT 1 + DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) { - ACTION_PARAM_START(6); + ACTION_PARAM_START(7); ACTION_PARAM_SOUND(snd,0); ACTION_PARAM_INT(dmg,1); ACTION_PARAM_INT(blastdmg,2); ACTION_PARAM_INT(blastrad,3); ACTION_PARAM_FIXED(thrust,4); ACTION_PARAM_NAME(dmgtype,5); + ACTION_PARAM_INT(flags,6); AActor *fire, *target; angle_t an; @@ -123,7 +128,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) return; S_Sound (self, CHAN_WEAPON, snd, 1, ATTN_NORM); - int newdam = P_DamageMobj (target, self, self, dmg, NAME_None); + + int newdam; + + if (flags & VAF_DMGTYPEAPPLYTODIRECT) + newdam = P_DamageMobj (target, self, self, dmg, dmgtype); + + else + newdam = P_DamageMobj (target, self, self, dmg, NAME_None); + P_TraceBleed (newdam > 0 ? newdam : dmg, target); an = self->angle >> ANGLETOFINESHIFT; diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 5c5bb7eba1..368d7ce8b6 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -53,7 +53,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) angle += pr_punch.Random2() << 18; pitch = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); - P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &linetarget); + P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, LAF_ISMELEEATTACK, &linetarget); // turn to face target if (linetarget) @@ -589,7 +589,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray) damage += (pr_bfgspray() & 7) + 1; thingToHit = linetarget; - int newdam = P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash)); + int newdam = P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash), + spray != NULL && (spray->flags3 & MF3_FOILINVUL)? DMG_FOILINVUL : 0); P_TraceBleed (newdam > 0 ? newdam : damage, thingToHit, self->target); } } diff --git a/src/g_game.cpp b/src/g_game.cpp index 0db149b0b0..506b8e24b4 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -862,7 +862,10 @@ static void ChangeSpy (int changespy) int pnum = consoleplayer; if (changespy != SPY_CANCEL) { - pnum = int(players[consoleplayer].camera->player - players); + player_t *player = players[consoleplayer].camera->player; + // only use the camera as starting index if it's a valid player. + if (player != NULL) pnum = int(players[consoleplayer].camera->player - players); + int step = (changespy == SPY_NEXT) ? 1 : -1; do diff --git a/src/g_hexen/a_fighterquietus.cpp b/src/g_hexen/a_fighterquietus.cpp index 0ba8abd6f0..846b30281a 100644 --- a/src/g_hexen/a_fighterquietus.cpp +++ b/src/g_hexen/a_fighterquietus.cpp @@ -58,12 +58,12 @@ class AFSwordMissile : public AActor { DECLARE_CLASS (AFSwordMissile, AActor) public: - int DoSpecialDamage(AActor *victim, AActor *source, int damage, FName damagetype); + int DoSpecialDamage(AActor *victim, int damage, FName damagetype); }; IMPLEMENT_CLASS (AFSwordMissile) -int AFSwordMissile::DoSpecialDamage(AActor *victim, AActor *source, int damage, FName damagetype) +int AFSwordMissile::DoSpecialDamage(AActor *victim, int damage, FName damagetype) { if (victim->player) { diff --git a/src/g_level.cpp b/src/g_level.cpp index 755a4fba62..0b07ae2b56 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -40,6 +40,7 @@ #include "s_sound.h" #include "d_event.h" #include "m_random.h" +#include "doomerrors.h" #include "doomstat.h" #include "wi_stuff.h" #include "w_wad.h" @@ -164,19 +165,27 @@ CCMD (map) { if (netgame) { - Printf ("Use "TEXTCOLOR_BOLD"changemap"TEXTCOLOR_NORMAL" instead. "TEXTCOLOR_BOLD"Map" - TEXTCOLOR_NORMAL" is for single-player only.\n"); + Printf ("Use " TEXTCOLOR_BOLD "changemap" TEXTCOLOR_NORMAL " instead. " TEXTCOLOR_BOLD "Map" + TEXTCOLOR_NORMAL " is for single-player only.\n"); return; } if (argv.argc() > 1) { - if (!P_CheckMapData(argv[1])) + try { - Printf ("No map %s\n", argv[1]); + if (!P_CheckMapData(argv[1])) + { + Printf ("No map %s\n", argv[1]); + } + else + { + G_DeferedInitNew (argv[1]); + } } - else + catch(CRecoverableError &error) { - G_DeferedInitNew (argv[1]); + if (error.GetMessage()) + Printf("%s", error.GetMessage()); } } else @@ -1914,7 +1923,7 @@ CCMD(listmaps) for(unsigned i = 0; i < wadlevelinfos.Size(); i++) { level_info_t *info = &wadlevelinfos[i]; - MapData *map = P_OpenMapData(info->mapname); + MapData *map = P_OpenMapData(info->mapname, true); if (map != NULL) { diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 0de822f626..2ef2b03c54 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -589,7 +589,7 @@ void APowerInvisibility::DoEffect () Super::DoEffect(); // Due to potential interference with other PowerInvisibility items // the effect has to be refreshed each tic. - fixed_t ts = Strength * (special1 + 1); if (ts > FRACUNIT) ts = FRACUNIT; + fixed_t ts = (Strength/100) * (special1 + 1); if (ts > FRACUNIT) ts = FRACUNIT; Owner->alpha = clamp((OPAQUE - ts), 0, OPAQUE); switch (Mode) { @@ -669,7 +669,7 @@ int APowerInvisibility::AlterWeaponSprite (visstyle_t *vis) else if (changed == 1) { // something else set the weapon sprite back to opaque but this item is still active. - fixed_t ts = Strength * (special1 + 1); if (ts > FRACUNIT) ts = FRACUNIT; + fixed_t ts = (Strength/100) * (special1 + 1); if (ts > FRACUNIT) ts = FRACUNIT; vis->alpha = clamp((OPAQUE - ts), 0, OPAQUE); switch (Mode) { @@ -696,7 +696,7 @@ int APowerInvisibility::AlterWeaponSprite (visstyle_t *vis) // Handling of Strife-like cumulative invisibility powerups, the weapon itself shouldn't become invisible if ((vis->alpha < TRANSLUC25 && special1 > 0) || (vis->alpha == 0)) { - vis->alpha = clamp((OPAQUE - Strength), 0, OPAQUE); + vis->alpha = clamp((OPAQUE - (Strength/100)), 0, OPAQUE); vis->colormap = SpecialColormaps[INVERSECOLORMAP].Colormap; } return -1; // This item is valid so another one shouldn't reset the translucency @@ -1697,7 +1697,7 @@ void APowerRegeneration::DoEffect() { if (Owner != NULL && Owner->health > 0 && (level.time & 31) == 0) { - if (P_GiveBody(Owner, 5)) + if (P_GiveBody(Owner, Strength/FRACUNIT)) { S_Sound(Owner, CHAN_ITEM, "*regenerate", 1, ATTN_NORM ); } diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 7e743a0afe..4caa562870 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -38,6 +38,7 @@ class ACustomBridge : public AActor DECLARE_CLASS (ACustomBridge, AActor) public: void BeginPlay (); + void Destroy(); }; IMPLEMENT_CLASS(ACustomBridge) @@ -58,6 +59,25 @@ void ACustomBridge::BeginPlay () } } +void ACustomBridge::Destroy() +{ + // Hexen originally just set a flag to make the bridge balls remove themselves in A_BridgeOrbit. + // But this is not safe with custom bridge balls that do not necessarily call that function. + // So the best course of action is to look for all bridge balls here and destroy them ourselves. + + TThinkerIterator it; + AActor *thing; + + while ((thing = it.Next())) + { + if (thing->target == this) + { + thing->Destroy(); + } + } + Super::Destroy(); +} + // Action functions for the non-Doom bridge -------------------------------- #define ORBIT_RADIUS 15 @@ -89,10 +109,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) // Set rotation radius if (self->target->args[4]) rotationradius = ((self->target->args[4] * self->target->radius) / (100 * FRACUNIT)); - if (self->target->special1) - { - self->SetState (NULL); - } self->angle += rotationspeed; self->x = self->target->x + rotationradius * finecosine[self->angle >> ANGLETOFINESHIFT]; self->y = self->target->y + rotationradius * finesine[self->angle >> ANGLETOFINESHIFT]; @@ -115,7 +131,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) cy = self->y; cz = self->z; startangle = pr_orbit() << 24; - self->special1 = 0; // Spawn triad into world -- may be more than a triad now. int ballcount = self->args[2]==0 ? 3 : self->args[2]; @@ -129,14 +144,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) } } -/* never used -void A_BridgeRemove (AActor *self) -{ - self->special1 = true; // Removing the bridge - self->flags &= ~MF_SOLID; - self->SetState (&ABridge::States[S_FREE_BRIDGE]); -} -*/ // Invisible bridge -------------------------------------------------------- diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index bba5cfdc79..cc559ea94b 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -785,7 +785,7 @@ void AInventory::BecomePickup () LinkToWorld (); P_FindFloorCeiling (this); } - flags = GetDefault()->flags | MF_DROPPED; + flags = (GetDefault()->flags | MF_DROPPED) & ~MF_COUNTITEM; renderflags &= ~RF_INVISIBLE; SetState (SpawnState); } @@ -1792,7 +1792,10 @@ bool ABackpackItem::HandlePickup (AInventory *item) AInventory *ABackpackItem::CreateTossable () { ABackpackItem *pack = static_cast(Super::CreateTossable()); - pack->bDepleted = true; + if (pack != NULL) + { + pack->bDepleted = true; + } return pack; } diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp index 293b17d3b6..adfc09b6e6 100644 --- a/src/g_shared/a_randomspawner.cpp +++ b/src/g_shared/a_randomspawner.cpp @@ -121,7 +121,11 @@ class ARandomSpawner : public AActor AActor * newmobj = NULL; bool boss = false; Super::PostBeginPlay(); - if (Species == NAME_None) { Destroy(); return; } + if (Species == NAME_None) + { + Destroy(); + return; + } const PClass * cls = PClass::FindClass(Species); if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile. { @@ -142,8 +146,9 @@ class ARandomSpawner : public AActor newmobj->args[4] = args[4]; newmobj->special1 = special1; newmobj->special2 = special2; - newmobj->SpawnFlags = SpawnFlags; + newmobj->SpawnFlags = SpawnFlags & ~MTF_SECRET; // MTF_SECRET needs special treatment to avoid incrementing the secret counter twice. It had already been processed for the spawner itself. newmobj->HandleSpawnFlags(); + newmobj->SpawnFlags = SpawnFlags; newmobj->tid = tid; newmobj->AddToHash(); newmobj->velx = velx; diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index fcadb0d1be..0849fd3544 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -352,11 +352,8 @@ int FMugShot::UpdateState(player_t *player, StateFlags stateflags) SetState("grin", false); return 0; } - else if (CurrentState == NULL) - { - bEvilGrin = false; - } } + bEvilGrin = false; bool ouch = (!st_oldouch && FaceHealth - player->health > ST_MUCHPAIN) || (st_oldouch && player->health - FaceHealth > ST_MUCHPAIN); if (player->damagecount && diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 0ceea11a00..547f6534ed 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -53,6 +53,7 @@ #include "d_player.h" #include "farchive.h" #include "a_hexenglobal.h" +#include "gstrings.h" #include "../version.h" @@ -1375,8 +1376,8 @@ void DBaseStatusBar::Draw (EHudState state) // Draw monster count if (am_showmonsters) { - mysnprintf (line, countof(line), "MONSTERS:" TEXTCOLOR_GREY " %d/%d", - level.killed_monsters, level.total_monsters); + mysnprintf (line, countof(line), "%s" TEXTCOLOR_GREY " %d/%d", + GStrings("AM_MONSTERS"), level.killed_monsters, level.total_monsters); screen->DrawText (SmallFont, highlight, 8, y, line, DTA_CleanNoMove, true, TAG_DONE); y += height; @@ -1385,8 +1386,8 @@ void DBaseStatusBar::Draw (EHudState state) // Draw secret count if (am_showsecrets) { - mysnprintf (line, countof(line), "SECRETS:" TEXTCOLOR_GREY " %d/%d", - level.found_secrets, level.total_secrets); + mysnprintf (line, countof(line), "%s" TEXTCOLOR_GREY " %d/%d", + GStrings("AM_SECRETS"), level.found_secrets, level.total_secrets); screen->DrawText (SmallFont, highlight, 8, y, line, DTA_CleanNoMove, true, TAG_DONE); y += height; @@ -1395,8 +1396,8 @@ void DBaseStatusBar::Draw (EHudState state) // Draw item count if (am_showitems) { - mysnprintf (line, countof(line), "ITEMS:" TEXTCOLOR_GREY " %d/%d", - level.found_items, level.total_items); + mysnprintf (line, countof(line), "%s" TEXTCOLOR_GREY " %d/%d", + GStrings("AM_ITEMS"), level.found_items, level.total_items); screen->DrawText (SmallFont, highlight, 8, y, line, DTA_CleanNoMove, true, TAG_DONE); } diff --git a/src/gi.cpp b/src/gi.cpp index 75476c8005..d9d58dc9e6 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -184,6 +184,20 @@ const char* GameInfoBorders[] = gameinfo.key.color = NAME_Null; \ } +#define GAMEINFOKEY_MUSIC(key, order, variable) \ + else if(nextKey.CompareNoCase(variable) == 0) \ + { \ + sc.MustGetToken(TK_StringConst); \ + gameinfo.order = 0; \ + char *colon = strchr (sc.String, ':'); \ + if (colon) \ + { \ + gameinfo.order = atoi(colon+1); \ + *colon = 0; \ + } \ + gameinfo.key = sc.String; \ + } + void FMapInfoParser::ParseGameInfo() { @@ -286,12 +300,12 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_STRINGARRAY(creditPages, "CreditPage", 8, true) GAMEINFOKEY_STRINGARRAY(PlayerClasses, "addplayerclasses", 0, false) GAMEINFOKEY_STRINGARRAY(PlayerClasses, "playerclasses", 0, true) - GAMEINFOKEY_STRING(titleMusic, "titleMusic") + GAMEINFOKEY_MUSIC(titleMusic, titleOrder, "titleMusic") GAMEINFOKEY_FLOAT(titleTime, "titleTime") GAMEINFOKEY_FLOAT(advisoryTime, "advisoryTime") GAMEINFOKEY_FLOAT(pageTime, "pageTime") GAMEINFOKEY_STRING(chatSound, "chatSound") - GAMEINFOKEY_STRING(finaleMusic, "finaleMusic") + GAMEINFOKEY_MUSIC(finaleMusic, finaleOrder, "finaleMusic") GAMEINFOKEY_CSTRING(finaleFlat, "finaleFlat", 8) GAMEINFOKEY_STRINGARRAY(finalePages, "finalePage", 8, true) GAMEINFOKEY_STRINGARRAY(infoPages, "addinfoPage", 8, false) @@ -309,7 +323,7 @@ void FMapInfoParser::ParseGameInfo() GAMEINFOKEY_COLOR(defaultbloodparticlecolor, "defaultbloodparticlecolor") GAMEINFOKEY_STRING(backpacktype, "backpacktype") GAMEINFOKEY_STRING(statusbar, "statusbar") - GAMEINFOKEY_STRING(intermissionMusic, "intermissionMusic") + GAMEINFOKEY_MUSIC(intermissionMusic, intermissionOrder, "intermissionMusic") GAMEINFOKEY_STRING(CursorPic, "CursorPic") GAMEINFOKEY_BOOL(noloopfinalemusic, "noloopfinalemusic") GAMEINFOKEY_BOOL(drawreadthis, "drawreadthis") diff --git a/src/gi.h b/src/gi.h index ff678df074..6b887e1dd0 100644 --- a/src/gi.h +++ b/src/gi.h @@ -91,11 +91,13 @@ struct gameinfo_t TArray PlayerClasses; FString titleMusic; + int titleOrder; float titleTime; float advisoryTime; float pageTime; FString chatSound; FString finaleMusic; + int finaleOrder; char finaleFlat[9]; char borderFlat[9]; char SkyFlatName[9]; @@ -114,6 +116,7 @@ struct gameinfo_t FString backpacktype; FString statusbar; FString intermissionMusic; + int intermissionOrder; FString CursorPic; DWORD dimcolor; float dimamount; diff --git a/src/gstrings.h b/src/gstrings.h index 41e37dbc50..770510cfdd 100644 --- a/src/gstrings.h +++ b/src/gstrings.h @@ -42,11 +42,6 @@ extern FStringTable GStrings; -// QuitGame messages -#define NUM_QUITDOOMMESSAGES 14 -#define NUM_QUITSTRIFEMESSAGES 8 -#define NUM_QUITCHEXMESSAGES 7 - extern const char *endmsg[]; diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 6ee67006e4..91090e4328 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -80,7 +80,7 @@ void DIntermissionScreen::Init(FIntermissionAction *desc, bool first) if (desc->mMusic.IsEmpty()) { // only start the default music if this is the first action in an intermission - if (first) S_ChangeMusic (gameinfo.finaleMusic, 0, desc->mMusicLooping); + if (first) S_ChangeMusic (gameinfo.finaleMusic, gameinfo.finaleOrder, desc->mMusicLooping); } else { diff --git a/src/m_argv.cpp b/src/m_argv.cpp index 54d9ffda46..816a2d54c0 100644 --- a/src/m_argv.cpp +++ b/src/m_argv.cpp @@ -35,6 +35,7 @@ #include #include "m_argv.h" #include "cmdlib.h" +#include "i_system.h" IMPLEMENT_CLASS (DArgs) @@ -391,6 +392,14 @@ void DArgs::CollectFiles(const char *param, const char *extension) } } + // Optional: Replace short path names with long path names +#ifdef _WIN32 + for (i = 0; i < work.Size(); ++i) + { + work[i] = I_GetLongPathName(work[i]); + } +#endif + // Step 3: Add work back to Argv, as long as it's non-empty. if (work.Size() > 0) { diff --git a/src/m_fixed.h b/src/m_fixed.h index 61080d73d2..71b3981241 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -12,7 +12,7 @@ #include #include "doomtype.h" -#if defined(__GNUC__) && defined(__i386__) +#if defined(__GNUC__) && defined(__i386__) && !defined(__clang__) #include "gccinlines.h" #elif defined(_MSC_VER) && defined(_M_IX86) #include "mscinlines.h" diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 99ac599380..9a87bb806b 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -131,7 +131,8 @@ void ClearSaveGames() { for(unsigned i=0;ibNoDelete) + delete DLoadSaveMenu::SaveGames[i]; } DLoadSaveMenu::SaveGames.Clear(); } @@ -898,7 +899,7 @@ IMPLEMENT_CLASS(DSaveMenu) DSaveMenu::DSaveMenu(DMenu *parent, FListMenuDescriptor *desc) : DLoadSaveMenu(parent, desc) { - strcpy (NewSaveNode.Title, ""); + strcpy (NewSaveNode.Title, GStrings["NEWSAVE"]); NewSaveNode.bNoDelete = true; SaveGames.Insert(0, &NewSaveNode); TopItem = 0; diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index 8a6e6720df..1d1d023830 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -166,15 +166,18 @@ public: NewWidth = SCREENWIDTH; NewHeight = SCREENHEIGHT; } - OldWidth = SCREENWIDTH; - OldHeight = SCREENHEIGHT; - OldBits = DisplayBits; - NewBits = BitTranslate[DummyDepthCvar]; - setmodeneeded = true; - testingmode = I_GetTime(false) + 5 * TICRATE; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); - SetModesMenu (NewWidth, NewHeight, NewBits); - return true; + else + { + OldWidth = SCREENWIDTH; + OldHeight = SCREENHEIGHT; + OldBits = DisplayBits; + NewBits = BitTranslate[DummyDepthCvar]; + setmodeneeded = true; + testingmode = I_GetTime(false) + 5 * TICRATE; + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); + SetModesMenu (NewWidth, NewHeight, NewBits); + return true; + } } return Super::Responder(ev); } @@ -348,7 +351,7 @@ void M_InitVideoModesMenu () static bool GetSelectedSize (int *width, int *height) { FOptionMenuDescriptor *opt = GetVideoModeMenu(); - if (opt != NULL) + if (opt != NULL && (unsigned)opt->mSelectedItem < opt->mItems.Size()) { int line = opt->mSelectedItem; int hsel; diff --git a/src/namedef.h b/src/namedef.h index 27b6376b22..14e4ec7ac3 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -442,6 +442,7 @@ xx(Alphafloor) xx(Alphaceiling) xx(Renderstylefloor) xx(Renderstyleceiling) +xx(Waterzone) xx(offsetx_top) xx(offsety_top) @@ -464,6 +465,7 @@ xx(blockprojectiles) xx(blockuse) xx(hidden) xx(blocksight) +xx(blockhitscan) xx(Renderstyle) @@ -567,3 +569,4 @@ xx(NeverSwitchOnPickup) xx(MoveBob) xx(StillBob) xx(PlayerClass) +xx(Wi_NoAutostartMap) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index cd55caefb3..32a70cd153 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -46,6 +46,7 @@ #include "p_acs.h" #include "p_saveg.h" #include "p_lnspec.h" +#include "p_enemy.h" #include "m_random.h" #include "doomstat.h" #include "c_console.h" @@ -112,6 +113,9 @@ FRandom pr_acs ("ACS"); #define NOT_FLOOR 8 #define NOT_CEILING 16 +// LineAtack flags +#define FHF_NORANDOMPUFFZ 1 + // SpawnDecal flags #define SDF_ABSANGLE 1 #define SDF_PERMANENT 2 @@ -571,11 +575,7 @@ int ACSStringPool::InsertString(FString &str, unsigned int h, unsigned int bucke } else { // Scan for the next free entry - unsigned int i; - for (i = FirstFreeEntry + 1; i < Pool.Size() && Pool[i].Next != FREE_ENTRY; ++i) - { - } - FirstFreeEntry = i; + FindFirstFreeEntry(FirstFreeEntry + 1); } PoolEntry *entry = &Pool[index]; entry->Str = str; @@ -586,6 +586,23 @@ int ACSStringPool::InsertString(FString &str, unsigned int h, unsigned int bucke return index | STRPOOL_LIBRARYID_OR; } +//============================================================================ +// +// ACSStringPool :: FindFirstFreeEntry +// +// Finds the first free entry, starting at base. +// +//============================================================================ + +void ACSStringPool::FindFirstFreeEntry(unsigned base) +{ + while (base < Pool.Size() && Pool[base].Next != FREE_ENTRY) + { + base++; + } + FirstFreeEntry = base; +} + //============================================================================ // // ACSStringPool :: ReadStrings @@ -634,6 +651,7 @@ void ACSStringPool::ReadStrings(PNGHandle *png, DWORD id) { delete[] str; } + FindFirstFreeEntry(0); } } @@ -686,6 +704,7 @@ void ACSStringPool::Dump() const Printf("%4u. (%2d) \"%s\"\n", i, Pool[i].LockCount, Pool[i].Str.GetChars()); } } + Printf("First free %u\n", FirstFreeEntry); } //============================================================================ @@ -3509,6 +3528,8 @@ enum APROP_Radius = 36, APROP_ReactionTime = 37, APROP_MeleeRange = 38, + APROP_ViewHeight = 39, + APROP_AttackZOffset = 40 }; // These are needed for ACS's APROP_RenderStyle @@ -3724,6 +3745,16 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) actor->reactiontime = value; break; + case APROP_ViewHeight: + if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) + static_cast(actor)->ViewHeight = value; + break; + + case APROP_AttackZOffset: + if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) + static_cast(actor)->AttackZOffset = value; + break; + default: // do nothing. break; @@ -3796,6 +3827,23 @@ int DLevelScript::GetActorProperty (int tid, int property, const SDWORD *stack, case APROP_Radius: return actor->radius; case APROP_ReactionTime:return actor->reactiontime; case APROP_MeleeRange: return actor->meleerange; + case APROP_ViewHeight: if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) + { + return static_cast(actor)->ViewHeight; + } + else + { + return 0; + } + case APROP_AttackZOffset: + if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn))) + { + return static_cast(actor)->AttackZOffset; + } + else + { + return 0; + } case APROP_SeeSound: return GlobalACSStrings.AddString(actor->SeeSound, stack, stackdepth); case APROP_AttackSound: return GlobalACSStrings.AddString(actor->AttackSound, stack, stackdepth); @@ -3848,6 +3896,8 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_Radius: case APROP_ReactionTime: case APROP_MeleeRange: + case APROP_ViewHeight: + case APROP_AttackZOffset: return (GetActorProperty(tid, property, NULL, 0) == value); // Boolean values need to compare to a binary version of value @@ -4199,6 +4249,7 @@ enum EACSFunctions ACSF_PlayActorSound, ACSF_SpawnDecal, ACSF_CheckFont, + ACSF_DropItem, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -4966,10 +5017,13 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const FName pufftype = argCount > 4 && args[4]? FName(FBehavior::StaticLookupString(args[4])) : NAME_BulletPuff; FName damagetype = argCount > 5 && args[5]? FName(FBehavior::StaticLookupString(args[5])) : NAME_None; fixed_t range = argCount > 6 && args[6]? args[6] : MISSILERANGE; + int flags = argCount > 7 && args[7]? args[7] : 0; + + int fhflags = (flags & FHF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; if (args[0] == 0) { - P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype); + P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags); } else { @@ -4978,7 +5032,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const while ((source = it.Next()) != NULL) { - P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype); + P_LineAttack(activator, angle, range, pitch, damage, damagetype, pufftype, fhflags); } } } @@ -5025,7 +5079,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) { S_Sound(spot, chan, sid, vol, atten); } - else if (!S_IsActorPlayingSomething(spot, chan, sid)) + else if (!S_IsActorPlayingSomething(spot, chan & 7, sid)) { S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten); } @@ -5198,6 +5252,39 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) // bool CheckFont(str fontname) return V_GetFont(FBehavior::StaticLookupString(args[0])) != NULL; + case ACSF_DropItem: + { + const char *type = FBehavior::StaticLookupString(args[1]); + int amount = argCount >= 3? args[2] : -1; + int chance = argCount >= 4? args[3] : 256; + const PClass *cls = PClass::FindClass(type); + int cnt = 0; + if (cls != NULL) + { + if (args[0] == 0) + { + if (activator != NULL) + { + P_DropItem(activator, cls, amount, chance); + cnt++; + } + } + else + { + FActorIterator it(args[0]); + AActor *actor; + + while ((actor = it.Next()) != NULL) + { + P_DropItem(actor, cls, amount, chance); + cnt++; + } + } + return cnt; + } + break; + } + default: break; } @@ -5556,7 +5643,8 @@ int DLevelScript::RunScript () case PCD_PUSHFUNCTION: { int funcnum = NEXTBYTE; - PushToStack(funcnum | activeBehavior->GetLibraryID()); + // Not technically a string, but since we use the same tagging mechanism + PushToStack(TAGSTR(funcnum)); break; } case PCD_CALL: @@ -5572,7 +5660,7 @@ int DLevelScript::RunScript () if(pcd == PCD_CALLSTACK) { funcnum = STACK(1); - module = FBehavior::StaticGetModule(funcnum>>16); + module = FBehavior::StaticGetModule(funcnum>>LIBRARYID_SHIFT); --sp; funcnum &= 0xFFFF; // Clear out tag @@ -8321,7 +8409,7 @@ scriptwait: { int playernum = STACK(1); - if (playernum < 0 || playernum >= MAXPLAYERS || !playeringame[playernum] || players[playernum].camera == NULL) + if (playernum < 0 || playernum >= MAXPLAYERS || !playeringame[playernum] || players[playernum].camera == NULL || players[playernum].camera->player != NULL) { STACK(1) = -1; } @@ -8449,7 +8537,8 @@ scriptwait: case PCD_SAVESTRING: // Saves the string { - PushToStack(GlobalACSStrings.AddString(work, Stack, sp)); + const int str = GlobalACSStrings.AddString(work, Stack, sp); + PushToStack(str); STRINGBUILDER_FINISH(work); } break; diff --git a/src/p_acs.h b/src/p_acs.h index 1a0fb3f60c..ec41ab886c 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -100,6 +100,7 @@ public: private: int FindString(const char *str, size_t len, unsigned int h, unsigned int bucketnum); int InsertString(FString &str, unsigned int h, unsigned int bucketnum, const SDWORD *stack, int stackdepth); + void FindFirstFreeEntry(unsigned int base); enum { NUM_BUCKETS = 251 }; enum { FREE_ENTRY = 0xFFFFFFFE }; // Stored in PoolEntry's Next field diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 417343f211..f2fd7b0bf8 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -698,6 +698,7 @@ static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, mapthings[count].SkillFilter = 0xffff; mapthings[count].flags = MTF_SINGLE|MTF_COOPERATIVE|MTF_DEATHMATCH; mapthings[count].special = 0; + mapthings[count].gravity = FRACUNIT; if (xsprites != NULL && sprites[i].lotag == 710) { // Blood ambient sound diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 380b72de4e..e51389ce8d 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -752,7 +752,10 @@ public: { ReplyText = GStrings(ReplyText + 1); } - FBrokenLines *ReplyLines = V_BreakLines (SmallFont, 320-50-10, ReplyText); + FString ReplyString = ReplyText; + if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->ItemCheck[0].Amount); + + FBrokenLines *ReplyLines = V_BreakLines (SmallFont, 320-50-10, ReplyString); mResponses.Push(mResponseLines.Size()); for (j = 0; ReplyLines[j].Width >= 0; ++j) @@ -958,6 +961,7 @@ public: if (CurNode->SpeakerName != NULL) { speakerName = CurNode->SpeakerName; + if (speakerName[0] == '$') speakerName = GStrings(speakerName+1); } else { @@ -1151,7 +1155,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang break; } } - if (jump) + if (jump && CurNode->ItemCheckNode > 0) { int root = pc->player->ConversationNPC->ConversationRoot; CurNode = StrifeDialogues[root + CurNode->ItemCheckNode - 1]; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 81a58ac158..359b49f9c5 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -915,7 +915,7 @@ void P_NewChaseDir(AActor * actor) // MBF's monster_backing option. Made an actor flag instead. Also cleaned the code up to make it readable. // Todo: implement the movement logic AActor *target = actor->target; - if (target->health > 0 && !actor->IsFriend(target)) + if (target->health > 0 && !actor->IsFriend(target) && target != actor->goal) { // Live enemy target if (actor->flags3 & MF3_AVOIDMELEE) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 7a14e4d447..2665f69ba6 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -252,7 +252,7 @@ static bool LoadGLVertexes(FileReader * lump) // GLNodes V1 and V4 are unsupported. // V1 because the precision is insufficient and // V4 due to the missing partner segs - Printf("GL nodes v%d found. This format is not supported by "GAMENAME"\n", + Printf("GL nodes v%d found. This format is not supported by " GAMENAME "\n", (*(int *)gldata == gNd4)? 4:1); delete [] gldata; diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index c46cb40f74..0ee955a826 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -657,10 +657,38 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) FState *diestate = NULL; + int gibhealth = GibHealth(); + int iflags4 = inflictor == NULL ? 0 : inflictor->flags4; + bool extremelydead = ((health < gibhealth || iflags4 & MF4_EXTREMEDEATH) && !(iflags4 & MF4_NOEXTREMEDEATH)); + + // Special check for 'extreme' damage type to ensure that it gets recorded properly as an extreme death for subsequent checks. + if (DamageType == NAME_Extreme) + { + extremelydead = true; + DamageType = NAME_None; + } + + // find the appropriate death state. The order is: + // + // 1. If damagetype is not 'none' and death is extreme, try a damage type specific extreme death state + // 2. If no such state is found or death is not extreme try a damage type specific normal death state + // 3. If damagetype is 'ice' and actor is a monster or player, try the generic freeze death (unless prohibited) + // 4. If no state has been found and death is extreme, try the extreme death state + // 5. If no such state is found or death is not extreme try the regular death state. + // 6. If still no state has been found, destroy the actor immediately. if (DamageType != NAME_None) { - diestate = FindState (NAME_Death, DamageType, true); + if (extremelydead) + { + FName labels[] = { NAME_Death, NAME_Extreme, DamageType }; + diestate = FindState(3, labels, true); + } + if (diestate == NULL) + { + diestate = FindState (NAME_Death, DamageType, true); + if (diestate != NULL) extremelydead = false; + } if (diestate == NULL) { if (DamageType == NAME_Ice) @@ -669,15 +697,13 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) if (!deh.NoAutofreeze && !(flags4 & MF4_NOICEDEATH) && (player || (flags3 & MF3_ISMONSTER))) { diestate = FindState(NAME_GenericFreezeDeath); + extremelydead = false; } } } } if (diestate == NULL) { - int flags4 = inflictor == NULL ? 0 : inflictor->flags4; - - int gibhealth = GibHealth(); // Don't pass on a damage type this actor cannot handle. // (most importantly, prevent barrels from passing on ice damage.) @@ -687,33 +713,43 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags) DamageType = NAME_None; } - if ((health < gibhealth || flags4 & MF4_EXTREMEDEATH) && !(flags4 & MF4_NOEXTREMEDEATH)) + if (extremelydead) { // Extreme death diestate = FindState (NAME_Death, NAME_Extreme, true); - // If a non-player, mark as extremely dead for the crash state. - if (diestate != NULL && player == NULL && health >= gibhealth) - { - health = gibhealth - 1; - } - // For players, mark the appropriate flag. - else if (player != NULL) - { - player->cheats |= CF_EXTREMELYDEAD; - } } if (diestate == NULL) { // Normal death + extremelydead = false; diestate = FindState (NAME_Death); } } + if (extremelydead) + { + // We'll only get here if an actual extreme death state was used. + + // For players, mark the appropriate flag. + if (player != NULL) + { + player->cheats |= CF_EXTREMELYDEAD; + } + // If a non-player, mark as extremely dead for the crash state. + else if (health >= gibhealth) + { + health = gibhealth - 1; + } + } + if (diestate != NULL) { SetState (diestate); - tics -= pr_killmobj() & 3; - if (tics < 1) - tics = 1; + if (tics > 1) + { + tics -= pr_killmobj() & 3; + if (tics < 1) + tics = 1; + } } else { @@ -932,7 +968,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, { // actor is invulnerable if (target->player == NULL) { - if (inflictor == NULL || !(inflictor->flags3 & MF3_FOILINVUL)) + if (inflictor == NULL || (!(inflictor->flags3 & MF3_FOILINVUL) && !(flags & DMG_FOILINVUL))) { return -1; } @@ -1107,7 +1143,9 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, && (pr_damagemobj()&1) // [RH] But only if not too fast and not flying && thrust < 10*FRACUNIT - && !(target->flags & MF_NOGRAVITY)) + && !(target->flags & MF_NOGRAVITY) + && (inflictor == NULL || !(inflictor->flags5 & MF5_NOFORWARDFALL)) + ) { ang += ANG180; thrust *= 4; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 67df3def1e..12c8771166 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1562,9 +1562,21 @@ FUNC(LS_Thing_SetGoal) ok = true; if (self->flags & MF_SHOOTABLE) { + if (self->target == self->goal) + { // Targeting a goal already? -> don't target it anymore. + // A_Look will set it to the goal, presuming no real targets + // come into view by then. + self->target = NULL; + } self->goal = goal; - if (arg3 == 0) self->flags5 &=~ MF5_CHASEGOAL; - else self->flags5 |= MF5_CHASEGOAL; + if (arg3 == 0) + { + self->flags5 &= ~MF5_CHASEGOAL; + } + else + { + self->flags5 |= MF5_CHASEGOAL; + } if (self->target == NULL) { self->reactiontime = arg2 * TICRATE; @@ -2545,6 +2557,7 @@ FUNC(LS_Line_SetBlocking) ML_RAILING, ML_BLOCKUSE, ML_BLOCKSIGHT, + ML_BLOCKHITSCAN, -1 }; @@ -2813,6 +2826,11 @@ FUNC(LS_SetPlayerProperty) { int i; + if ((ib_compatflags & BCOMPATF_LINKFROZENPROPS) && (mask & (CF_FROZEN | CF_TOTALLYFROZEN))) + { // Clearing one of these properties clears both of them (if the compat flag is set.) + mask = CF_FROZEN | CF_TOTALLYFROZEN; + } + for (i = 0; i < MAXPLAYERS; i++) { if (!playeringame[i]) diff --git a/src/p_local.h b/src/p_local.h index a4da0a04b7..e7fb2cb7d5 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -554,6 +554,7 @@ enum EDmgFlags DMG_FORCED = 8, DMG_NO_FACTOR = 16, DMG_PLAYERATTACK = 32, + DMG_FOILINVUL = 64, }; diff --git a/src/p_map.cpp b/src/p_map.cpp index 17bb3e1359..8b0b605c63 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -53,11 +53,6 @@ #include "r_data/r_translate.h" #include "g_level.h" -#define WATER_SINK_FACTOR 3 -#define WATER_SINK_SMALL_FACTOR 4 -#define WATER_SINK_SPEED (FRACUNIT/2) -#define WATER_JUMP_SPEED (FRACUNIT*7/2) - CVAR (Bool, cl_bloodsplats, true, CVAR_ARCHIVE) CVAR (Int, sv_smartaim, 0, CVAR_ARCHIVE|CVAR_SERVERINFO) CVAR (Bool, cl_doautoaim, false, CVAR_ARCHIVE) @@ -3563,7 +3558,7 @@ AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, else tflags = TRACE_NoSky|TRACE_Impact; if (!Trace (t1->x, t1->y, shootz, t1->Sector, vx, vy, vz, distance, - MF_SHOOTABLE, ML_BLOCKEVERYTHING, t1, trace, + MF_SHOOTABLE, ML_BLOCKEVERYTHING|ML_BLOCKHITSCAN, t1, trace, tflags, hitGhosts ? CheckForGhost : CheckForSpectral)) { // hit nothing if (puffDefaults == NULL) @@ -4359,14 +4354,17 @@ bool P_NoWayTraverse (AActor *usething, fixed_t endx, fixed_t endy) void P_UseLines (player_t *player) { angle_t angle; - fixed_t x1, y1; + fixed_t x1, y1, usedist; bool foundline; foundline = false; angle = player->mo->angle >> ANGLETOFINESHIFT; - x1 = player->mo->x + (USERANGE>>FRACBITS)*finecosine[angle]; - y1 = player->mo->y + (USERANGE>>FRACBITS)*finesine[angle]; + usedist = player->mo->UseRange; + + // [NS] Now queries the Player's UseRange. + x1 = player->mo->x + FixedMul(usedist, finecosine[angle]); + y1 = player->mo->y + FixedMul(usedist, finesine[angle]); // old code: // @@ -4398,13 +4396,20 @@ void P_UseLines (player_t *player) bool P_UsePuzzleItem (AActor *PuzzleItemUser, int PuzzleItemType) { int angle; - fixed_t x1, y1, x2, y2; + fixed_t x1, y1, x2, y2, usedist; angle = PuzzleItemUser->angle>>ANGLETOFINESHIFT; x1 = PuzzleItemUser->x; y1 = PuzzleItemUser->y; - x2 = x1+(USERANGE>>FRACBITS)*finecosine[angle]; - y2 = y1+(USERANGE>>FRACBITS)*finesine[angle]; + + // [NS] If it's a Player, get their UseRange. + if (PuzzleItemUser->player) + usedist = PuzzleItemUser->player->mo->UseRange; + else + usedist = USERANGE; + + x2 = x1 + FixedMul(usedist, finecosine[angle]); + y2 = y1 + FixedMul(usedist, finesine[angle]); FPathTraverse it(x1, y1, x2, y2, PT_ADDLINES|PT_ADDTHINGS); intercept_t *in; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 41b41aec67..03bbb4d8d2 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3993,8 +3993,12 @@ void AActor::HandleSpawnFlags () } if (SpawnFlags & MTF_SECRET) { - //Printf("Secret %s in sector %i!\n", GetTag(), Sector->sectornum); - flags5 |= MF5_COUNTSECRET; + if (!(flags5 & MF5_COUNTSECRET)) + { + //Printf("Secret %s in sector %i!\n", GetTag(), Sector->sectornum); + flags5 |= MF5_COUNTSECRET; + level.total_secrets++; + } } } @@ -4712,6 +4716,10 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) mobj->SpawnPoint[2] = mthing->z; mobj->SpawnAngle = mthing->angle; mobj->SpawnFlags = mthing->flags; + if (mthing->gravity < 0) mobj->gravity = -mthing->gravity; + else if (mthing->gravity > 0) mobj->gravity = FixedMul(mobj->gravity, mthing->gravity); + else mobj->flags &= ~MF_NOGRAVITY; + P_FindFloorCeiling(mobj, FFCF_SAMESECTOR | FFCF_ONLY3DFLOORS | FFCF_3DRESTRICT); if (!(mobj->flags2 & MF2_ARGSDEFINED)) @@ -5922,7 +5930,15 @@ void AActor::Crash() if (DamageType != NAME_None) { - crashstate = FindState(NAME_Crash, DamageType, true); + if (health < GibHealth()) + { // Extreme death + FName labels[] = { NAME_Crash, NAME_Extreme, DamageType }; + crashstate = FindState (3, labels, true); + } + if (crashstate == NULL) + { // Normal death + crashstate = FindState(NAME_Crash, DamageType, true); + } } if (crashstate == NULL) { diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index a045c50989..bf0da0cbe3 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -256,11 +256,19 @@ static void CopyPlayer (player_t *dst, player_t *src, const char *name) { // The userinfo needs to be saved for real players, but it // needs to come from the save for bots. - userinfo_t uibackup = dst->userinfo; + userinfo_t uibackup; + userinfo_t uibackup2; + + uibackup.TransferFrom(dst->userinfo); + uibackup2.TransferFrom(src->userinfo); + int chasecam = dst->cheats & CF_CHASECAM; // Remember the chasecam setting bool attackdown = dst->attackdown; bool usedown = dst->usedown; - *dst = *src; + + + *dst = *src; // To avoid memory leaks at this point the userinfo in src must be empty which is taken care of by the TransferFrom call above. + dst->cheats |= chasecam; if (dst->isbot) @@ -276,10 +284,11 @@ static void CopyPlayer (player_t *dst, player_t *src, const char *name) } bglobal.botnum++; bglobal.botingame[dst - players] = true; + dst->userinfo.TransferFrom(uibackup2); } else { - dst->userinfo = uibackup; + dst->userinfo.TransferFrom(uibackup); } // Validate the skin dst->userinfo.SkinNumChanged(R_FindSkin(skins[dst->userinfo.GetSkin()].name, dst->CurrentPlayerClass)); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 0f6917f8df..3693e9f7ea 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -250,7 +250,7 @@ static int GetMapIndex(const char *mapname, int lastindex, const char *lumpname, // //=========================================================================== -MapData *P_OpenMapData(const char * mapname) +MapData *P_OpenMapData(const char * mapname, bool justcheck) { MapData * map = new MapData; FileReader * wadReader = NULL; @@ -329,7 +329,20 @@ MapData *P_OpenMapData(const char * mapname) // Since levels must be stored in WADs they can't really have full // names and for any valid level lump this always returns the short name. const char * lumpname = Wads.GetLumpFullName(lump_name + i); - index = GetMapIndex(mapname, index, lumpname, i != 1 || Wads.LumpLength(lump_name + i) == 0); + try + { + index = GetMapIndex(mapname, index, lumpname, !justcheck); + } + catch(...) + { + delete map; + throw; + } + if (index == -2) + { + delete map; + return NULL; + } if (index == ML_BEHAVIOR) map->HasBehavior = true; // The next lump is not part of this map anymore @@ -461,7 +474,20 @@ MapData *P_OpenMapData(const char * mapname) if (i>0) { - index = GetMapIndex(maplabel, index, lumpname, true); + try + { + index = GetMapIndex(maplabel, index, lumpname, !justcheck); + } + catch(...) + { + delete map; + throw; + } + if (index == -2) + { + delete map; + return NULL; + } if (index == ML_BEHAVIOR) map->HasBehavior = true; // The next lump is not part of this map anymore @@ -492,7 +518,7 @@ MapData *P_OpenMapData(const char * mapname) bool P_CheckMapData(const char *mapname) { - MapData *mapd = P_OpenMapData(mapname); + MapData *mapd = P_OpenMapData(mapname, true); if (mapd == NULL) return false; delete mapd; return true; @@ -1734,6 +1760,7 @@ void P_LoadThings (MapData * map) memset (&mti[i], 0, sizeof(mti[i])); + mti[i].gravity = FRACUNIT; mti[i].Conversation = 0; mti[i].SkillFilter = MakeSkill(flags); mti[i].ClassFilter = 0xffff; // Doom map format doesn't have class flags so spawn for all player classes @@ -1809,6 +1836,7 @@ void P_LoadThings2 (MapData * map) mti[i].ClassFilter = (mti[i].flags & MTF_CLASS_MASK) >> MTF_CLASS_SHIFT; mti[i].flags &= ~(MTF_SKILLMASK|MTF_CLASS_MASK); mti[i].Conversation = 0; + mti[i].gravity = FRACUNIT; } delete[] mtp; } @@ -3592,7 +3620,7 @@ void P_SetupLevel (char *lumpname, int position) P_FreeLevelData (); interpolator.ClearInterpolations(); // [RH] Nothing to interpolate on a fresh level. - MapData *map = P_OpenMapData(lumpname); + MapData *map = P_OpenMapData(lumpname, true); if (map == NULL) { I_Error("Unable to open map '%s'\n", lumpname); diff --git a/src/p_setup.h b/src/p_setup.h index 6e0a90a1d7..4a41a76f98 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -94,7 +94,7 @@ struct MapData void GetChecksum(BYTE cksum[16]); }; -MapData * P_OpenMapData(const char * mapname); +MapData * P_OpenMapData(const char * mapname, bool justcheck); bool P_CheckMapData(const char * mapname); diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 3a63577484..63f7c1c89e 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -639,12 +639,21 @@ void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass, { next = actor->snext; // Only affect actors touching the 3D floor - if (actor->z + actor->height > sec->floorplane.ZatPoint(actor->x, actor->y)) + fixed_t z1 = sec->floorplane.ZatPoint(actor->x, actor->y); + fixed_t z2 = sec->ceilingplane.ZatPoint(actor->x, actor->y); + if (z2 < z1) + { + // Account for Vavoom-style 3D floors + fixed_t zz = z1; + z1 = z2; + z2 = zz; + } + if (actor->z + actor->height > z1) { // If DAMAGE_IN_AIR is used, anything not beneath the 3D floor will be // damaged (so, anything touching it or above it). Other 3D floors between // the actor and this one will not stop this effect. - if ((flags & DAMAGE_IN_AIR) || actor->z <= sec->ceilingplane.ZatPoint(actor->x, actor->y)) + if ((flags & DAMAGE_IN_AIR) || actor->z <= z2) { // Here we pass the DAMAGE_IN_AIR flag to disable the floor check, since it // only works with the real sector's floor. We did the appropriate height checks diff --git a/src/p_spec.h b/src/p_spec.h index 4f67f87ffb..57d2169729 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -763,7 +763,7 @@ protected: fixed_t stairsize, fixed_t speed, int delay, int reset, int igntxt, int usespecials); friend bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, - fixed_t speed, fixed_t height, int crush, int change, bool hexencrush, bool hereticlower=false); + fixed_t speed, fixed_t height, int crush, int change, bool hexencrush, bool hereticlower); friend bool EV_FloorCrushStop (int tag); friend bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed); private: @@ -774,7 +774,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line, fixed_t stairsize, fixed_t speed, int delay, int reset, int igntxt, int usespecials); bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, - fixed_t speed, fixed_t height, int crush, int change, bool hexencrush, bool hereticlower); + fixed_t speed, fixed_t height, int crush, int change, bool hexencrush, bool hereticlower=false); bool EV_FloorCrushStop (int tag); bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed); diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index c1d18fd4c7..fc5964737d 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -475,6 +475,7 @@ public: FString arg0str, arg1str; memset(th, 0, sizeof(*th)); + th->gravity = FRACUNIT; sc.MustGetToken('{'); while (!sc.CheckToken('}')) { @@ -515,6 +516,11 @@ public: th->special = CheckInt(key); break; + case NAME_Gravity: + CHECK_N(Zd | Zdt) + th->gravity = CheckFixed(key); + break; + case NAME_Arg0: case NAME_Arg1: case NAME_Arg2: @@ -921,6 +927,10 @@ public: Flag(ld->flags, ML_BLOCKSIGHT, key); continue; + case NAME_blockhitscan: + Flag(ld->flags, ML_BLOCKHITSCAN, key); + continue; + // [Dusk] lock number case NAME_Locknumber: ld->locknumber = CheckInt(key); @@ -1326,7 +1336,11 @@ public: continue; case NAME_hidden: - sec->MoreFlags |= SECF_HIDDEN; + Flag(sec->MoreFlags, SECF_HIDDEN, key); + break; + + case NAME_Waterzone: + Flag(sec->MoreFlags, SECF_UNDERWATER, key); break; default: diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index dc287384d1..6ea32b3085 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -224,7 +224,6 @@ class USDFParser : public UDMFParserBase if (reply->ItemCheck.Size() > 0) { if (reply->ItemCheck[0].Amount <= 0) reply->NeedsGold = false; - if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->ItemCheck[0].Amount); } reply->Reply = ncopystring(ReplyString); @@ -288,6 +287,7 @@ class USDFParser : public UDMFParserBase //node->ItemCheckCount[0] = node->ItemCheckCount[1] = node->ItemCheckCount[2] = -1; node->ThisNodeNum = StrifeDialogues.Push(node); + node->ItemCheckNode = -1; FString SpeakerName; FString Dialogue; diff --git a/src/p_user.cpp b/src/p_user.cpp index 5ac8a1a885..901f6cfaab 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -309,12 +309,120 @@ player_t::player_t() ConversationFaceTalker(0) { memset (&cmd, 0, sizeof(cmd)); - memset (&userinfo, 0, sizeof(userinfo)); memset (frags, 0, sizeof(frags)); memset (psprites, 0, sizeof(psprites)); memset (&skill, 0, sizeof(skill)); } +player_t &player_t::operator=(const player_t &p) +{ + mo = p.mo; + playerstate = p.playerstate; + cmd = p.cmd; + original_cmd = p.original_cmd; + original_oldbuttons = p.original_oldbuttons; + // Intentionally not copying userinfo! + cls = p.cls; + DesiredFOV = p.DesiredFOV; + FOV = p.FOV; + viewz = p.viewz; + viewheight = p.viewheight; + deltaviewheight = p.deltaviewheight; + bob = p.bob; + velx = p.velx; + vely = p.vely; + centering = p.centering; + turnticks = p.turnticks; + attackdown = p.attackdown; + usedown = p.usedown; + oldbuttons = p.oldbuttons; + health = p.health; + inventorytics = p.inventorytics; + CurrentPlayerClass = p.CurrentPlayerClass; + backpack = p.backpack; + memcpy(frags, &p.frags, sizeof(frags)); + fragcount = p.fragcount; + lastkilltime = p.lastkilltime; + multicount = p.multicount; + spreecount = p.spreecount; + WeaponState = p.WeaponState; + ReadyWeapon = p.ReadyWeapon; + PendingWeapon = p.PendingWeapon; + cheats = p.cheats; + timefreezer = p.timefreezer; + refire = p.refire; + inconsistant = p.inconsistant; + waiting = p.waiting; + killcount = p.killcount; + itemcount = p.itemcount; + secretcount = p.secretcount; + damagecount = p.damagecount; + bonuscount = p.bonuscount; + hazardcount = p.hazardcount; + poisoncount = p.poisoncount; + poisontype = p.poisontype; + poisonpaintype = p.poisonpaintype; + poisoner = p.poisoner; + attacker = p.attacker; + extralight = p.extralight; + fixedcolormap = p.fixedcolormap; + fixedlightlevel = p.fixedlightlevel; + memcpy(psprites, &p.psprites, sizeof(psprites)); + morphTics = p.morphTics; + MorphedPlayerClass = p.MorphedPlayerClass; + MorphStyle = p.MorphStyle; + MorphExitFlash = p.MorphExitFlash; + PremorphWeapon = p.PremorphWeapon; + chickenPeck = p.chickenPeck; + jumpTics = p.jumpTics; + respawn_time = p.respawn_time; + camera = p.camera; + air_finished = p.air_finished; + LastDamageType = p.LastDamageType; + savedyaw = p.savedyaw; + savedpitch = p.savedpitch; + angle = p.angle; + dest = p.dest; + prev = p.prev; + enemy = p.enemy; + missile = p.missile; + mate = p.mate; + last_mate = p.last_mate; + settings_controller = p.settings_controller; + skill = p.skill; + t_active = p.t_active; + t_respawn = p.t_respawn; + t_strafe = p.t_strafe; + t_react = p.t_react; + t_fight = p.t_fight; + t_roam = p.t_roam; + t_rocket = p.t_rocket; + isbot = p.isbot; + first_shot = p.first_shot; + sleft = p.sleft; + allround = p.allround; + oldx = p.oldx; + oldy = p.oldy; + BlendR = p.BlendR; + BlendG = p.BlendG; + BlendB = p.BlendB; + BlendA = p.BlendA; + LogText = p.LogText; + MinPitch = p.MinPitch; + MaxPitch = p.MaxPitch; + crouching = p.crouching; + crouchdir = p.crouchdir; + crouchfactor = p.crouchfactor; + crouchoffset = p.crouchoffset; + crouchviewdelta = p.crouchviewdelta; + weapons = p.weapons; + ConversationNPC = p.ConversationNPC; + ConversationPC = p.ConversationPC; + ConversationNPCAngle = p.ConversationNPCAngle; + ConversationFaceTalker = p.ConversationFaceTalker; + return *this; +} + // This function supplements the pointer cleanup in dobject.cpp, because // player_t is not derived from DObject. (I tried it, and DestroyScan was // unable to properly determine the player object's type--possibly @@ -474,6 +582,14 @@ void APlayerPawn::Serialize (FArchive &arc) { arc << GruntSpeed << FallingScreamMinSpeed << FallingScreamMaxSpeed; } + if (SaveVersion >= 4502) + { + arc << UseRange; + } + if (SaveVersion >= 4503) + { + arc << AirCapacity; + } } //=========================================================================== @@ -1063,7 +1179,7 @@ bool APlayerPawn::ResetAirSupply (bool playgasp) { S_Sound (this, CHAN_VOICE, "*gasp", 1, ATTN_NORM); } - if (level.airsupply> 0) player->air_finished = level.time + level.airsupply; + if (level.airsupply> 0 && player->mo->AirCapacity > 0) player->air_finished = level.time + FixedMul(level.airsupply, player->mo->AirCapacity); else player->air_finished = INT_MAX; return wasdrowning; } diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 8bf5444552..986d992033 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -174,7 +174,15 @@ void R_InitPlanes () void R_DeinitPlanes () { fakeActive = 0; - R_ClearPlanes(false); + + // do not use R_ClearPlanes because at this point the screen pointer is no longer valid. + for (int i = 0; i <= MAXVISPLANES; i++) // new code -- killough + { + for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; ) + { + freehead = &(*freehead)->next; + } + } for (visplane_t *pl = freetail; pl != NULL; ) { visplane_t *next = pl->next; @@ -490,7 +498,7 @@ void R_MapColoredPlane (int y, int x1) void R_ClearPlanes (bool fullclear) { - int i, max; + int i; // Don't clear fake planes if not doing a full clear. if (!fullclear) @@ -516,7 +524,6 @@ void R_ClearPlanes (bool fullclear) } else { - max = fullclear ? MAXVISPLANES : MAXVISPLANES-1; for (i = 0; i <= MAXVISPLANES; i++) // new code -- killough { for (*freehead = visplanes[i], visplanes[i] = NULL; *freehead; ) @@ -524,10 +531,7 @@ void R_ClearPlanes (bool fullclear) freehead = &(*freehead)->next; } } - } - if (fullclear) - { // opening / clipping determination clearbufshort (floorclip, viewwidth, viewheight); // [RH] clip ceiling to console bottom diff --git a/src/r_segs.cpp b/src/r_segs.cpp index d050d8c3ba..4fec863ff0 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -828,7 +828,7 @@ void R_RenderFakeWallRange (drawseg_t *ds, int x1, int x2) { if (sclipTop <= backsector->e->XFloor.lightlist[j].plane.Zat0()) { - lightlist_t *lit = &backsector->e->XFloor.lightlist[i]; + lightlist_t *lit = &backsector->e->XFloor.lightlist[j]; basecolormap = lit->extra_colormap; wallshade = LIGHT2SHADE(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource == NULL) + r_actualextralight); break; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index b5382ccad4..0b51578ed1 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -62,6 +62,9 @@ extern bool DrawFSHUD; // [RH] Defined in d_main.cpp EXTERN_CVAR (Bool, cl_capfps) +extern lighttable_t* fixedcolormap; +extern FSpecialColormap*realfixedcolormap; + // TYPES ------------------------------------------------------------------- struct InterpolationViewer @@ -1005,6 +1008,11 @@ void FCanvasTextureInfo::UpdateAll () { FCanvasTextureInfo *probe; + // curse Doom's overuse of global variables in the renderer. + // These get clobbered by rendering to a camera texture but they need to be preserved so the final rendering can be done with the correct palette. + unsigned char *savecolormap = fixedcolormap; + FSpecialColormap *savecm = realfixedcolormap; + for (probe = List; probe != NULL; probe = probe->Next) { if (probe->Viewpoint != NULL && probe->Texture->bNeedsUpdate) @@ -1012,6 +1020,9 @@ void FCanvasTextureInfo::UpdateAll () Renderer->RenderTextureView(probe->Texture, probe->Viewpoint, probe->FOV); } } + + fixedcolormap = savecolormap; + realfixedcolormap = savecm; } //========================================================================== diff --git a/src/resourcefiles/file_7z.cpp b/src/resourcefiles/file_7z.cpp index 2f955705ee..8b1c23b67f 100644 --- a/src/resourcefiles/file_7z.cpp +++ b/src/resourcefiles/file_7z.cpp @@ -243,7 +243,7 @@ bool F7ZFile::Open(bool quiet) Archive = NULL; if (!quiet) { - Printf("\n"TEXTCOLOR_RED"%s: ", Filename); + Printf("\n" TEXTCOLOR_RED "%s: ", Filename); if (res == SZ_ERROR_UNSUPPORTED) { Printf("Decoder does not support this archive\n"); diff --git a/src/s_playlist.cpp b/src/s_playlist.cpp index ce82a8182d..c7af3b0c55 100644 --- a/src/s_playlist.cpp +++ b/src/s_playlist.cpp @@ -63,7 +63,7 @@ bool FPlayList::ChangeList (const char *path) if ( (file = fopen (path, "rb")) == NULL) { - Printf ("Could not open "TEXTCOLOR_BOLD"%s"TEXTCOLOR_NORMAL": %s\n", path, strerror(errno)); + Printf ("Could not open " TEXTCOLOR_BOLD "%s" TEXTCOLOR_NORMAL ": %s\n", path, strerror(errno)); return false; } diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 2626c2b825..d1c3139672 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1683,7 +1683,7 @@ bool S_GetSoundPlayingInfo (const FPolyObj *poly, int sound_id) // //========================================================================== -bool S_IsChannelUsed(AActor *actor, int channel, int *seen) +static bool S_IsChannelUsed(AActor *actor, int channel, int *seen) { if (*seen & (1 << channel)) { diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 148f006375..4b9d710a33 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -922,7 +922,7 @@ void STACK_ARGS FScanner::ScriptMessage (const char *message, ...) va_end (arglist); } - Printf (TEXTCOLOR_RED"Script error, \"%s\" line %d:\n"TEXTCOLOR_RED"%s\n", ScriptName.GetChars(), + Printf (TEXTCOLOR_RED "Script error, \"%s\" line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); } diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp index 46e3898ff9..def35606a4 100644 --- a/src/sdl/i_system.cpp +++ b/src/sdl/i_system.cpp @@ -616,7 +616,7 @@ int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) const char *str; if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0) { - FString cmd("kdialog --title \""GAMESIG" "); + FString cmd("kdialog --title \"" GAMESIG " "); cmd << GetVersionString() << ": Select an IWAD to use\"" " --menu \"ZDoom found more than one IWAD\n" "Select from the list below to determine which one to use:\""; @@ -749,6 +749,8 @@ int I_FindClose (void *handle) findstate_t *state = (findstate_t *)handle; if (handle != (void*)-1 && state->count > 0) { + for(int i = 0;i < state->count;++i) + free (state->namelist[i]); state->count = 0; free (state->namelist); state->namelist = NULL; diff --git a/src/sdl/iwadpicker_cocoa.mm b/src/sdl/iwadpicker_cocoa.mm index 1a1fa8b8c1..a0469ac7a8 100644 --- a/src/sdl/iwadpicker_cocoa.mm +++ b/src/sdl/iwadpicker_cocoa.mm @@ -156,7 +156,7 @@ static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" }; cancelled = false; app = [NSApplication sharedApplication]; - id windowTitle = [NSString stringWithUTF8String:GAMESIG " " DOTVERSIONSTR ": Select an IWAD to use"]; + id windowTitle = [NSString stringWithFormat:@GAMESIG " %s: Select an IWAD to use", GetVersionString()]; NSRect frame = NSMakeRect(0, 0, 440, 450); window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO]; diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index fece95dcfe..1bd98a16b0 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -108,7 +108,6 @@ CUSTOM_CVAR (Float, snd_waterlp, 250, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } #ifndef NO_FMOD - #if FMOD_VERSION < 0x43400 #define FMOD_OPENSTATE_PLAYING FMOD_OPENSTATE_STREAMING #endif @@ -734,8 +733,8 @@ bool FMODSoundRenderer::Init() } if (wrongver != NULL) { - Printf (" "TEXTCOLOR_ORANGE"Error! You are using %s version of FMOD (%x.%02x.%02x).\n" - " "TEXTCOLOR_ORANGE"This program was built for version %x.%02x.%02x\n", + Printf (" " TEXTCOLOR_ORANGE "Error! You are using %s version of FMOD (%x.%02x.%02x).\n" + " " TEXTCOLOR_ORANGE "This program was built for version %x.%02x.%02x\n", wrongver, version >> 16, (version >> 8) & 255, version & 255, FMOD_VERSION >> 16, (FMOD_VERSION >> 8) & 255, FMOD_VERSION & 255); @@ -1263,15 +1262,15 @@ void FMODSoundRenderer::PrintStatus() unsigned int bufferlength; int numbuffers; - Printf ("Loaded FMOD version: "TEXTCOLOR_GREEN"%x.%02x.%02x\n", ActiveFMODVersion >> 16, + Printf ("Loaded FMOD version: " TEXTCOLOR_GREEN "%x.%02x.%02x\n", ActiveFMODVersion >> 16, (ActiveFMODVersion >> 8) & 255, ActiveFMODVersion & 255); if (FMOD_OK == Sys->getOutput(&output)) { - Printf ("Output type: "TEXTCOLOR_GREEN"%s\n", Enum_NameForNum(OutputNames, output)); + Printf ("Output type: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(OutputNames, output)); } if (FMOD_OK == Sys->getSpeakerMode(&speakermode)) { - Printf ("Speaker mode: "TEXTCOLOR_GREEN"%s\n", Enum_NameForNum(SpeakerModeNames, speakermode)); + Printf ("Speaker mode: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(SpeakerModeNames, speakermode)); } if (FMOD_OK == Sys->getDriver(&driver)) { @@ -1280,19 +1279,19 @@ void FMODSoundRenderer::PrintStatus() { strcpy(name, "Unknown"); } - Printf ("Driver: "TEXTCOLOR_GREEN"%d"TEXTCOLOR_NORMAL" ("TEXTCOLOR_ORANGE"%s"TEXTCOLOR_NORMAL")\n", driver, name); + Printf ("Driver: " TEXTCOLOR_GREEN "%d" TEXTCOLOR_NORMAL " (" TEXTCOLOR_ORANGE "%s" TEXTCOLOR_NORMAL ")\n", driver, name); DumpDriverCaps(Driver_Caps, Driver_MinFrequency, Driver_MaxFrequency); } if (FMOD_OK == Sys->getSoftwareFormat(&samplerate, &format, &numoutputchannels, NULL, &resampler, NULL)) { - Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: "TEXTCOLOR_GREEN"%d\n", samplerate); - Printf (TEXTCOLOR_LIGHTBLUE "Software mixer format: "TEXTCOLOR_GREEN"%s\n", Enum_NameForNum(SoundFormatNames, format)); - Printf (TEXTCOLOR_LIGHTBLUE "Software mixer channels: "TEXTCOLOR_GREEN"%d\n", numoutputchannels); - Printf (TEXTCOLOR_LIGHTBLUE "Software mixer resampler: "TEXTCOLOR_GREEN"%s\n", Enum_NameForNum(ResamplerNames, resampler)); + Printf (TEXTCOLOR_LIGHTBLUE "Software mixer sample rate: " TEXTCOLOR_GREEN "%d\n", samplerate); + Printf (TEXTCOLOR_LIGHTBLUE "Software mixer format: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(SoundFormatNames, format)); + Printf (TEXTCOLOR_LIGHTBLUE "Software mixer channels: " TEXTCOLOR_GREEN "%d\n", numoutputchannels); + Printf (TEXTCOLOR_LIGHTBLUE "Software mixer resampler: " TEXTCOLOR_GREEN "%s\n", Enum_NameForNum(ResamplerNames, resampler)); } if (FMOD_OK == Sys->getDSPBufferSize(&bufferlength, &numbuffers)) { - Printf (TEXTCOLOR_LIGHTBLUE "DSP buffers: "TEXTCOLOR_GREEN"%u samples x %d\n", bufferlength, numbuffers); + Printf (TEXTCOLOR_LIGHTBLUE "DSP buffers: " TEXTCOLOR_GREEN "%u samples x %d\n", bufferlength, numbuffers); } } @@ -1304,8 +1303,8 @@ void FMODSoundRenderer::PrintStatus() void FMODSoundRenderer::DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int maxfrequency) { - Printf (TEXTCOLOR_OLIVE " Min. frequency: "TEXTCOLOR_GREEN"%d\n", minfrequency); - Printf (TEXTCOLOR_OLIVE " Max. frequency: "TEXTCOLOR_GREEN"%d\n", maxfrequency); + Printf (TEXTCOLOR_OLIVE " Min. frequency: " TEXTCOLOR_GREEN "%d\n", minfrequency); + Printf (TEXTCOLOR_OLIVE " Max. frequency: " TEXTCOLOR_GREEN "%d\n", maxfrequency); Printf (" Features:\n"); if (caps == 0) Printf(TEXTCOLOR_OLIVE " None\n"); if (caps & FMOD_CAPS_HARDWARE) Printf(TEXTCOLOR_OLIVE " Hardware mixing\n"); @@ -1320,7 +1319,7 @@ void FMODSoundRenderer::DumpDriverCaps(FMOD_CAPS caps, int minfrequency, int max { Printf("\n"); } - if (caps & FMOD_CAPS_REVERB_LIMITED) Printf("TEXTCOLOR_OLIVE Limited reverb\n"); + if (caps & FMOD_CAPS_REVERB_LIMITED) Printf(TEXTCOLOR_OLIVE " Limited reverb\n"); } //========================================================================== @@ -1388,11 +1387,11 @@ FString FMODSoundRenderer::GatherStats() } #endif - out.Format ("%d channels,"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% CPU " - "(DSP:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% " - "Stream:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% " - "Geometry:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%% " - "Update:"TEXTCOLOR_YELLOW"%5.2f"TEXTCOLOR_NORMAL"%%)", + out.Format ("%d channels," TEXTCOLOR_YELLOW "%5.2f" TEXTCOLOR_NORMAL "%% CPU " + "(DSP:" TEXTCOLOR_YELLOW "%5.2f" TEXTCOLOR_NORMAL "%% " + "Stream:" TEXTCOLOR_YELLOW "%5.2f" TEXTCOLOR_NORMAL "%% " + "Geometry:" TEXTCOLOR_YELLOW "%5.2f" TEXTCOLOR_NORMAL "%% " + "Update:" TEXTCOLOR_YELLOW "%5.2f" TEXTCOLOR_NORMAL "%%)", channels, total, dsp, stream, geometry, update); return out; } diff --git a/src/sound/music_fluidsynth_mididevice.cpp b/src/sound/music_fluidsynth_mididevice.cpp index 2e86cb2eeb..53a93fe099 100644 --- a/src/sound/music_fluidsynth_mididevice.cpp +++ b/src/sound/music_fluidsynth_mididevice.cpp @@ -620,10 +620,10 @@ FString FluidSynthMIDIDevice::GetStats() fluid_settings_getint(FluidSettings, "synth.polyphony", &maxpoly); CritSec.Leave(); - out.Format("Voices: "TEXTCOLOR_YELLOW"%3d"TEXTCOLOR_NORMAL"/"TEXTCOLOR_ORANGE"%3d"TEXTCOLOR_NORMAL"("TEXTCOLOR_RED"%3d"TEXTCOLOR_NORMAL")" - TEXTCOLOR_YELLOW"%6.2f"TEXTCOLOR_NORMAL"%% CPU " - "Reverb: "TEXTCOLOR_YELLOW"%3s"TEXTCOLOR_NORMAL - " Chorus: "TEXTCOLOR_YELLOW"%3s", + out.Format("Voices: " TEXTCOLOR_YELLOW "%3d" TEXTCOLOR_NORMAL "/" TEXTCOLOR_ORANGE "%3d" TEXTCOLOR_NORMAL "(" TEXTCOLOR_RED "%3d" TEXTCOLOR_NORMAL ")" + TEXTCOLOR_YELLOW "%6.2f" TEXTCOLOR_NORMAL "%% CPU " + "Reverb: " TEXTCOLOR_YELLOW "%3s" TEXTCOLOR_NORMAL + " Chorus: " TEXTCOLOR_YELLOW "%3s", voices, polyphony, maxpoly, load, reverb, chorus); return out; } diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 3c3037f88e..9fe7980796 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1376,7 +1376,7 @@ void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) } } -void OpenALSoundRenderer::SetInactive(EInactiveState) +void OpenALSoundRenderer::SetInactive(SoundRenderer::EInactiveState) { } diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 9842e63126..54eb7a599e 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -74,7 +74,7 @@ public: virtual void SetSfxVolume(float volume); virtual void SetMusicVolume(float volume); virtual SoundHandle LoadSound(BYTE *sfxdata, int length); - virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend); + virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1); virtual void UnloadSound(SoundHandle sfx); virtual unsigned int GetMSLength(SoundHandle sfx); virtual unsigned int GetSampleLength(SoundHandle sfx); @@ -104,7 +104,7 @@ public: virtual void SetSfxPaused(bool paused, int slot); // Pauses or resumes *every* channel, including environmental reverb. - virtual void SetInactive(EInactiveState state); + virtual void SetInactive(SoundRenderer::EInactiveState inactive); // Updates the volume, separation, and pitch of a sound channel. virtual void UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel); diff --git a/src/statistics.cpp b/src/statistics.cpp index aa8d9afc16..81cd889835 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -463,7 +463,7 @@ void STAT_ChangeLevel(const char *newl) { // we reached the end of this episode int wad = 0; - MapData * map = P_OpenMapData(StartEpisode->mEpisodeMap); + MapData * map = P_OpenMapData(StartEpisode->mEpisodeMap, false); if (map != NULL) { wad = Wads.GetLumpFile(map->lumpnum); diff --git a/src/textures/animations.cpp b/src/textures/animations.cpp index aaf6d03d62..5a6f0729ad 100644 --- a/src/textures/animations.cpp +++ b/src/textures/animations.cpp @@ -659,6 +659,17 @@ void FTextureManager::ParseCameraTexture(FScanner &sc) sc.UnGet (); } } + if (sc.GetString()) + { + if (sc.Compare("WorldPanning")) + { + viewer->bWorldPanning = true; + } + else + { + sc.UnGet(); + } + } viewer->SetScaledSize(fitwidth, fitheight); } diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 3083735a9e..fd2b59fb16 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -233,13 +233,13 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl NumParts = SAFESHORT(mtexture.d->patchcount); } - if (NumParts <= 0) + if (NumParts < 0) { I_FatalError ("Bad texture directory"); } UseType = FTexture::TEX_Wall; - Parts = new TexPart[NumParts]; + Parts = NumParts > 0 ? new TexPart[NumParts] : NULL; Width = SAFESHORT(mtexture.d->width); Height = SAFESHORT(mtexture.d->height); strncpy (Name, (const char *)mtexture.d->name, 8); @@ -906,7 +906,7 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d // There is bizzarely a Doom editing tool that writes to the // first two elements of columndirectory, so I can't check those. - if (SAFESHORT(tex->patchcount) <= 0 || + if (SAFESHORT(tex->patchcount) < 0 || tex->columndirectory[2] != 0 || tex->columndirectory[3] != 0) { diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 0302ca5435..f28026f193 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -127,7 +127,7 @@ void FTextureManager::DeleteAll() { if (mAnimatedDoors[i].TextureFrames != NULL) { - delete mAnimatedDoors[i].TextureFrames; + delete[] mAnimatedDoors[i].TextureFrames; mAnimatedDoors[i].TextureFrames = NULL; } } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index d35572121a..c97aee39c6 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -70,6 +70,7 @@ #include "m_bbox.h" #include "r_data/r_translate.h" #include "p_trace.h" +#include "gstrings.h" static FRandom pr_camissile ("CustomActorfire"); @@ -1403,7 +1404,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) } if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); - int puffFlags = LAF_ISMELEEATTACK | (flags & CPF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; + int puffFlags = LAF_ISMELEEATTACK | ((flags & CPF_NORANDOMPUFFZ) ? LAF_NORANDOMPUFFZ : 0); P_LineAttack (self, angle, Range, pitch, Damage, NAME_Melee, PuffType, puffFlags, &linetarget, &actualdamage); @@ -1425,7 +1426,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED; if (flags & CPF_DAGGER) P_DaggerAlert (self, linetarget); - } } @@ -1746,6 +1746,7 @@ enum SIX_Flags SIXF_TRANSFERSCALE = 1 << 14, SIXF_TRANSFERSPECIAL = 1 << 15, SIXF_CLEARCALLERSPECIAL = 1 << 16, + SIXF_TRANSFERSTENCILCOL = 1 << 17, }; static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) @@ -1858,6 +1859,10 @@ static bool InitSpawnedItem(AActor *self, AActor *mo, int flags) self->special = 0; memset(self->args, 0, sizeof(self->args)); } + if (flags & SIXF_TRANSFERSTENCILCOL) + { + mo->fillcolor = self->fillcolor; + } return true; } @@ -2133,6 +2138,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Print) ACTION_PARAM_FLOAT(time, 1); ACTION_PARAM_NAME(fontname, 2); + if (text[0] == '$') text = GStrings(text+1); if (self->CheckLocalView (consoleplayer) || (self->target!=NULL && self->target->CheckLocalView (consoleplayer))) { @@ -2171,6 +2177,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PrintBold) float saved = con_midtime; FFont *font = NULL; + if (text[0] == '$') text = GStrings(text+1); if (fontname != NAME_None) { font = V_GetFont(fontname); @@ -2196,11 +2203,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Log) { ACTION_PARAM_START(1); ACTION_PARAM_STRING(text, 0); + + if (text[0] == '$') text = GStrings(text+1); Printf("%s\n", text); ACTION_SET_RESULT(false); // Prints should never set the result for inventory state chains! } -//=========================================================================== +//========================================================================= // // A_LogInt // @@ -4925,6 +4934,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTics) ACTION_PARAM_START(1); ACTION_PARAM_INT(tics_to_set, 0); + if (stateowner != self && self->player != NULL && stateowner->IsKindOf(RUNTIME_CLASS(AWeapon))) + { // Is this a weapon? Need to check psp states for a match, then. Blah. + for (int i = 0; i < NUMPSPRITES; ++i) + { + if (self->player->psprites[i].state == CallingState) + { + self->player->psprites[i].tics = tics_to_set; + return; + } + } + } + // Just set tics for self. self->tics = tics_to_set; } @@ -4941,3 +4962,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetDamageType) self->DamageType = damagetype; } + +//========================================================================== +// +// A_DropItem +// +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DropItem) +{ + ACTION_PARAM_START(3); + ACTION_PARAM_CLASS(spawntype, 0); + ACTION_PARAM_INT(amount, 1); + ACTION_PARAM_INT(chance, 2); + + P_DropItem(self, spawntype, amount, chance); +} diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 795bcb5cc7..ef0cf2fe18 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -184,6 +184,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF5, DONTDRAIN, AActor, flags5), DEFINE_FLAG(MF5, NODROPOFF, AActor, flags5), + DEFINE_FLAG(MF5, NOFORWARDFALL, AActor, flags5), DEFINE_FLAG(MF5, COUNTSECRET, AActor, flags5), DEFINE_FLAG(MF5, NODAMAGE, AActor, flags5), DEFINE_FLAG(MF5, BLOODSPLATTER, AActor, flags5), @@ -233,6 +234,7 @@ static FFlagDef ActorFlags[]= DEFINE_FLAG(MF6, DOHARMSPECIES, AActor, flags6), DEFINE_FLAG(MF6, POISONALWAYS, AActor, flags6), DEFINE_FLAG(MF6, NOTAUTOAIMED, AActor, flags6), + DEFINE_FLAG(MF6, NOTONAUTOMAP, AActor, flags6), // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), diff --git a/src/thingdef/thingdef_parse.cpp b/src/thingdef/thingdef_parse.cpp index c065dfbe03..498003b4ee 100644 --- a/src/thingdef/thingdef_parse.cpp +++ b/src/thingdef/thingdef_parse.cpp @@ -867,7 +867,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls) OPTIONAL = 1 }; - bool error = false; + unsigned int error = 0; const AFuncDesc *afd; FName funcname; FString args; @@ -876,8 +876,8 @@ static void ParseActionDef (FScanner &sc, PClass *cls) if (sc.LumpNum == -1 || Wads.GetLumpFile(sc.LumpNum) > 0) { - sc.ScriptMessage ("action functions can only be imported by internal class and actor definitions!"); - error++; + sc.ScriptMessage ("Action functions can only be imported by internal class and actor definitions!"); + ++error; } sc.MustGetToken(TK_Native); @@ -887,7 +887,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls) if (afd == NULL) { sc.ScriptMessage ("The function '%s' has not been exported from the executable.", sc.String); - error++; + ++error; } sc.MustGetToken('('); if (!sc.CheckToken(')')) @@ -998,7 +998,7 @@ static void ParseActionDef (FScanner &sc, PClass *cls) } if (error) { - FScriptPosition::ErrorCounter++; + FScriptPosition::ErrorCounter += error; } else if (cls->Symbols.AddSymbol (sym) == NULL) { diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index cf4ef95bba..dc08db3615 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -2113,9 +2113,8 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory) I_Error("\"powerup.strength\" requires an actor of type \"Powerup\"\n"); return; } - // Puts a percent value in the 0.0..1.0 range PROP_FIXED_PARM(f, 0); - *pStrength = f / 100; + *pStrength = f; } //========================================================================== @@ -2410,6 +2409,24 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, viewheight, F, PlayerPawn) defaults->ViewHeight = z; } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, userange, F, PlayerPawn) +{ + PROP_FIXED_PARM(z, 0); + defaults->UseRange = z; +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, aircapacity, F, PlayerPawn) +{ + PROP_FIXED_PARM(z, 0); + defaults->AirCapacity = z; +} + //========================================================================== // //========================================================================== diff --git a/src/version.h b/src/version.h index 1038e401b5..01fbc7a88c 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4501 +#define SAVEVER 4503 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 37b418ce99..7aef939b12 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -62,7 +62,7 @@ typedef enum CVAR (Bool, wi_percents, true, CVAR_ARCHIVE) CVAR (Bool, wi_showtotaltime, true, CVAR_ARCHIVE) -CVAR (Bool, wi_noautostartmap, false, CVAR_ARCHIVE) +CVAR (Bool, wi_noautostartmap, false, CVAR_USERINFO|CVAR_ARCHIVE) void WI_loadData (); @@ -1098,11 +1098,28 @@ void WI_updateNoState () { WI_updateAnimatedBack(); + if (acceleratestage) + { + cnt = 0; + } + else + { + bool noauto = noautostartmap; - if (!wi_noautostartmap && !noautostartmap) cnt--; - if (acceleratestage) cnt=0; + for (int i = 0; !noauto && i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + noauto |= players[i].userinfo.GetNoAutostartMap(); + } + } + if (!noauto) + { + cnt--; + } + } - if (cnt==0) + if (cnt == 0) { WI_End(); G_WorldDone(); @@ -1947,7 +1964,7 @@ void WI_Ticker(void) if (level.info->InterMusic.IsNotEmpty()) S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder); else - S_ChangeMusic (gameinfo.intermissionMusic.GetChars()); + S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); } diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index b5843ec7a5..a82cb65f9c 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1569,3 +1569,31 @@ unsigned int I_MakeRNGSeed() CryptReleaseContext(prov, 0); return seed; } + +//========================================================================== +// +// I_GetLongPathName +// +// Returns the long version of the path, or the original if there isn't +// anything worth changing. +// +//========================================================================== + +FString I_GetLongPathName(FString shortpath) +{ + DWORD buffsize = GetLongPathName(shortpath.GetChars(), NULL, 0); + if (buffsize == 0) + { // nothing to change (it doesn't exist, maybe?) + return shortpath; + } + TCHAR *buff = new TCHAR[buffsize]; + DWORD buffsize2 = GetLongPathName(shortpath.GetChars(), buff, buffsize); + if (buffsize2 >= buffsize) + { // Failure! Just return the short path + delete[] buff; + return shortpath; + } + FString longpath(buff, buffsize2); + delete[] buff; + return longpath; +} diff --git a/src/win32/i_system.h b/src/win32/i_system.h index 6bafdc01c3..9fbf2db5cb 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -155,6 +155,9 @@ typedef _W64 long WLONG_PTR; typedef long WLONG_PTR; #endif +// Wrapper for GetLongPathName +FString I_GetLongPathName(FString shortpath); + // Directory searching routines // Mirror WIN32_FIND_DATAA in diff --git a/wadsrc/CMakeLists.txt b/wadsrc/CMakeLists.txt index 4220525116..83dc8292d8 100644 --- a/wadsrc/CMakeLists.txt +++ b/wadsrc/CMakeLists.txt @@ -1,11 +1,3 @@ cmake_minimum_required( VERSION 2.4 ) -get_target_property(ZIPDIR_EXE zipdir LOCATION) - -add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 - COMMAND ${ZIPDIR_EXE} -udf ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 $ - DEPENDS zipdir ${CMAKE_CURRENT_SOURCE_DIR}/static ) - -add_custom_target( pk3 ALL - DEPENDS ${ZDOOM_OUTPUT_DIR}/zdoom.pk3 ) +add_pk3(zdoom.pk3 ${CMAKE_CURRENT_SOURCE_DIR}/static) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index c2fa8a0c72..3ba47a5c1d 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -84,7 +84,7 @@ ACTOR Actor native //: Thinker action native A_VileChase(); action native A_VileStart(); action native A_VileTarget(class fire = "ArchvileFire"); - action native A_VileAttack(sound snd = "vile/stop", int initialdmg = 20, int blastdmg = 70, int blastradius = 70, float thrustfac = 1.0, name damagetype = "Fire"); + action native A_VileAttack(sound snd = "vile/stop", int initialdmg = 20, int blastdmg = 70, int blastradius = 70, float thrustfac = 1.0, name damagetype = "Fire", int flags = 0); action native A_StartFire(); action native A_Fire(float spawnheight = 0); action native A_FireCrackle(); @@ -300,6 +300,7 @@ ACTOR Actor native //: Thinker action native A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); action native A_SetTics(int tics); action native A_SetDamageType(name damagetype); + action native A_DropItem(class item, int dropamount = -1, int chance = 256); action native A_CheckSightOrRange(float distance, state label); action native A_CheckRange(float distance, state label); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 24736eb3dd..cd9b088ab9 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -4,6 +4,9 @@ const int PAF_NOSKULLATTACK = 1; const int PAF_AIMFACING = 2; const int PAF_NOTARGET = 4; +// Flags for A_VileAttack +const int VAF_DMGTYPEAPPLYTODIRECT = 1; + // Flags for A_Saw const int SF_NORANDOM = 1; const int SF_RANDOMLIGHTMISS = 2; @@ -59,6 +62,7 @@ const int SXF_MULTIPLYSPEED = 8192; const int SXF_TRANSFERSCALE = 16384; const int SXF_TRANSFERSPECIAL = 32768; const int SXF_CLEARCALLERSPECIAL = 65536; +const int SXF_TRANSFERSTENCILCOL = 131072; // Flags for A_Chase const int CHF_FASTCHASE = 1; diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index 5f5e20b502..ed113c4dfb 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -300,6 +300,7 @@ ACTOR PowerDrain : Powerup native ACTOR PowerRegeneration : Powerup native { Powerup.Duration -120 + Powerup.Strength 5 } ACTOR PowerHighJump : Powerup native {} diff --git a/wadsrc/static/actors/shared/player.txt b/wadsrc/static/actors/shared/player.txt index 05fb998c31..159d4cca94 100644 --- a/wadsrc/static/actors/shared/player.txt +++ b/wadsrc/static/actors/shared/player.txt @@ -24,6 +24,7 @@ Actor PlayerPawn : Actor native Player.GruntSpeed 12 Player.FallingScreamSpeed 35,40 Player.ViewHeight 41 + Player.UseRange 64 Player.ForwardMove 1,1 Player.SideMove 1,1 Player.ColorRange 0,0 @@ -31,6 +32,7 @@ Actor PlayerPawn : Actor native Player.DamageScreenColor "ff 00 00" Player.MugShotMaxHealth 0 Player.FlechetteType "ArtiPoisonBag3" + Player.AirCapacity 1 Obituary "$OB_MPDEFAULT" } diff --git a/wadsrc/static/actors/strife/alienspectres.txt b/wadsrc/static/actors/strife/alienspectres.txt index bdd30d8e49..6e56f680d0 100644 --- a/wadsrc/static/actors/strife/alienspectres.txt +++ b/wadsrc/static/actors/strife/alienspectres.txt @@ -20,6 +20,7 @@ ACTOR AlienSpectre1 : SpectralMonster 129 PainSound "alienspectre/pain" DeathSound "alienspectre/death" ActiveSound "alienspectre/active" + Obituary "$OB_ALIENSPECTRE" +NOGRAVITY +FLOAT +SHADOW diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index a84ba218b7..4b75dfaba3 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -353,3 +353,26 @@ F481922F4881F74760F3C0437FD5EDD0 // map03 // make the blue key spawn above the 3D floor setthingz 918 296 } + +64B6CE3CB7349B6F6B1A885C449ACB96 // Super Sonic Doom, map31 +{ + // During the end-of-level tally, both PROP_FROZEN and PROP_TOTALLYFROZEN + // are set, but only PROP_TOTALLYFROZEN is cleared, so PROP_FROZEN is + // still set when returning to the origin map. + linkfrozenprops +} + +D62DCA9EC226DE49108D5DD9271F7631 // Cheogsh 2 map04 +{ + // Stuff in megasphere cage is positioned too low + setthingz 1640 528 + setthingz 1641 528 + setthingz 1642 528 + setthingz 1643 528 + setthingz 1644 528 + setthingz 1645 528 + setthingz 1646 528 + setthingz 1647 528 + setthingz 1648 528 + setthingz 1649 528 +} \ No newline at end of file diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 0c8fff5d3e..5695ad502c 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -112,6 +112,7 @@ PD_YELLOWCO = "You need a yellow card to activate this object"; PD_BLUESO = "You need a blue skull to activate this object"; PD_REDSO = "You need a red skull to activate this object"; PD_YELLOWSO = "You need a yellow skull to activate this object"; +NEWSAVE = ""; GGSAVED = "game saved."; HUSTR_MSGU = "[Message unsent]"; PICKUP_PISTOL_DROPPED = "Picked up a pistol."; @@ -735,7 +736,7 @@ OB_MACIL = "%o should have never rebelled against Macil."; OB_REBEL = "%o was gunned down by a Rebel."; OB_BEGGAR = "%o was beaten to death by the poor."; OB_PEASANT = "%o should have never picked a fight with a civilian."; -OB_ALIENSPECTE = "%o was struck down by the Spectre."; +OB_ALIENSPECTRE = "%o was struck down by the Spectre."; OB_ENTITY = "%o felt the wrath of The One God."; OB_LOREMASTER = "%o couldn't escape from the Lore Master's grasp."; OB_PROGRAMMER = "%o was deleted by the Programmer."; @@ -1614,6 +1615,10 @@ MNU_EPISODE = "Select Episode"; WI_FINISHED = "finished"; WI_ENTERING = "Now entering:"; +AM_MONSTERS = "Monsters:"; +AM_SECRETS = "Secrets:"; +AM_ITEMS = "Items:"; + // Bloodbath announcer BBA_BONED = "%k boned %o like a fish"; diff --git a/wadsrc/static/language.fr b/wadsrc/static/language.fr index 354ba2bee2..1533a15065 100644 --- a/wadsrc/static/language.fr +++ b/wadsrc/static/language.fr @@ -779,7 +779,7 @@ OB_MACIL = "%o n'aurait jamais du se rebelle contre Macil."; OB_REBEL = "%o a ete abbatu par un Rebel."; OB_BEGGAR = "%o a ete battu a mort par un pauvre."; OB_PEASANT = "%o n'aurait jamais du chercher la bagarre a un civil."; -OB_ALIENSPECTE = "%o a ete terrasse par le Spectre."; +OB_ALIENSPECTRE = "%o a ete terrasse par le Spectre."; OB_ENTITY = "%o a senti le courroux du dieu unique."; OB_LOREMASTER = "%o n'a pu echapper a l'emprise du Maitre des Traditions."; OB_PROGRAMMER = "%o a ete efface par le Programmer."; diff --git a/wadsrc/static/language.ptb b/wadsrc/static/language.ptb index 1dc0e36c02..9f7cc4e113 100644 --- a/wadsrc/static/language.ptb +++ b/wadsrc/static/language.ptb @@ -712,7 +712,7 @@ OB_MACIL = "%o should have never rebelled against Macil."; OB_REBEL = "%o was gunned down by a Rebel."; OB_BEGGAR = "%o was beaten to death by the poor."; OB_PEASANT = "%o should have never picked a fight with a civilian."; -OB_ALIENSPECTE = "%o was struck down by the Spectre."; +OB_ALIENSPECTRE = "%o was struck down by the Spectre."; OB_ENTITY = "%o felt the wrath of The One God."; OB_LOREMASTER = "%o couldn't escape from the Lore Master's grasp."; OB_PROGRAMMER = "%o was deleted by the Programmer."; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 3d4ccf72bd..bc34ee33ee 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -912,6 +912,14 @@ OptionValue MaplabelTypes 2, "Not for hubs" } +OptionValue STSTypes +{ + 0, "Off" + 1, "Front" + 2, "Animated" + 3, "Rotated" +} + OptionMenu AutomapOptions { Title "AUTOMAP OPTIONS" @@ -934,6 +942,7 @@ OptionMenu AutomapOptions Option "Draw map background", "am_drawmapback", "OnOff" Option "Show keys (cheat)", "am_showkeys", "OnOff" Option "Show trigger lines", "am_showtriggerlines", "OnOff" + Option "Show things as sprites", "am_showthingsprites", "STSTypes" } //------------------------------------------------------------------------------------------- @@ -1001,8 +1010,11 @@ OptionMenu MapColorMenu StaticText "Overlay Mode", 1 ColorPicker "You", "am_ovyourcolor" ColorPicker "1-sided walls", "am_ovwallcolor" - ColorPicker "2-sided walls", "am_ovotherwallscolor" + ColorPicker "2-sided walls with different floors", "am_ovfdwallcolor" + ColorPicker "2-sided walls with different ceilings", "am_ovcdwallcolor" + ColorPicker "2-sided walls with 3D floors", "am_ovefwallcolor" ColorPicker "Not-yet-seen walls", "am_ovunseencolor" + ColorPicker "Locked doors", "am_ovotherwallscolor" ColorPicker "Teleporter", "am_ovtelecolor" ColorPicker "Secret sector", "am_ovsecretsectorcolor" ColorPicker "Special trigger lines", "am_ovspecialwallcolor"