diff --git a/dumb/CMakeLists.txt b/dumb/CMakeLists.txt index 85cbaeb55..c2cbe8d1b 100644 --- a/dumb/CMakeLists.txt +++ b/dumb/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required( VERSION 2.4 ) +include( CheckFunctionExists ) + # DUMB is much slower in a Debug build than a Release build, so we force a Release # build here, since we're not maintaining DUMB, only using it. # Comment out the below line to allow Debug builds. @@ -13,6 +15,11 @@ if( CMAKE_COMPILER_IS_GNUC ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-pointer-sign -Wno-uninitialized" ) endif( CMAKE_COMPILER_IS_GNUC ) +CHECK_FUNCTION_EXISTS( itoa ITOA_EXISTS ) +if( NOT ITOA_EXISTS ) + add_definitions( -DNEED_ITOA=1 ) +endif( NOT ITOA_EXISTS ) + include_directories( include ) add_library( dumb diff --git a/dumb/src/helpers/resamp3.inc b/dumb/src/helpers/resamp3.inc index a820e94c1..3d61bfff1 100644 --- a/dumb/src/helpers/resamp3.inc +++ b/dumb/src/helpers/resamp3.inc @@ -58,7 +58,7 @@ int32 dumb_resample(DUMB_RESAMPLER *resampler, sample_t *dst, int32 dst_size, VO done = 0; dt = (int)(delta * 65536.0 + 0.5); - if (dt == 0) return 0; + if (dt == 0 || dt == 0x80000000) return 0; SET_VOLUME_VARIABLES; if (VOLUMES_ARE_ZERO) dst = NULL; diff --git a/dumb/src/it/readam.c b/dumb/src/it/readam.c index 70dafadcf..9910b1d82 100644 --- a/dumb/src/it/readam.c +++ b/dumb/src/it/readam.c @@ -24,9 +24,6 @@ #include "internal/it.h" #include "internal/riff.h" -DUH *dumb_read_riff_amff( struct riff * stream ); -DUH *dumb_read_riff_am( struct riff * stream ); - static int it_riff_am_process_sample( IT_SAMPLE * sample, const unsigned char * data, int len, int ver ) { int header_length; diff --git a/dumb/src/it/readoldpsm.c b/dumb/src/it/readoldpsm.c index 1d7260508..3c764af25 100644 --- a/dumb/src/it/readoldpsm.c +++ b/dumb/src/it/readoldpsm.c @@ -291,7 +291,7 @@ static int it_old_psm_read_patterns(IT_PATTERN * pattern, DUMBFILE * f, int num, if (channel >= chans) { //channel = 0; - goto error_fb; + //goto error_fb; } if (flags & 0x80) { if ((*ptr < 60) && (channel < pchans)) { diff --git a/dumb/src/it/readpsm.c b/dumb/src/it/readpsm.c index fa19943b9..d6fc099c5 100644 --- a/dumb/src/it/readpsm.c +++ b/dumb/src/it/readpsm.c @@ -1271,7 +1271,11 @@ DUH *DUMBEXPORT dumb_read_psm_quick(DUMBFILE *f, int subsong) if ( ver ) { tag[2][0] = "FORMATVERSION"; +#if NEED_ITOA sprintf(version, "%d", ver); +#else + itoa(ver, version, 10); +#endif tag[2][1] = (const char *) &version; ++n_tags; } diff --git a/specs/fmod_version.txt b/specs/fmod_version.txt new file mode 100644 index 000000000..a65aec918 --- /dev/null +++ b/specs/fmod_version.txt @@ -0,0 +1 @@ +This version of ZDoom must be compiled with any version between 4.22 and 4.28 inclusive. diff --git a/src/actionspecials.h b/src/actionspecials.h index 5d9471fec..cd49504c3 100644 --- a/src/actionspecials.h +++ b/src/actionspecials.h @@ -12,7 +12,7 @@ DEFINE_SPECIAL(Door_Close, 10, 2, 3, 3) DEFINE_SPECIAL(Door_Open, 11, 2, 3, 3) DEFINE_SPECIAL(Door_Raise, 12, 3, 4, 4) DEFINE_SPECIAL(Door_LockedRaise, 13, 4, 5, 5) -DEFINE_SPECIAL(Door_Animated, 14, 3, 3, 3) +DEFINE_SPECIAL(Door_Animated, 14, 4, 4, 4) DEFINE_SPECIAL(Autosave, 15, 0, 0, 0) // [RH] Save the game *now* DEFINE_SPECIAL(Transfer_WallLight, 16, -1, -1, 2) DEFINE_SPECIAL(Thing_Raise, 17, 1, 1, 1) diff --git a/src/actor.h b/src/actor.h index 50b15d48c..7ab8bc666 100644 --- a/src/actor.h +++ b/src/actor.h @@ -552,9 +552,6 @@ public: virtual void Tick (); - // Smallest yaw interval for a mapthing to be spawned with - virtual angle_t AngleIncrements (); - // Called when actor dies virtual void Die (AActor *source, AActor *inflictor); @@ -691,6 +688,31 @@ public: return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist); } + PalEntry GetBloodColor() const + { + return GetClass()->BloodColor; + } + + PClassActor *GetBloodType(int type = 0) const + { + if (type == 0) + { + return PClass::FindActor(GetClass()->BloodType); + } + else if (type == 1) + { + return PClass::FindActor(GetClass()->BloodType2); + } + else if (type == 2) + { + return PClass::FindActor(GetClass()->BloodType3); + } + else + { + return NULL; + } + } + // Calculate amount of missile damage virtual int GetMissileDamage(int mask, int add); @@ -821,6 +843,7 @@ public: FSoundIDNoInit UseSound; // [RH] Sound to play when an actor is used. FSoundIDNoInit BounceSound; FSoundIDNoInit WallBounceSound; + FSoundIDNoInit CrushPainSound; fixed_t Speed; fixed_t FloatSpeed; diff --git a/src/am_map.cpp b/src/am_map.cpp index 8f6871f99..28739c856 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1850,7 +1850,7 @@ void AM_drawPlayers () { float h, s, v, r, g, b; - D_GetPlayerColor (i, &h, &s, &v); + D_GetPlayerColor (i, &h, &s, &v, NULL); HSVtoRGB (&r, &g, &b, h, s, v); color.FromRGB(clamp (int(r*255.f),0,255), clamp (int(g*255.f),0,255), clamp (int(b*255.f),0,255)); diff --git a/src/b_func.cpp b/src/b_func.cpp index adaa755c2..efc3f7f57 100644 --- a/src/b_func.cpp +++ b/src/b_func.cpp @@ -118,7 +118,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget) //in doom is 90 degrees infront. bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle) { - if (!P_CheckSight (from, to, 2)) + if (!P_CheckSight (from, to, SF_SEEPASTBLOCKEVERYTHING)) return false; // out of sight if (vangle == ANGLE_MAX) return true; @@ -339,7 +339,7 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot) && !p_leader[count]) //taken? { - if (P_CheckSight (bot, client->mo, 1)) + if (P_CheckSight (bot, client->mo, SF_IGNOREVISIBILITY)) { test = P_AproxDistance (client->mo->x - bot->x, client->mo->y - bot->y); @@ -525,7 +525,7 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd) enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1); dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y); //try the predicted location - if (P_CheckSight (actor, bglobal.body1, 1)) //See the predicted location, so give a test missile + if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile { FCheckPosition tm; if (SafeCheckPosition (bot, actor->x, actor->y, tm)) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 9ee99276f..68c0943b1 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -788,8 +788,8 @@ CCMD(info) AActor *linetarget; if (CheckCheatmode () || players[consoleplayer].mo == NULL) return; - P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE, &linetarget, 0, - false, false, true); + P_AimLineAttack(players[consoleplayer].mo,players[consoleplayer].mo->angle,MISSILERANGE, + &linetarget, 0, ALF_CHECKNONSHOOTABLE|ALF_FORCENOSMART); if (linetarget) { Printf("Target=%s, Health=%d, Spawnhealth=%d\n", @@ -924,6 +924,19 @@ CCMD(nextsecret) } } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- +CCMD(currentpos) +{ + AActor *mo = players[consoleplayer].mo; + Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, lightlevel: %d\n", + FIXED2FLOAT(mo->x), FIXED2FLOAT(mo->y), FIXED2FLOAT(mo->z), mo->angle/float(ANGLE_1), FIXED2FLOAT(mo->floorz), mo->Sector->sectornum, mo->Sector->lightlevel); +} + + //----------------------------------------------------------------------------- // // diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 5ebe450b6..2fbafd2a9 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -1035,6 +1035,32 @@ FString BuildString (int argc, char **argv) } } +FString BuildString (int argc, FString *argv) +{ + if (argc == 1) + { + return *argv; + } + else + { + FString buf; + int arg; + + for (arg = 0; arg < argc; arg++) + { + if (strchr (argv[arg], ' ')) + { + buf << '"' << argv[arg] << "\" "; + } + else + { + buf << argv[arg] << ' '; + } + } + return buf; + } +} + //=========================================================================== // // SubstituteAliasParams diff --git a/src/c_dispatch.h b/src/c_dispatch.h index 96e375ea2..df6fe1348 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -59,6 +59,7 @@ void C_SetAlias (const char *name, const char *cmd); // build a single string out of multiple strings FString BuildString (int argc, char **argv); +FString BuildString (int argc, FString *argv); // Class that can parse command lines class FCommandLine diff --git a/src/cmdlib.cpp b/src/cmdlib.cpp index 9942d27fc..dd32cdb55 100644 --- a/src/cmdlib.cpp +++ b/src/cmdlib.cpp @@ -148,17 +148,13 @@ int Q_filelength (FILE *f) bool FileExists (const char *filename) { - FILE *f; + struct stat buff; // [RH] Empty filenames are never there if (filename == NULL || *filename == 0) return false; - f = fopen (filename, "r"); - if (!f) - return false; - fclose (f); - return true; + return stat(filename, &buff) == 0 && !(buff.st_mode & S_IFDIR); } //========================================================================== diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 9d7c54f7a..8f4615683 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2135,20 +2135,7 @@ static int PatchText (int oldSize) if (!good) { - // search cluster text background flats (only if no user-defined MAPINFO is used!) - if (strlen(newStr) <= 8 && Wads.CheckNumForName("MAPINFO") >= 0) - { - for (unsigned int i = 0; i < wadclusterinfos.Size(); i++) - { - if (!strcmp(wadclusterinfos[i].finaleflat, oldStr)) - { - strcpy(wadclusterinfos[i].finaleflat, newStr); - good = true; - } - } - } - - if (!good) DPrintf (" (Unmatched)\n"); + DPrintf (" (Unmatched)\n"); } } @@ -2904,6 +2891,12 @@ bool ADehackedPickup::TryPickup (AActor *&toucher) RealPickup = static_cast(Spawn (type, x, y, z, NO_REPLACE)); if (RealPickup != NULL) { + // The internally spawned item should never count towards statistics. + if (RealPickup->flags & MF_COUNTITEM) + { + RealPickup->flags &= ~MF_COUNTITEM; + level.total_items--; + } if (!(flags & MF_DROPPED)) { RealPickup->flags &= ~MF_DROPPED; diff --git a/src/d_main.cpp b/src/d_main.cpp index 0a59d05f4..3b4228a68 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -129,7 +129,7 @@ void D_CheckNetGame (); void D_ProcessEvents (); void G_BuildTiccmd (ticcmd_t* cmd); void D_DoAdvanceDemo (); -void D_AddWildFile (const char *pattern); +void D_AddWildFile (TArray &wadfiles, const char *pattern); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- @@ -657,6 +657,7 @@ void D_Display () switch (gamestate) { case GS_FULLCONSOLE: + R_UpdateAnimations(I_FPSTime()); screen->SetBlendingRect(0,0,0,0); hw2d = screen->Begin2D(false); C_DrawConsole (false); @@ -721,6 +722,7 @@ void D_Display () break; case GS_INTERMISSION: + R_UpdateAnimations(I_FPSTime()); screen->SetBlendingRect(0,0,0,0); hw2d = screen->Begin2D(false); WI_Drawer (); @@ -728,6 +730,7 @@ void D_Display () break; case GS_FINALE: + R_UpdateAnimations(I_FPSTime()); screen->SetBlendingRect(0,0,0,0); hw2d = screen->Begin2D(false); F_Drawer (); @@ -735,6 +738,7 @@ void D_Display () break; case GS_DEMOSCREEN: + R_UpdateAnimations(I_FPSTime()); screen->SetBlendingRect(0,0,0,0); hw2d = screen->Begin2D(false); D_PageDrawer (); @@ -1478,27 +1482,22 @@ static const char *BaseFileSearch (const char *file, const char *ext, bool lookf // //========================================================================== -bool ConsiderPatches (const char *arg, const char *ext) +bool ConsiderPatches (const char *arg) { - bool noDef = false; - DArgs *files = Args->GatherFiles (arg, ext, false); + int i, argc; + FString *args; + const char *f; - if (files->NumArgs() > 0) + argc = Args->CheckParmList(arg, &args); + for (i = 0; i < argc; ++i) { - int i; - const char *f; - - for (i = 0; i < files->NumArgs(); ++i) + if ( (f = BaseFileSearch(args[i], ".deh")) || + (f = BaseFileSearch(args[i], ".bex")) ) { - if ( (f = BaseFileSearch (files->GetArg (i), ".deh")) ) - D_LoadDehFile(f); - else if ( (f = BaseFileSearch (files->GetArg (i), ".bex")) ) - D_LoadDehFile(f); + D_LoadDehFile(f); } - noDef = true; } - files->Destroy(); - return noDef; + return argc > 0; } //========================================================================== @@ -1591,40 +1590,18 @@ void D_MultiExec (DArgs *list, bool usePullin) static void GetCmdLineFiles(TArray &wadfiles) { - DArgs *files = Args->GatherFiles ("-file", ".wad", true); - DArgs *files1 = Args->GatherFiles (NULL, ".zip", false); - DArgs *files2 = Args->GatherFiles (NULL, ".pk3", false); - DArgs *files3 = Args->GatherFiles (NULL, ".txt", false); - if (files->NumArgs() > 0 || files1->NumArgs() > 0 || files2->NumArgs() > 0 || files3->NumArgs() > 0) - { - // Check for -file in shareware - if (gameinfo.flags & GI_SHAREWARE) - { - I_FatalError ("You cannot -file with the shareware version. Register!"); - } + FString *args; + int i, argc; - // the files gathered are wadfile/lump names - for (int i = 0; i < files->NumArgs(); i++) - { - D_AddWildFile (wadfiles, files->GetArg (i)); - } - for (int i = 0; i < files1->NumArgs(); i++) - { - D_AddWildFile (wadfiles, files1->GetArg (i)); - } - for (int i = 0; i < files2->NumArgs(); i++) - { - D_AddWildFile (wadfiles, files2->GetArg (i)); - } - for (int i = 0; i < files3->NumArgs(); i++) - { - D_AddWildFile (wadfiles, files3->GetArg (i)); - } + argc = Args->CheckParmList("-file", &args); + if ((gameinfo.flags & GI_SHAREWARE) && argc > 0) + { + I_FatalError ("You cannot -file with the shareware version. Register!"); + } + for (i = 0; i < argc; ++i) + { + D_AddWildFile(wadfiles, args[i]); } - files->Destroy(); - files1->Destroy(); - files2->Destroy(); - files3->Destroy(); } static void CopyFiles(TArray &to, TArray &from) @@ -1753,10 +1730,12 @@ static FString CheckGameInfo(TArray & pwads) void D_DoomMain (void) { int p, flags; - char *v; + const char *v; const char *wad; DArgs *execFiles; TArray pwads; + FString *args; + int argcount; // Set the FPU precision to 53 significant bits. This is the default // for Visual C++, but not for GCC, so some slight math variances @@ -1775,6 +1754,13 @@ void D_DoomMain (void) #endif #endif + // Combine different file parameters with their pre-switch bits. + Args->CollectFiles("-deh", ".deh"); + Args->CollectFiles("-bex", ".bex"); + Args->CollectFiles("-exec", ".cfg"); + Args->CollectFiles("-playdemo", ".lmp"); + Args->CollectFiles("-file", NULL); // anythnig left goes after -file + PClass::StaticInit (); atterm (C_DeinitConsole); @@ -1861,16 +1847,21 @@ void D_DoomMain (void) D_MultiExec (execFiles, true); // Run .cfg files at the start of the command line. - execFiles = Args->GatherFiles (NULL, ".cfg", false); + 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. + pwads.Clear(); + pwads.ShrinkToFit(); + Printf ("W_Init: Init WADfiles.\n"); Wads.InitMultipleFiles (allwads); allwads.Clear(); + allwads.ShrinkToFit(); // [RH] Initialize localizable strings. GStrings.LoadStrings (false); @@ -1963,21 +1954,23 @@ void D_DoomMain (void) autostart = true; } - // [RH] Hack to handle +map - p = Args->CheckParm ("+map"); - if (p && p < Args->NumArgs()-1) + // [RH] Hack to handle +map. The standard console command line handler + // won't be able to handle it, so we take it out of the command line and set + // it up like -warp. + FString mapvalue = Args->TakeValue("+map"); + if (mapvalue.IsNotEmpty()) { - if (!P_CheckMapData(Args->GetArg (p+1))) + if (!P_CheckMapData(mapvalue)) { - Printf ("Can't find map %s\n", Args->GetArg (p+1)); + Printf ("Can't find map %s\n", mapvalue.GetChars()); } else { - startmap = Args->GetArg (p + 1); - Args->GetArg (p)[0] = '-'; + startmap = mapvalue; autostart = true; } } + if (devparm) { Printf ("%s", GStrings("D_DEVSTR")); @@ -1995,17 +1988,12 @@ void D_DoomMain (void) #endif // turbo option // [RH] (now a cvar) + v = Args->CheckValue("-turbo"); + if (v != NULL) { - UCVarValue value; - static char one_hundred[] = "100"; - - value.String = Args->CheckValue ("-turbo"); - if (value.String == NULL) - value.String = one_hundred; - else - Printf ("turbo scale: %s%%\n", value.String); - - turbo.SetGenericRepDefault (value, CVAR_String); + double amt = atof(v); + Printf ("turbo scale: %.0f%%\n", amt); + turbo = (float)amt; } v = Args->CheckValue ("-timer"); @@ -2039,6 +2027,9 @@ void D_DoomMain (void) StartScreen->AppendStatusLine(temp); } + // [RH] Load sound environments + S_ParseReverbDef (); + // [RH] Parse through all loaded mapinfo lumps Printf ("G_ParseMapInfo: Load map definitions.\n"); G_ParseMapInfo (iwad_info->MapInfo); @@ -2047,7 +2038,6 @@ void D_DoomMain (void) Printf ("S_InitData: Load sound definitions.\n"); S_InitData (); - Printf ("Texman.Init: Init texture manager.\n"); TexMan.Init(); @@ -2083,7 +2073,7 @@ void D_DoomMain (void) // If there are none, try adding any in the config file. // Note that the command line overrides defaults from the config. - if ((ConsiderPatches("-deh", ".deh") | ConsiderPatches("-bex", ".bex")) == 0 && + if ((ConsiderPatches("-deh") | ConsiderPatches("-bex")) == 0 && gameinfo.gametype == GAME_Doom && GameConfig->SetSection ("Doom.DefaultDehacked")) { const char *key; @@ -2121,10 +2111,10 @@ void D_DoomMain (void) } //Added by MC: - DArgs *bots = Args->GatherFiles("-bots", "", false); - for (p = 0; p < bots->NumArgs(); ++p) + argcount = Args->CheckParmList("-bots", &args); + for (p = 0; p < argcount; ++p) { - bglobal.getspawned.Push(bots->GetArg(p)); + bglobal.getspawned.Push(args[p]); } bglobal.spawn_tries = 0; bglobal.wanted_botnum = bglobal.getspawned.Size(); @@ -2174,14 +2164,13 @@ void D_DoomMain (void) V_Init2(); - DArgs *files = Args->GatherFiles ("-playdemo", ".lmp", false); - if (files->NumArgs() > 0) + v = Args->CheckValue("-playdemo"); + if (v != NULL) { singledemo = true; // quit after one demo - G_DeferedPlayDemo (files->GetArg (0)); + G_DeferedPlayDemo (v); D_DoomLoop (); // never returns } - files->Destroy(); v = Args->CheckValue ("-timedemo"); if (v) diff --git a/src/d_netinf.h b/src/d_netinf.h index c2d49630c..728bad327 100644 --- a/src/d_netinf.h +++ b/src/d_netinf.h @@ -54,7 +54,8 @@ void D_DoServerInfoChange (BYTE **stream, bool singlebit); void D_WriteUserInfoStrings (int player, BYTE **stream, bool compact=false); void D_ReadUserInfoStrings (int player, BYTE **stream, bool update); -void D_GetPlayerColor (int player, float *h, float *s, float *v); +struct FPlayerColorSet; +void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet **colorset); void D_PickRandomTeam (int player); int D_PickRandomTeam (); class player_t; diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 608408627..ac1f77128 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -65,6 +65,7 @@ EXTERN_CVAR (Bool, teamplay) CVAR (Float, autoaim, 5000.f, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE); +CVAR (Int, colorset, 0, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, skin, "base", CVAR_USERINFO | CVAR_ARCHIVE); CVAR (Int, team, TEAM_NONE, CVAR_USERINFO | CVAR_ARCHIVE); CVAR (String, gender, "male", CVAR_USERINFO | CVAR_ARCHIVE); @@ -85,6 +86,7 @@ enum INFO_MoveBob, INFO_StillBob, INFO_PlayerClass, + INFO_ColorSet, }; const char *GenderNames[3] = { "male", "female", "other" }; @@ -101,6 +103,7 @@ static const char *UserInfoStrings[] = "movebob", "stillbob", "playerclass", + "colorset", NULL }; @@ -184,10 +187,24 @@ int D_PlayerClassToInt (const char *classname) } } -void D_GetPlayerColor (int player, float *h, float *s, float *v) +void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet **set) { userinfo_t *info = &players[player].userinfo; - int color = info->color; + FPlayerColorSet *colorset = NULL; + int color; + + if (players[player].mo != NULL) + { + colorset = P_GetPlayerColorSet(players[player].mo->GetClass()->TypeName, info->colorset); + } + if (colorset != NULL) + { + color = GPalette.BaseColors[GPalette.Remap[colorset->RepresentativeColor]]; + } + else + { + color = info->color; + } RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f, h, s, v); @@ -206,6 +223,10 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v) *s = clamp(ts + *s * 0.15f - 0.075f, 0.f, 1.f); *v = clamp(tv + *v * 0.5f - 0.25f, 0.f, 1.f); } + if (set != NULL) + { + *set = colorset; + } } // Find out which teams are present. If there is only one, @@ -379,6 +400,7 @@ void D_SetupUserInfo () coninfo->aimdist = abs ((int)(autoaim * (float)ANGLE_1)); } coninfo->color = color; + coninfo->colorset = colorset; coninfo->skin = R_FindSkin (skin, 0); coninfo->gender = D_GenderToInt (gender); coninfo->neverswitch = neverswitchonpickup; @@ -564,6 +586,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact) "\\name\\%s" "\\autoaim\\%g" "\\color\\%x %x %x" + "\\colorset\\%d" "\\skin\\%s" "\\team\\%d" "\\gender\\%s" @@ -574,6 +597,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact) , D_EscapeUserInfo(info->netname).GetChars(), (double)info->aimdist / (float)ANGLE_1, + info->colorset, RPART(info->color), GPART(info->color), BPART(info->color), D_EscapeUserInfo(skins[info->skin].name).GetChars(), info->team, @@ -599,6 +623,7 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact) "\\%g" // movebob "\\%g" // stillbob "\\%s" // playerclass + "\\%d" // colorset , D_EscapeUserInfo(info->netname).GetChars(), (double)info->aimdist / (float)ANGLE_1, @@ -610,7 +635,8 @@ void D_WriteUserInfoStrings (int i, BYTE **stream, bool compact) info->neverswitch, (float)(info->MoveBob) / 65536.f, (float)(info->StillBob) / 65536.f, - info->PlayerClass == -1 ? "Random" : D_EscapeUserInfo(type->DisplayName).GetChars() + info->PlayerClass == -1 ? "Random" : D_EscapeUserInfo(type->DisplayName).GetChars(), + info->colorset ); } } @@ -714,7 +740,15 @@ void D_ReadUserInfoStrings (int i, BYTE **stream, bool update) break; case INFO_Color: - info->color = V_GetColorFromString (NULL, value); + case INFO_ColorSet: + if (infotype == INFO_Color) + { + info->color = V_GetColorFromString (NULL, value); + } + else + { + info->colorset = atoi(value); + } R_BuildPlayerTranslation (i); if (StatusBar != NULL && i == StatusBar->GetPlayer()) { @@ -804,6 +838,10 @@ FArchive &operator<< (FArchive &arc, userinfo_t &info) arc.Read (&info.netname, sizeof(info.netname)); } arc << info.team << info.aimdist << info.color << info.skin << info.gender << info.neverswitch; + if (SaveVersion >= 2193) + { + arc << info.colorset; + } return arc; } @@ -829,6 +867,7 @@ CCMD (playerinfo) Printf ("Team: %s (%d)\n", ui->team == TEAM_NONE ? "None" : Teams[ui->team].GetName (), ui->team); Printf ("Aimdist: %d\n", ui->aimdist); Printf ("Color: %06x\n", ui->color); + Printf ("ColorSet: %d\n", ui->colorset); Printf ("Skin: %s (%d)\n", skins[ui->skin].name, ui->skin); Printf ("Gender: %s (%d)\n", GenderNames[ui->gender], ui->gender); Printf ("NeverSwitch: %d\n", ui->neverswitch); diff --git a/src/d_player.h b/src/d_player.h index 9f9942c86..3453819b0 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -65,6 +65,11 @@ public: BYTE ColorRangeEnd; }; +FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum); +void P_EnumPlayerColorSets(FName classname, TArray *out); + +class player_t; + class APlayerPawn : public AActor { DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) @@ -215,6 +220,7 @@ struct userinfo_t BYTE team; int aimdist; int color; + int colorset; int skin; int gender; bool neverswitch; diff --git a/src/doomdata.h b/src/doomdata.h index 37e7190d6..d066277a7 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -227,10 +227,10 @@ struct mapseg_t { WORD v1; WORD v2; - short angle; + SWORD angle; WORD linedef; - short side; - short offset; + SWORD side; + SWORD offset; }; @@ -242,11 +242,11 @@ struct mapseg_t struct mapnode_t { - short x,y,dx,dy; // partition line - short bbox[2][4]; // bounding box for each child + SWORD x,y,dx,dy; // partition line + SWORD bbox[2][4]; // bounding box for each child // If NF_SUBSECTOR is or'ed in, it's a subsector, // else it's a node of another subtree. - unsigned short children[2]; + WORD children[2]; }; @@ -256,23 +256,23 @@ struct mapnode_t // plus skill/visibility flags and attributes. struct mapthing_t { - short x; - short y; - short angle; - short type; - short options; + SWORD x; + SWORD y; + SWORD angle; + SWORD type; + SWORD options; }; // [RH] Hexen-compatible MapThing. struct mapthinghexen_t { - unsigned short thingid; - short x; - short y; - short z; - short angle; - short type; - short flags; + SWORD thingid; + SWORD x; + SWORD y; + SWORD z; + SWORD angle; + SWORD type; + SWORD flags; BYTE special; BYTE args[5]; }; diff --git a/src/f_finale.cpp b/src/f_finale.cpp index 9b8694d6f..51498134f 100644 --- a/src/f_finale.cpp +++ b/src/f_finale.cpp @@ -117,6 +117,10 @@ void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int } FinaleFlat = (flat != NULL && *flat != 0) ? flat : gameinfo.finaleFlat; + if (FinaleFlat != NULL && FinaleFlat[0] == '$') + { + FinaleFlat = GStrings(FinaleFlat + 1); + } if (textInLump) { @@ -758,7 +762,7 @@ void F_CastDrawer (void) FTexture* pic; // erase the entire screen to a background - screen->DrawTexture (TexMan["BOSSBACK"], 0, 0, + screen->DrawTexture (TexMan[GStrings("bgcastcall")], 0, 0, DTA_DestWidth, screen->GetWidth(), DTA_DestHeight, screen->GetHeight(), TAG_DONE); diff --git a/src/g_doom/a_possessed.cpp b/src/g_doom/a_possessed.cpp index af34dfe5f..2650d7743 100644 --- a/src/g_doom/a_possessed.cpp +++ b/src/g_doom/a_possessed.cpp @@ -126,7 +126,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CPosRefire) if (!self->target || P_HitFriend (self) || self->target->health <= 0 - || !P_CheckSight (self, self->target, 0) ) + || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) { self->SetState (self->SeeState); } diff --git a/src/g_doom/a_spidermaster.cpp b/src/g_doom/a_spidermaster.cpp index f8d89ce5f..2f312f7a6 100644 --- a/src/g_doom/a_spidermaster.cpp +++ b/src/g_doom/a_spidermaster.cpp @@ -24,7 +24,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpidRefire) if (!self->target || P_HitFriend (self) || self->target->health <= 0 - || !P_CheckSight (self, self->target, 0) ) + || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) { self->SetState (self->SeeState); } diff --git a/src/g_game.cpp b/src/g_game.cpp index 52f07ad9c..6a0602d3f 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2192,18 +2192,14 @@ void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf) // // G_RecordDemo // -void G_RecordDemo (char* name) +void G_RecordDemo (const char* name) { - char *v; - usergame = false; strcpy (demoname, name); FixPathSeperator (demoname); DefaultExtension (demoname, ".lmp"); - v = Args->CheckValue ("-maxdemo"); maxdemosize = 0x20000; demobuffer = (BYTE *)M_Malloc (maxdemosize); - demorecording = true; } @@ -2288,7 +2284,7 @@ void G_BeginRecording (const char *startmap) FString defdemoname; -void G_DeferedPlayDemo (char *name) +void G_DeferedPlayDemo (const char *name) { defdemoname = name; gameaction = ga_playdemo; @@ -2516,7 +2512,7 @@ void G_DoPlayDemo (void) // // G_TimeDemo // -void G_TimeDemo (char* name) +void G_TimeDemo (const char* name) { nodrawers = !!Args->CheckParm ("-nodraw"); noblit = !!Args->CheckParm ("-noblit"); diff --git a/src/g_game.h b/src/g_game.h index 72afcd3c5..56f16081b 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -32,7 +32,7 @@ struct PNGHandle; // void G_DeathMatchSpawnPlayer (int playernum); -void G_DeferedPlayDemo (char* demo); +void G_DeferedPlayDemo (const char* demo); // Can be called by the startup code or M_Responder, // calls P_SetupLevel or W_EnterWorld. @@ -44,12 +44,12 @@ void G_DoLoadGame (void); void G_SaveGame (const char *filename, const char *description); // Only called by startup code. -void G_RecordDemo (char* name); +void G_RecordDemo (const char* name); void G_BeginRecording (const char *startmap); void G_PlayDemo (char* name); -void G_TimeDemo (char* name); +void G_TimeDemo (const char* name); bool G_CheckDemoStatus (void); void G_WorldDone (void); diff --git a/src/g_hexen/a_clericstaff.cpp b/src/g_hexen/a_clericstaff.cpp index 1b2bd74fa..211559b94 100644 --- a/src/g_hexen/a_clericstaff.cpp +++ b/src/g_hexen/a_clericstaff.cpp @@ -69,7 +69,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) for (i = 0; i < 3; i++) { angle = pmo->angle+i*(ANG45/16); - slope = P_AimLineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, false, true); + slope = P_AimLineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D); if (linetarget) { P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindActor("CStaffPuff")); @@ -93,7 +93,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CStaffCheck) break; } angle = pmo->angle-i*(ANG45/16); - slope = P_AimLineAttack (player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, false, true); + slope = P_AimLineAttack (player->mo, angle, fixed_t(1.5*MELEERANGE), &linetarget, 0, ALF_CHECK3D); if (linetarget) { P_LineAttack (pmo, angle, fixed_t(1.5*MELEERANGE), slope, damage, NAME_Melee, PClass::FindActor("CStaffPuff")); diff --git a/src/g_hexen/a_fighterhammer.cpp b/src/g_hexen/a_fighterhammer.cpp index e0dca5068..4bacfa2e9 100644 --- a/src/g_hexen/a_fighterhammer.cpp +++ b/src/g_hexen/a_fighterhammer.cpp @@ -50,7 +50,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) for (i = 0; i < 16; i++) { angle = pmo->angle + i*(ANG45/32); - slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); + slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); if (linetarget) { P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true); @@ -63,7 +63,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) goto hammerdone; } angle = pmo->angle-i*(ANG45/32); - slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); + slope = P_AimLineAttack(pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); if(linetarget) { P_LineAttack(pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true); @@ -78,7 +78,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FHammerAttack) } // didn't find any targets in meleerange, so set to throw out a hammer angle = pmo->angle; - slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, false, true); + slope = P_AimLineAttack (pmo, angle, HAMMER_RANGE, &linetarget, 0, ALF_CHECK3D); if (P_LineAttack (pmo, angle, HAMMER_RANGE, slope, damage, NAME_Melee, hammertime, true) != NULL) { pmo->special1 = false; diff --git a/src/g_hexen/a_magecone.cpp b/src/g_hexen/a_magecone.cpp index 4e1ff7739..0cdb16832 100644 --- a/src/g_hexen/a_magecone.cpp +++ b/src/g_hexen/a_magecone.cpp @@ -79,7 +79,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireConePL1) for (i = 0; i < 16; i++) { angle = self->angle+i*(ANG45/16); - slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget, 0, false, true); + slope = P_AimLineAttack (self, angle, MELEERANGE, &linetarget, 0, ALF_CHECK3D); if (linetarget) { P_DamageMobj (linetarget, self, self, damage, NAME_Ice); diff --git a/src/g_level.cpp b/src/g_level.cpp index 1b0bd1130..1fd0130dc 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -572,7 +572,7 @@ void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nex if (strncmp(levelname, "enDSeQ", 6) != 0) { - nextinfo = FindLevelInfo (nextlevel); + nextinfo = FindLevelInfo (levelname); if (nextinfo != NULL) { level_info_t *nextredir = nextinfo->CheckLevelRedirect(); @@ -1039,7 +1039,7 @@ void G_WorldDone (void) { F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder, thiscluster->cdtrack, thiscluster->cdid, - thiscluster->finaleflat, thiscluster->ExitText, + thiscluster->FinaleFlat, thiscluster->ExitText, thiscluster->flags & CLUSTER_EXITTEXTINLUMP, thiscluster->flags & CLUSTER_FINALEPIC, thiscluster->flags & CLUSTER_LOOKUPEXITTEXT, @@ -1057,7 +1057,7 @@ void G_WorldDone (void) { F_StartFinale (nextcluster->MessageMusic, nextcluster->musicorder, nextcluster->cdtrack, nextcluster->cdid, - nextcluster->finaleflat, nextcluster->EnterText, + nextcluster->FinaleFlat, nextcluster->EnterText, nextcluster->flags & CLUSTER_ENTERTEXTINLUMP, nextcluster->flags & CLUSTER_FINALEPIC, nextcluster->flags & CLUSTER_LOOKUPENTERTEXT, @@ -1067,7 +1067,7 @@ void G_WorldDone (void) { F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder, thiscluster->cdtrack, nextcluster->cdid, - thiscluster->finaleflat, thiscluster->ExitText, + thiscluster->FinaleFlat, thiscluster->ExitText, thiscluster->flags & CLUSTER_EXITTEXTINLUMP, thiscluster->flags & CLUSTER_FINALEPIC, thiscluster->flags & CLUSTER_LOOKUPEXITTEXT, @@ -1319,6 +1319,8 @@ void G_InitLevelLocals () compatflags.Callback(); NormalLight.ChangeFade (level.fadeto); + + level.DefaultEnvironment = info->DefaultEnvironment; } //========================================================================== diff --git a/src/g_level.h b/src/g_level.h index 3f5186b1e..b1575e33f 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -66,15 +66,16 @@ struct FMapInfoParser int format_type; bool HexenHack; - FMapInfoParser() + FMapInfoParser(int format = FMT_Unknown) { - format_type = FMT_Unknown; + format_type = format; HexenHack = false; } bool ParseLookupName(FString &dest); void ParseMusic(FString &name, int &order); void ParseLumpOrTextureName(char *name); + void ParseLumpOrTextureName(FString &name); void ParseCluster(); void ParseNextMap(char *mapname); @@ -276,6 +277,7 @@ struct level_info_t DWORD compatflags; DWORD compatmask; FString Translator; // for converting Doom-format linedef and sector types. + int DefaultEnvironment; // Default sound environment for the map. // Redirection: If any player is carrying the specified item, then // you go to the RedirectMap instead of this one. @@ -388,6 +390,7 @@ struct FLevelLocals fixed_t aircontrol; fixed_t airfriction; int airsupply; + int DefaultEnvironment; // Default sound environment. FSectorScrollValues *Scrolls; // NULL if no DScrollers in this level @@ -437,7 +440,7 @@ extern TArray EndSequences; struct cluster_info_t { int cluster; - char finaleflat[9]; + FString FinaleFlat; FString ExitText; FString EnterText; FString MessageMusic; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index cfdaf75c1..a0da36af2 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -265,6 +265,7 @@ void level_info_t::Reset() bordertexture[0] = 0; teamdamage = 0.f; specialactions.Clear(); + DefaultEnvironment = 0; } @@ -389,7 +390,7 @@ bool level_info_t::isValid() void cluster_info_t::Reset() { cluster = 0; - finaleflat[0] = 0; + FinaleFlat = ""; ExitText = ""; EnterText = ""; MessageMusic = ""; @@ -615,6 +616,12 @@ void FMapInfoParser::ParseLumpOrTextureName(char *name) name[8]=0; } +void FMapInfoParser::ParseLumpOrTextureName(FString &name) +{ + sc.MustGetString(); + name = sc.String; +} + //========================================================================== // @@ -691,12 +698,12 @@ void FMapInfoParser::ParseCluster() else if (sc.Compare("flat")) { ParseAssign(); - ParseLumpOrTextureName(clusterinfo->finaleflat); + ParseLumpOrTextureName(clusterinfo->FinaleFlat); } else if (sc.Compare("pic")) { ParseAssign(); - ParseLumpOrTextureName(clusterinfo->finaleflat); + ParseLumpOrTextureName(clusterinfo->FinaleFlat); clusterinfo->flags |= CLUSTER_FINALEPIC; } else if (sc.Compare("hub")) @@ -1244,6 +1251,36 @@ DEFINE_MAP_OPTION(mapbackground, true) parse.ParseLumpOrTextureName(info->mapbg); } +DEFINE_MAP_OPTION(defaultenvironment, false) +{ + int id; + + parse.ParseAssign(); + if (parse.sc.CheckNumber()) + { // Numeric ID XXX [, YYY] + id = parse.sc.Number << 8; + if (parse.CheckNumber()) + { + id |= parse.sc.Number; + } + } + else + { // Named environment + parse.sc.MustGetString(); + ReverbContainer *reverb = S_FindEnvironment(parse.sc.String); + if (reverb == NULL) + { + parse.sc.ScriptMessage("Unknown sound environment '%s'\n", parse.sc.String); + id = 0; + } + else + { + id = reverb->ID; + } + } + info->DefaultEnvironment = id; +} + //========================================================================== // @@ -1923,10 +1960,23 @@ void G_ParseMapInfo (const char *basemapinfo) parse.ParseMapInfo(Wads.GetNumForFullName(basemapinfo), gamedefaults, defaultinfo); } + static const char *mapinfonames[] = { "MAPINFO", "ZMAPINFO", NULL }; + int nindex; + // Parse any extra MAPINFOs. - while ((lump = Wads.FindLump ("MAPINFO", &lastlump)) != -1) + while ((lump = Wads.FindLumpMulti (mapinfonames, &lastlump, false, &nindex)) != -1) { - FMapInfoParser parse; + if (nindex == 0) + { + // If this lump is named MAPINFO we need to check if the same WAD contains a ZMAPINFO lump. + // If that exists we need to skip this one. + + int wad = Wads.GetLumpFile(lump); + int altlump = Wads.CheckNumForName("ZMAPINFO", ns_global, wad, true); + + if (altlump >= 0) continue; + } + FMapInfoParser parse(nindex == 1? FMapInfoParser::FMT_New : FMapInfoParser::FMT_Unknown); level_info_t defaultinfo; parse.ParseMapInfo(lump, gamedefaults, defaultinfo); } diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index 48cd26370..fb246c0b6 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -193,6 +193,12 @@ void APowerup::DoEffect () void APowerup::EndEffect () { + int colormap = GetSpecialColormap(BlendColor); + + if (colormap != NOFIXEDCOLORMAP && Owner && Owner->player && Owner->player->fixedcolormap == colormap) + { // only unset if the fixed colormap comes from this item + Owner->player->fixedcolormap = NOFIXEDCOLORMAP; + } } //=========================================================================== @@ -347,6 +353,7 @@ IMPLEMENT_CLASS (APowerInvulnerable) void APowerInvulnerable::InitEffect () { + Super::InitEffect(); Owner->effects &= ~FX_RESPAWNINVUL; Owner->flags2 |= MF2_INVULNERABLE; if (Mode == NAME_None && Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn))) @@ -421,6 +428,8 @@ void APowerInvulnerable::DoEffect () void APowerInvulnerable::EndEffect () { + Super::EndEffect(); + if (Owner == NULL) { return; @@ -498,6 +507,7 @@ bool APowerStrength::HandlePickup (AInventory *item) void APowerStrength::InitEffect () { + Super::InitEffect(); } //=========================================================================== @@ -537,7 +547,6 @@ PalEntry APowerStrength::GetBlend () // Invisibility Powerup ------------------------------------------------------ IMPLEMENT_CLASS (APowerInvisibility) -IMPLEMENT_CLASS (APowerShadow) // Invisibility flag combos #define INVISIBILITY_FLAGS1 (MF_SHADOW) @@ -552,6 +561,7 @@ IMPLEMENT_CLASS (APowerShadow) void APowerInvisibility::InitEffect () { + Super::InitEffect(); // This used to call CommonInit(), which used to contain all the code that's repeated every // tic, plus the following code that needs to happen once and only once. // The CommonInit() code has been moved to DoEffect(), so this now ends with a call to DoEffect(), @@ -615,6 +625,7 @@ void APowerInvisibility::DoEffect () void APowerInvisibility::EndEffect () { + Super::EndEffect(); if (Owner != NULL) { Owner->flags &= ~(flags & INVISIBILITY_FLAGS1); @@ -822,6 +833,7 @@ void APowerLightAmp::DoEffect () void APowerLightAmp::EndEffect () { + Super::EndEffect(); if (Owner != NULL && Owner->player != NULL && Owner->player->fixedcolormap < NUMCOLORMAPS) { Owner->player->fixedlightlevel = -1; @@ -914,6 +926,7 @@ void APowerFlight::Serialize (FArchive &arc) void APowerFlight::InitEffect () { + Super::InitEffect(); Owner->flags2 |= MF2_FLY; Owner->flags |= MF_NOGRAVITY; if (Owner->z <= Owner->floorz) @@ -955,6 +968,7 @@ void APowerFlight::Tick () void APowerFlight::EndEffect () { + Super::EndEffect(); if (Owner == NULL || Owner->player == NULL) { return; @@ -1035,6 +1049,8 @@ void APowerWeaponLevel2::InitEffect () { AWeapon *weapon, *sister; + Super::InitEffect(); + if (Owner->player == NULL) return; @@ -1071,6 +1087,7 @@ void APowerWeaponLevel2::EndEffect () { player_t *player = Owner != NULL ? Owner->player : NULL; + Super::EndEffect(); if (player != NULL) { @@ -1199,6 +1216,8 @@ void APowerTargeter::InitEffect () { player_t *player; + Super::InitEffect(); + if ((player = Owner->player) == NULL) return; @@ -1250,6 +1269,7 @@ void APowerTargeter::DoEffect () void APowerTargeter::EndEffect () { + Super::EndEffect(); if (Owner != NULL && Owner->player != NULL) { P_SetPsprite (Owner->player, ps_targetcenter, NULL); @@ -1281,6 +1301,8 @@ IMPLEMENT_CLASS (APowerFrightener) void APowerFrightener::InitEffect () { + Super::InitEffect(); + if (Owner== NULL || Owner->player == NULL) return; @@ -1295,6 +1317,8 @@ void APowerFrightener::InitEffect () void APowerFrightener::EndEffect () { + Super::EndEffect(); + if (Owner== NULL || Owner->player == NULL) return; @@ -1319,6 +1343,8 @@ void APowerTimeFreezer::InitEffect( ) { int ulIdx; + Super::InitEffect(); + if (Owner== NULL || Owner->player == NULL) return; @@ -1394,6 +1420,8 @@ void APowerTimeFreezer::EndEffect( ) { int ulIdx; + Super::EndEffect(); + // Allow other actors to move about freely once again. level.flags2 &= ~LEVEL2_FROZEN; @@ -1432,6 +1460,8 @@ IMPLEMENT_CLASS( APowerDamage) void APowerDamage::InitEffect( ) { + Super::InitEffect(); + // Use sound channel 5 to avoid interference with other actions. if (Owner != NULL) S_Sound(Owner, 5, SeeSound, 1.0f, ATTN_NONE); } @@ -1444,6 +1474,7 @@ void APowerDamage::InitEffect( ) void APowerDamage::EndEffect( ) { + Super::EndEffect(); // Use sound channel 5 to avoid interference with other actions. if (Owner != NULL) S_Sound(Owner, 5, DeathSound, 1.0f, ATTN_NONE); } @@ -1495,6 +1526,8 @@ IMPLEMENT_CLASS(APowerProtection) void APowerProtection::InitEffect( ) { + Super::InitEffect(); + if (Owner != NULL) { S_Sound(Owner, CHAN_AUTO, SeeSound, 1.0f, ATTN_NONE); @@ -1518,6 +1551,7 @@ void APowerProtection::InitEffect( ) void APowerProtection::EndEffect( ) { + Super::EndEffect(); if (Owner != NULL) { S_Sound(Owner, CHAN_AUTO, DeathSound, 1.0f, ATTN_NONE); @@ -1570,6 +1604,8 @@ IMPLEMENT_CLASS(APowerDrain) void APowerDrain::InitEffect( ) { + Super::InitEffect(); + if (Owner== NULL || Owner->player == NULL) return; @@ -1585,6 +1621,8 @@ void APowerDrain::InitEffect( ) void APowerDrain::EndEffect( ) { + Super::EndEffect(); + // Nothing to do if there's no owner. if (Owner != NULL && Owner->player != NULL) { @@ -1606,6 +1644,8 @@ IMPLEMENT_CLASS(APowerRegeneration) void APowerRegeneration::InitEffect( ) { + Super::InitEffect(); + if (Owner== NULL || Owner->player == NULL) return; @@ -1621,6 +1661,7 @@ void APowerRegeneration::InitEffect( ) void APowerRegeneration::EndEffect( ) { + Super::EndEffect(); // Nothing to do if there's no owner. if (Owner != NULL && Owner->player != NULL) { @@ -1641,6 +1682,8 @@ IMPLEMENT_CLASS(APowerHighJump) void APowerHighJump::InitEffect( ) { + Super::InitEffect(); + if (Owner== NULL || Owner->player == NULL) return; @@ -1656,6 +1699,7 @@ void APowerHighJump::InitEffect( ) void APowerHighJump::EndEffect( ) { + Super::EndEffect(); // Nothing to do if there's no owner. if (Owner != NULL && Owner->player != NULL) { @@ -1676,6 +1720,8 @@ IMPLEMENT_CLASS(APowerDoubleFiringSpeed) void APowerDoubleFiringSpeed::InitEffect( ) { + Super::InitEffect(); + if (Owner== NULL || Owner->player == NULL) return; @@ -1691,6 +1737,7 @@ void APowerDoubleFiringSpeed::InitEffect( ) void APowerDoubleFiringSpeed::EndEffect( ) { + Super::EndEffect(); // Nothing to do if there's no owner. if (Owner != NULL && Owner->player != NULL) { @@ -1724,6 +1771,8 @@ void APowerMorph::Serialize (FArchive &arc) void APowerMorph::InitEffect( ) { + Super::InitEffect(); + if (Owner != NULL && Owner->player != NULL && PlayerClass != NAME_None) { player_t *realplayer = Owner->player; // Remember the identity of the player @@ -1751,6 +1800,8 @@ void APowerMorph::InitEffect( ) void APowerMorph::EndEffect( ) { + Super::EndEffect(); + // Abort if owner already destroyed if (Owner == NULL) { @@ -1806,6 +1857,8 @@ IMPLEMENT_CLASS(APowerInfiniteAmmo) void APowerInfiniteAmmo::InitEffect( ) { + Super::InitEffect(); + if (Owner== NULL || Owner->player == NULL) return; @@ -1821,6 +1874,8 @@ void APowerInfiniteAmmo::InitEffect( ) void APowerInfiniteAmmo::EndEffect( ) { + Super::EndEffect(); + // Nothing to do if there's no owner. if (Owner != NULL && Owner->player != NULL) { diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 6cd45b035..6d1bdd31f 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -81,12 +81,6 @@ protected: // fixed_t OwnersNormalAlpha; }; -// Needed only for m_cheat.cpp now -class APowerShadow : public APowerInvisibility -{ - DECLARE_CLASS (APowerShadow, APowerInvisibility) -}; - class APowerIronFeet : public APowerup { DECLARE_CLASS (APowerIronFeet, APowerup) diff --git a/src/g_shared/a_camera.cpp b/src/g_shared/a_camera.cpp index c47c7c22d..99da16ae7 100644 --- a/src/g_shared/a_camera.cpp +++ b/src/g_shared/a_camera.cpp @@ -53,7 +53,6 @@ class ASecurityCamera : public AActor public: void PostBeginPlay (); void Tick (); - angle_t AngleIncrements (); void Serialize (FArchive &arc); protected: @@ -71,11 +70,6 @@ void ASecurityCamera::Serialize (FArchive &arc) arc << Center << Acc << Delta << Range; } -angle_t ASecurityCamera::AngleIncrements () -{ - return ANGLE_1; -} - void ASecurityCamera::PostBeginPlay () { Super::PostBeginPlay (); diff --git a/src/g_shared/a_hatetarget.cpp b/src/g_shared/a_hatetarget.cpp index 71c254bad..3753d0bb9 100644 --- a/src/g_shared/a_hatetarget.cpp +++ b/src/g_shared/a_hatetarget.cpp @@ -43,7 +43,6 @@ class AHateTarget : public AActor DECLARE_CLASS (AHateTarget, AActor) public: void BeginPlay (); - angle_t AngleIncrements (void); int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype); }; @@ -77,7 +76,3 @@ int AHateTarget::TakeSpecialDamage (AActor *inflictor, AActor *source, int damag } } -angle_t AHateTarget::AngleIncrements (void) -{ - return ANGLE_1; -} diff --git a/src/g_shared/a_keys.cpp b/src/g_shared/a_keys.cpp index c0e13e414..064f1e1ec 100644 --- a/src/g_shared/a_keys.cpp +++ b/src/g_shared/a_keys.cpp @@ -68,6 +68,7 @@ struct Lock return true; } } + return false; } else for(unsigned int i=0;ihuds[barNum] != NULL) + { + delete this->huds[barNum]; + } this->huds[barNum] = new SBarInfoMainBlock(this); if(barNum == STBAR_AUTOMAP) { diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index f84dc6a8b..a8d570605 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -166,20 +166,23 @@ static void DrawHudText(FFont *font, int color, char * text, int x, int y, int t { int width; FTexture *texc = font->GetChar(text[i], &width); - int offset = texc->TopOffset - tex_zero->TopOffset + tex_zero->GetHeight(); - screen->DrawChar(font, color, x, y, text[i], - DTA_KeepRatio, true, - DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, - DTA_LeftOffset, width/2, DTA_TopOffset, offset, - /*DTA_CenterBottomOffset, 1,*/ TAG_DONE); - x+=zerowidth; + if (texc != NULL) + { + int offset = texc->TopOffset - tex_zero->TopOffset + tex_zero->GetHeight(); + screen->DrawChar(font, color, x, y, text[i], + DTA_KeepRatio, true, + DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_Alpha, trans, + DTA_LeftOffset, width/2, DTA_TopOffset, offset, + /*DTA_CenterBottomOffset, 1,*/ TAG_DONE); + } + x += zerowidth; } } //--------------------------------------------------------------------------- // -// Draws a numberses a fixed widh for all characters +// Draws a number with a fixed width for all digits // //--------------------------------------------------------------------------- diff --git a/src/g_strife/a_crusader.cpp b/src/g_strife/a_crusader.cpp index 5d43b030d..8307056c5 100644 --- a/src/g_strife/a_crusader.cpp +++ b/src/g_strife/a_crusader.cpp @@ -9,7 +9,7 @@ #include "thingdef/thingdef.h" */ -bool Sys_1ed64 (AActor *self) +static bool CrusaderCheckRange (AActor *self) { if (P_CheckSight (self, self->target) && self->reactiontime == 0) { @@ -25,7 +25,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CrusaderChoose) if (self->target == NULL) return 0; - if (Sys_1ed64 (self)) + if (CrusaderCheckRange (self)) { A_FaceTarget (self); self->angle -= ANGLE_180/16; diff --git a/src/g_strife/a_sentinel.cpp b/src/g_strife/a_sentinel.cpp index 4e9303332..87579ff8d 100644 --- a/src/g_strife/a_sentinel.cpp +++ b/src/g_strife/a_sentinel.cpp @@ -87,7 +87,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SentinelRefire) { if (self->target == NULL || self->target->health <= 0 || - !P_CheckSight (self, self->target) || + !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) || P_HitFriend(self) || pr_sentinelrefire() < 40) { diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index e9f90a23d..936d4e7f7 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -536,13 +536,14 @@ void FGameConfigFile::ArchiveGlobalData () FString FGameConfigFile::GetConfigPath (bool tryProg) { - char *pathval; + const char *pathval; FString path; pathval = Args->CheckValue ("-config"); if (pathval != NULL) + { return FString(pathval); - + } #ifdef _WIN32 path = NULL; HRESULT hr; diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index 456652bc7..1d881bd3d 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -418,7 +418,7 @@ void HU_DrawColorBar(int x, int y, int height, int playernum) { float h, s, v, r, g, b; - D_GetPlayerColor (playernum, &h, &s, &v); + D_GetPlayerColor (playernum, &h, &s, &v, NULL); HSVtoRGB (&r, &g, &b, h, s, v); screen->Clear (x, y, x + 24*CleanXfac, y + height, -1, diff --git a/src/i_net.cpp b/src/i_net.cpp index 3ff86f7ec..633c75d1a 100644 --- a/src/i_net.cpp +++ b/src/i_net.cpp @@ -338,20 +338,21 @@ void PreSend (const void *buffer, int bufferlen, const sockaddr_in *to) sendto (mysocket, (const char *)buffer, bufferlen, 0, (const sockaddr *)to, sizeof(*to)); } -void BuildAddress (sockaddr_in *address, char *name) +void BuildAddress (sockaddr_in *address, const char *name) { hostent *hostentry; // host information entry u_short port; - char *portpart; + const char *portpart; bool isnamed = false; int curchar; char c; + FString target; address->sin_family = AF_INET; if ( (portpart = strchr (name, ':')) ) { - *portpart = 0; + target = FString(name, portpart - name); port = atoi (portpart + 1); if (!port) { @@ -361,11 +362,12 @@ void BuildAddress (sockaddr_in *address, char *name) } else { + target = name; port = DOOMPORT; } address->sin_port = htons(port); - for (curchar = 0; (c = name[curchar]) ; curchar++) + for (curchar = 0; (c = target[curchar]) ; curchar++) { if ((c < '0' || c > '9') && c != '.') { @@ -376,21 +378,18 @@ void BuildAddress (sockaddr_in *address, char *name) if (!isnamed) { - address->sin_addr.s_addr = inet_addr (name); - Printf ("Node number %d, address %s\n", doomcom.numnodes, name); + address->sin_addr.s_addr = inet_addr (target); + Printf ("Node number %d, address %s\n", doomcom.numnodes, target.GetChars()); } else { - hostentry = gethostbyname (name); + hostentry = gethostbyname (target); if (!hostentry) - I_FatalError ("gethostbyname: couldn't find %s\n%s", name, neterror()); + I_FatalError ("gethostbyname: couldn't find %s\n%s", target.GetChars(), neterror()); address->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; Printf ("Node number %d, hostname %s\n", doomcom.numnodes, hostentry->h_name); } - - if (portpart) - *portpart = ':'; } void CloseNetwork (void) @@ -910,7 +909,7 @@ static bool NodesOnSameNetwork() bool I_InitNetwork (void) { int i; - char *v; + const char *v; memset (&doomcom, 0, sizeof(doomcom)); diff --git a/src/info.cpp b/src/info.cpp index f4da5bf1f..2abe17bed 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -460,18 +460,11 @@ PClassActor *PClassActor::GetReplacee(bool lookskill) void PClassActor::SetDamageFactor(FName type, fixed_t factor) { - if (factor != FRACUNIT) + if (DamageFactors == NULL) { - if (DamageFactors == NULL) - { - DamageFactors = new DmgFactors; - } - DamageFactors->Insert(type, factor); - } - else if (DamageFactors != NULL) - { - DamageFactors->Remove(type); + DamageFactors = new DmgFactors; } + DamageFactors->Insert(type, factor); } //========================================================================== @@ -488,7 +481,7 @@ void PClassActor::SetPainChance(FName type, int chance) { PainChances = new PainChanceList; } - PainChances->Insert(type, MIN(chance, 255)); + PainChances->Insert(type, MIN(chance, 256)); } else if (PainChances != NULL) { @@ -501,6 +494,25 @@ void PClassActor::SetPainChance(FName type, int chance) // //========================================================================== +void PClassActor::SetColorSet(int index, const FPlayerColorSet *set) +{ + if (set != NULL) + { + if (ColorSets == NULL) ColorSets = new FPlayerColorSetMap; + ColorSets->Insert(index, *set); + } + else + { + if (ColorSets != NULL) + ColorSets->Remove(index); + } +} + +//========================================================================== +// +// +//========================================================================== + FDoomEdMap DoomEdMap; FDoomEdMap::FDoomEdEntry *FDoomEdMap::DoomEdHash[DOOMED_HASHSIZE]; @@ -678,4 +690,4 @@ CCMD (summonmbf) CCMD (summonfoe) { SummonActor (DEM_SUMMONFOE, DEM_SUMMONFOE2, argv); -} +} \ No newline at end of file diff --git a/src/info.h b/src/info.h index 3af996b44..bdeefb53f 100644 --- a/src/info.h +++ b/src/info.h @@ -123,8 +123,21 @@ FArchive &operator<< (FArchive &arc, FState *&state); #include "gametype.h" +// Standard pre-defined skin colors +struct FPlayerColorSet +{ + FName Name; // Name of this color + + int Lump; // Lump to read the translation from, otherwise use next 2 fields + BYTE FirstColor, LastColor; // Describes the range of colors to use for the translation + + BYTE RepresentativeColor; // A palette entry representative of this translation, + // for map arrows and status bar backgrounds and such +}; + typedef TMap DmgFactors; -typedef TMap PainChanceList; +typedef TMap PainChanceList; +typedef TMap FPlayerColorSetMap; class DDropItem; class PClassActor : public PClass @@ -145,6 +158,7 @@ public: void RegisterIDs(); void SetDamageFactor(FName type, fixed_t factor); void SetPainChance(FName type, int chance); + void SetColorSet(int index, const FPlayerColorSet *set); size_t PropagateMark(); void InitializeNativeDefaults(); @@ -168,6 +182,7 @@ public: FStateLabels *StateList; DmgFactors *DamageFactors; PainChanceList *PainChances; + FPlayerColorSetMap *ColorSets; FString Obituary; // Player was killed by this actor FString HitObituary; // Player was killed by this actor in melee fixed_t DeathHeight; // Height on normal death diff --git a/src/m_argv.cpp b/src/m_argv.cpp index 155374c60..5dbdc4d3d 100644 --- a/src/m_argv.cpp +++ b/src/m_argv.cpp @@ -38,161 +38,348 @@ IMPLEMENT_CLASS (DArgs) -DArgs::DArgs () +//=========================================================================== +// +// DArgs Default Constructor +// +//=========================================================================== + +DArgs::DArgs() { - m_ArgC = 0; - m_ArgV = NULL; } -DArgs::DArgs (int argc, char **argv) +//=========================================================================== +// +// DArgs Copy Constructor +// +//=========================================================================== + +DArgs::DArgs(const DArgs &other) { - CopyArgs (argc, argv); + Argv = other.Argv; } -DArgs::DArgs (const DArgs &other) +//=========================================================================== +// +// DArgs Argv Constructor +// +//=========================================================================== + +DArgs::DArgs(int argc, char **argv) { - CopyArgs (other.m_ArgC, other.m_ArgV); + SetArgs(argc, argv); +} + +//=========================================================================== +// +// DArgs String Argv Constructor +// +//=========================================================================== + +DArgs::DArgs(int argc, FString *argv) +{ + AppendArgs(argc, argv); } -DArgs::~DArgs () -{ - FlushArgs (); -} -DArgs &DArgs::operator= (const DArgs &other) +//=========================================================================== +// +// DArgs Copy Operator +// +//=========================================================================== + +DArgs &DArgs::operator=(const DArgs &other) { - FlushArgs (); - CopyArgs (other.m_ArgC, other.m_ArgV); + Argv = other.Argv; return *this; } -void DArgs::SetArgs (int argc, char **argv) -{ - FlushArgs (); - CopyArgs (argc, argv); -} - -void DArgs::CopyArgs (int argc, char **argv) -{ - int i; - - m_ArgC = argc; - m_ArgV = new char *[argc]; - for (i = 0; i < argc; i++) - m_ArgV[i] = copystring (argv[i]); -} - -void DArgs::FlushArgs () -{ - int i; - - for (i = 0; i < m_ArgC; i++) - delete[] m_ArgV[i]; - delete[] m_ArgV; - m_ArgC = 0; - m_ArgV = NULL; -} - +//=========================================================================== +// +// DArgs :: SetArgs +// +//=========================================================================== + +void DArgs::SetArgs(int argc, char **argv) +{ + Argv.Resize(argc); + for (int i = 0; i < argc; ++i) + { + Argv[i] = argv[i]; + } +} + +//=========================================================================== +// +// DArgs :: FlushArgs +// +//=========================================================================== + +void DArgs::FlushArgs() +{ + Argv.Clear(); +} + +//=========================================================================== +// +// DArgs :: CheckParm // -// CheckParm // Checks for the given parameter in the program's command line arguments. // Returns the argument number (1 to argc-1) or 0 if not present // -int DArgs::CheckParm (const char *check, int start) const -{ - for (int i = start; i < m_ArgC; ++i) - if (!stricmp (check, m_ArgV[i])) - return i; +//=========================================================================== +int DArgs::CheckParm(const char *check, int start) const +{ + for (unsigned i = start; i < Argv.Size(); ++i) + { + if (0 == stricmp(check, Argv[i])) + { + return i; + } + } return 0; } -char *DArgs::CheckValue (const char *check) const -{ - int i = CheckParm (check); +//=========================================================================== +// +// DArgs :: CheckParmList +// +// Returns the number of arguments after the parameter (if found) and also +// returns a pointer to the first argument. +// +//=========================================================================== - if (i > 0 && i < m_ArgC - 1) - return m_ArgV[i+1][0] != '+' && m_ArgV[i+1][0] != '-' ? m_ArgV[i+1] : NULL; - else - return NULL; -} - -char *DArgs::GetArg (int arg) const +int DArgs::CheckParmList(const char *check, FString **strings, int start) const { - if (arg >= 0 && arg < m_ArgC) - return m_ArgV[arg]; - else - return NULL; -} + unsigned int i, parmat = CheckParm(check, start); -char **DArgs::GetArgList (int arg) const -{ - if (arg >= 0 && arg < m_ArgC) - return &m_ArgV[arg]; - else - return NULL; -} - -int DArgs::NumArgs () const -{ - return m_ArgC; -} - -void DArgs::AppendArg (const char *arg) -{ - char **temp = new char *[m_ArgC + 1]; - if (m_ArgV) + if (parmat == 0) { - memcpy (temp, m_ArgV, sizeof(*m_ArgV) * m_ArgC); - delete[] m_ArgV; - } - temp[m_ArgC] = copystring (arg); - m_ArgV = temp; - m_ArgC++; -} - -DArgs *DArgs::GatherFiles (const char *param, const char *extension, bool acceptNoExt) const -{ - DArgs *out = new DArgs; - int i; - size_t extlen = strlen (extension); - - if (extlen > 0) - { - for (i = 1; i < m_ArgC && *m_ArgV[i] != '-' && *m_ArgV[i] != '+'; i++) + if (strings != NULL) { - size_t len = strlen (m_ArgV[i]); - if (len >= extlen && stricmp (m_ArgV[i] + len - extlen, extension) == 0) - out->AppendArg (m_ArgV[i]); - else if (acceptNoExt) - { - const char *src = m_ArgV[i] + len - 1; - - while (src != m_ArgV[i] && *src != '/' - #ifdef _WIN32 - && *src != '\\' - #endif - ) - { - if (*src == '.') - goto morefor; // it has an extension - src--; - } - out->AppendArg (m_ArgV[i]); -morefor: - ; - } + *strings = NULL; + } + return 0; + } + for (i = ++parmat; i < Argv.Size(); ++i) + { + if (Argv[i][0] == '-' || Argv[i][1] == '+') + { + break; } } - if (param != NULL) + if (strings != NULL) { - i = 1; - while (0 != (i = CheckParm (param, i))) + *strings = &Argv[parmat]; + } + return i - parmat; +} + +//=========================================================================== +// +// DArgs :: CheckValue +// +// Like CheckParm, but it also checks that the parameter has a value after +// it and returns that or NULL if not present. +// +//=========================================================================== + +const char *DArgs::CheckValue(const char *check) const +{ + int i = CheckParm(check); + + if (i > 0 && i < (int)Argv.Size() - 1) + { + i++; + return Argv[i][0] != '+' && Argv[i][0] != '-' ? Argv[i].GetChars() : NULL; + } + else + { + return NULL; + } +} + +//=========================================================================== +// +// DArgs :: TakeValue +// +// Like CheckValue, except it also removes the parameter and its argument +// (if present) from argv. +// +//=========================================================================== + +FString DArgs::TakeValue(const char *check) +{ + int i = CheckParm(check); + FString out; + + if (i > 0 && i < (int)Argv.Size()) + { + if (i < (int)Argv.Size() - 1 && Argv[i+1][0] != '+' && Argv[i+1][0] != '-') { - for (++i; i < m_ArgC && *m_ArgV[i] != '-' && *m_ArgV[i] != '+'; ++i) - out->AppendArg (m_ArgV[i]); + out = Argv[i+1]; + Argv.Delete(i, 2); // Delete the parm and its value. + } + else + { + Argv.Delete(i); // Just delete the parm, since it has no value. } } return out; } + +//=========================================================================== +// +// DArgs :: GetArg +// +// Gets the argument at a particular position. +// +//=========================================================================== + +const char *DArgs::GetArg(int arg) const +{ + return ((unsigned)arg < Argv.Size()) ? Argv[arg].GetChars() : NULL; + return Argv[arg]; +} + +//=========================================================================== +// +// DArgs :: GetArgList +// +// Returns a pointer to the FString at a particular position. +// +//=========================================================================== + +FString *DArgs::GetArgList(int arg) const +{ + return ((unsigned)arg < Argv.Size()) ? &Argv[arg] : NULL; +} + +//=========================================================================== +// +// DArgs :: NumArgs +// +//=========================================================================== + +int DArgs::NumArgs() const +{ + return (int)Argv.Size(); +} + +//=========================================================================== +// +// DArgs :: AppendArg +// +// Adds another argument to argv. Invalidates any previous results from +// GetArgList(). +// +//=========================================================================== + +void DArgs::AppendArg(FString arg) +{ + Argv.Push(arg); +} + +//=========================================================================== +// +// DArgs :: AppendArgs +// +// Adds an array of FStrings to argv. +// +//=========================================================================== + +void DArgs::AppendArgs(int argc, const FString *argv) +{ + if (argv != NULL && argc > 0) + { + Argv.Grow(argc); + for (int i = 0; i < argc; ++i) + { + Argv.Push(argv[i]); + } + } +} + +//=========================================================================== +// +// DArgs :: CollectFiles +// +// Takes all arguments after any instance of -param and any arguments before +// all switches that end in .extension and combines them into a single +// -switch block at the end of the arguments. If extension is NULL, then +// every parameter before the first switch is added after this -param. +// +//=========================================================================== + +void DArgs::CollectFiles(const char *param, const char *extension) +{ + TArray work; + DArgs *out = new DArgs; + unsigned int i; + size_t extlen = extension == NULL ? 0 : strlen(extension); + + // Step 1: Find suitable arguments before the first switch. + i = 1; + while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+') + { + bool useit; + + if (extlen > 0) + { // Argument's extension must match. + size_t len = Argv[i].Len(); + useit = (len >= extlen && stricmp(&Argv[i][len - extlen], extension) == 0); + } + else + { // Anything will do so long as it's before the first switch. + useit = true; + } + if (useit) + { + work.Push(Argv[i]); + Argv.Delete(i); + } + else + { + i++; + } + } + + // Step 2: Find each occurence of -param and add its arguments to work. + while ((i = CheckParm(param, i)) > 0) + { + Argv.Delete(i); + while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+') + { + work.Push(Argv[i]); + Argv.Delete(i); + } + } + + // Step 3: Add work back to Argv, as long as it's non-empty. + if (work.Size() > 0) + { + Argv.Push(param); + AppendArgs(work.Size(), &work[0]); + } +} + +//=========================================================================== +// +// DArgs :: GatherFiles +// +// Returns all the arguments after the first instance of -param. If you want +// to combine more than one or get switchless stuff included, you need to +// call CollectFiles first. +// +//=========================================================================== + +DArgs *DArgs::GatherFiles(const char *param) const +{ + FString *files; + int filecount; + + filecount = CheckParmList(param, &files); + return new DArgs(filecount, files); +} diff --git a/src/m_argv.h b/src/m_argv.h index b0d44076a..b2a432edb 100644 --- a/src/m_argv.h +++ b/src/m_argv.h @@ -35,40 +35,40 @@ #define __M_ARGV_H__ #include "dobject.h" +#include "zstring.h" // // MISC // class DArgs : public DObject { - DECLARE_CLASS (DArgs, DObject) + DECLARE_CLASS(DArgs, DObject) public: - DArgs (); - DArgs (const DArgs &args); - DArgs (int argc, char **argv); - ~DArgs (); + DArgs(); + DArgs(const DArgs &args); + DArgs(int argc, char **argv); + DArgs(int argc, FString *argv); - DArgs &operator= (const DArgs &other); + DArgs &operator=(const DArgs &other); - void AppendArg (const char *arg); - void SetArgs (int argc, char **argv); - DArgs *GatherFiles (const char *param, const char *extension, bool acceptNoExt) const; - void SetArg (int argnum, const char *arg); + void AppendArg(FString arg); + void AppendArgs(int argc, const FString *argv); + void SetArgs(int argc, char **argv); + void CollectFiles(const char *param, const char *extension); + DArgs *GatherFiles(const char *param) const; + void SetArg(int argnum, const char *arg); - // Returns the position of the given parameter - // in the arg list (0 if not found). - int CheckParm (const char *check, int start=1) const; - char *CheckValue (const char *check) const; - char *GetArg (int arg) const; - char **GetArgList (int arg) const; - int NumArgs () const; - void FlushArgs (); + int CheckParm(const char *check, int start=1) const; // Returns the position of the given parameter in the arg list (0 if not found). + int CheckParmList(const char *check, FString **strings, int start=1) const; + const char *CheckValue(const char *check) const; + const char *GetArg(int arg) const; + FString *GetArgList(int arg) const; + FString TakeValue(const char *check); + int NumArgs() const; + void FlushArgs(); private: - int m_ArgC; - char **m_ArgV; - - void CopyArgs (int argc, char **argv); + TArray Argv; }; extern DArgs *Args; diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index bb59780bd..8a04be64e 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -52,17 +52,17 @@ void cht_DoCheat (player_t *player, int cheat) { - static PClass *const *BeholdPowers[9] = + static const char * const BeholdPowers[9] = { - &RUNTIME_CLASS_CASTLESS(APowerInvulnerable), - &RUNTIME_CLASS_CASTLESS(APowerStrength), - &RUNTIME_CLASS_CASTLESS(APowerInvisibility), - &RUNTIME_CLASS_CASTLESS(APowerIronFeet), - NULL, // MapRevealer - &RUNTIME_CLASS_CASTLESS(APowerLightAmp), - &RUNTIME_CLASS_CASTLESS(APowerShadow), - &RUNTIME_CLASS_CASTLESS(APowerMask), - &RUNTIME_CLASS_CASTLESS(APowerTargeter) + "PowerInvulnerable", + "PowerStrength", + "PowerInvisibility", + "PowerIronFeet", + "MapRevealer", + "PowerLightAmp", + "PowerShadow", + "PowerMask", + "PowerTargeter", }; PClassActor *type; AInventory *item; @@ -245,12 +245,12 @@ void cht_DoCheat (player_t *player, int cheat) } else if (player->mo != NULL && player->health >= 0) { - item = player->mo->FindInventory(static_cast(*BeholdPowers[i])); + item = player->mo->FindInventory(PClass::FindActor(BeholdPowers[i])); if (item == NULL) { if (i != 0) { - player->mo->GiveInventoryType(static_cast(*BeholdPowers[i])); + cht_Give(player, BeholdPowers[i]); if (cheat == CHT_BEHOLDS) { P_GiveBody (player->mo, -100); @@ -259,7 +259,7 @@ void cht_DoCheat (player_t *player, int cheat) else { // Let's give the item here so that the power doesn't need colormap information. - player->mo->GiveInventoryType(PClass::FindActor("InvulnerabilitySphere")); + cht_Give(player, "InvulnerabilitySphere"); } } else @@ -316,7 +316,10 @@ void cht_DoCheat (player_t *player, int cheat) player->mo->special1 = 0; // required for the Hexen fighter's fist attack. // This gets set by AActor::Die as flag for the wimpy death and must be reset here. player->mo->SetState (player->mo->SpawnState); - player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); + if (!(player->mo->flags2 & MF2_DONTTRANSLATE)) + { + player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); + } player->mo->DamageType = NAME_None; // player->mo->GiveDefaultInventory(); if (player->ReadyWeapon != NULL) diff --git a/src/m_menu.cpp b/src/m_menu.cpp index 2045e064d..94befe8fe 100644 --- a/src/m_menu.cpp +++ b/src/m_menu.cpp @@ -118,7 +118,7 @@ protected: // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- -void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table); +void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayerSkin *skin, FRemapTable *table); // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- @@ -188,6 +188,7 @@ static void M_EditPlayerName (int choice); static void M_ChangePlayerTeam (int choice); static void M_PlayerNameChanged (FSaveGameNode *dummy); static void M_PlayerNameNotChanged (); +static void M_ChangeColorSet (int choice); static void M_SlidePlayerRed (int choice); static void M_SlidePlayerGreen (int choice); static void M_SlidePlayerBlue (int choice); @@ -246,17 +247,10 @@ static char savegamestring[SAVESTRINGSIZE]; static FString EndString; static short itemOn; // menu item skull is on -static short whichSkull; // which skull to draw static int MenuTime; static int InfoType; static int InfoTic; -static const char skullName[2][9] = {"M_SKULL1", "M_SKULL2"}; // graphic name of skulls -static const char cursName[8][8] = // graphic names of Strife menu selector -{ - "M_CURS1", "M_CURS2", "M_CURS3", "M_CURS4", "M_CURS5", "M_CURS6", "M_CURS7", "M_CURS8" -}; - static oldmenu_t *currentMenu; // current menudef static oldmenu_t *TopLevelMenu; // The main menu everything hangs off of @@ -269,6 +263,7 @@ static int PlayerSkin; static FState *PlayerState; static int PlayerTics; static int PlayerRotation; +static TArray PlayerColorSets; static FTexture *SavePic; static FBrokenLines *SaveComment; @@ -536,15 +531,24 @@ static oldmenuitem_t PlayerSetupMenu[] = { { 1,0,'n',NULL,M_EditPlayerName, CR_UNTRANSLATED}, { 2,0,'t',NULL,M_ChangePlayerTeam, CR_UNTRANSLATED}, + { 2,0,'c',NULL,M_ChangeColorSet, CR_UNTRANSLATED}, { 2,0,'r',NULL,M_SlidePlayerRed, CR_UNTRANSLATED}, { 2,0,'g',NULL,M_SlidePlayerGreen, CR_UNTRANSLATED}, { 2,0,'b',NULL,M_SlidePlayerBlue, CR_UNTRANSLATED}, - { 2,0,'c',NULL,M_ChangeClass, CR_UNTRANSLATED}, + { 2,0,'t',NULL,M_ChangeClass, CR_UNTRANSLATED}, { 2,0,'s',NULL,M_ChangeSkin, CR_UNTRANSLATED}, { 2,0,'e',NULL,M_ChangeGender, CR_UNTRANSLATED}, { 2,0,'a',NULL,M_ChangeAutoAim, CR_UNTRANSLATED} }; +enum +{ + // These must be changed if the menu definition is altered + PSM_RED = 3, + PSM_GREEN = 4, + PSM_BLUE = 5, +}; + static oldmenu_t PSetupDef = { countof(PlayerSetupMenu), @@ -2088,13 +2092,16 @@ void M_PlayerSetup (void) PlayerClass = &PlayerClasses[players[consoleplayer].CurrentPlayerClass]; } PlayerSkin = players[consoleplayer].userinfo.skin; - R_GetPlayerTranslation (players[consoleplayer].userinfo.color, &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); + R_GetPlayerTranslation (players[consoleplayer].userinfo.color, + P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset), + &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); PlayerState = GetDefaultByType (PlayerClass->Type)->SeeState; PlayerTics = PlayerState->GetTics(); if (FireTexture == NULL) { FireTexture = new FBackdropTexture; } + P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets); } static void M_PlayerSetupTicker (void) @@ -2112,6 +2119,7 @@ static void M_PlayerSetupTicker (void) item = (MenuTime>>2) % (ClassMenuDef.numitems-1); PlayerClass = &PlayerClasses[D_PlayerClassToInt (ClassMenuItems[item].name)]; + P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets); } else { @@ -2125,6 +2133,7 @@ static void M_PlayerSetupTicker (void) PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(PlayerClass - &PlayerClasses[0])); R_GetPlayerTranslation (players[consoleplayer].userinfo.color, + P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } @@ -2280,19 +2289,27 @@ static void M_PlayerSetupDrawer () DTA_Clean, true, TAG_DONE); } - // Draw player color sliders - //V_DrawTextCleanMove (CR_GREY, PSetupDef.x, PSetupDef.y + LINEHEIGHT, "Color"); + // Draw player color selection and sliders + FPlayerColorSet *colorset = P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset); + x = SmallFont->StringWidth("Color") + 8 + PSetupDef.x; + screen->DrawText(SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*2+yo, "Color", DTA_Clean, true, TAG_DONE); + screen->DrawText(SmallFont, value, x, PSetupDef.y + LINEHEIGHT*2+yo, + colorset != NULL ? colorset->Name.GetChars() : "Custom", DTA_Clean, true, TAG_DONE); - screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*2+yo, "Red", DTA_Clean, true, TAG_DONE); - screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*3+yo, "Green", DTA_Clean, true, TAG_DONE); - screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT*4+yo, "Blue", DTA_Clean, true, TAG_DONE); + // Only show the sliders for a custom color set. + if (colorset == NULL) + { + screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + int(LINEHEIGHT*2.875)+yo, "Red", DTA_Clean, true, TAG_DONE); + screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + int(LINEHEIGHT*3.5)+yo, "Green", DTA_Clean, true, TAG_DONE); + screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + int(LINEHEIGHT*4.125)+yo, "Blue", DTA_Clean, true, TAG_DONE); - x = SmallFont->StringWidth ("Green") + 8 + PSetupDef.x; - color = players[consoleplayer].userinfo.color; + x = SmallFont->StringWidth ("Green") + 8 + PSetupDef.x; + color = players[consoleplayer].userinfo.color; - M_DrawPlayerSlider (x, PSetupDef.y + LINEHEIGHT*2+yo, RPART(color)); - M_DrawPlayerSlider (x, PSetupDef.y + LINEHEIGHT*3+yo, GPART(color)); - M_DrawPlayerSlider (x, PSetupDef.y + LINEHEIGHT*4+yo, BPART(color)); + M_DrawPlayerSlider (x, PSetupDef.y + int(LINEHEIGHT*2.875)+yo, RPART(color)); + M_DrawPlayerSlider (x, PSetupDef.y + int(LINEHEIGHT*3.5)+yo, GPART(color)); + M_DrawPlayerSlider (x, PSetupDef.y + int(LINEHEIGHT*4.125)+yo, BPART(color)); + } // [GRB] Draw class setting int pclass = players[consoleplayer].userinfo.PlayerClass; @@ -2586,7 +2603,9 @@ static void M_ChangeSkin (int choice) PlayerSkin = (PlayerSkin < (int)numskins - 1) ? PlayerSkin + 1 : 0; } while (!PlayerClass->CheckSkin (PlayerSkin)); - R_GetPlayerTranslation (players[consoleplayer].userinfo.color, &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); + R_GetPlayerTranslation (players[consoleplayer].userinfo.color, + P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset), + &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); cvar_set ("skin", skins[PlayerSkin].name); } @@ -2707,13 +2726,55 @@ static void M_ChangePlayerTeam (int choice) } } +static void M_ChangeColorSet (int choice) +{ + int curpos = (int)PlayerColorSets.Size(); + int mycolorset = players[consoleplayer].userinfo.colorset; + while (--curpos >= 0) + { + if (PlayerColorSets[curpos] == mycolorset) + break; + } + if (choice == 0) + { + curpos--; + } + else + { + curpos++; + } + if (curpos < -1) + { + curpos = (int)PlayerColorSets.Size() - 1; + } + else if (curpos >= (int)PlayerColorSets.Size()) + { + curpos = -1; + } + mycolorset = (curpos >= 0) ? PlayerColorSets[curpos] : -1; + + // disable the sliders if a valid colorset is selected + PlayerSetupMenu[PSM_RED].status = + PlayerSetupMenu[PSM_GREEN].status = + PlayerSetupMenu[PSM_BLUE].status = (mycolorset == -1? 2:-1); + + char command[24]; + mysnprintf(command, countof(command), "colorset %d", mycolorset); + C_DoCommand(command); + R_GetPlayerTranslation(players[consoleplayer].userinfo.color, + P_GetPlayerColorSet(PlayerClass->Type->TypeName, mycolorset), + &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); +} + static void SendNewColor (int red, int green, int blue) { char command[24]; mysnprintf (command, countof(command), "color \"%02x %02x %02x\"", red, green, blue); C_DoCommand (command); - R_GetPlayerTranslation (MAKERGB (red, green, blue), &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); + R_GetPlayerTranslation(MAKERGB (red, green, blue), + P_GetPlayerColorSet(PlayerClass->Type->TypeName, players[consoleplayer].userinfo.colorset), + &skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]); } static void M_SlidePlayerRed (int choice) @@ -3645,27 +3706,50 @@ void M_Drawer () // [RH] Use options menu cursor for the player setup menu. if (skullAnimCounter < 6) { + double item; + // The green slider is halfway between lines, and the red and + // blue ones are offset slightly to make room for it. + if (itemOn < 3) + { + item = itemOn; + } + else if (itemOn > 5) + { + item = itemOn - 1; + } + else if (itemOn == 3) + { + item = 2.875; + } + else if (itemOn == 4) + { + item = 3.5; + } + else + { + item = 4.125; + } screen->DrawText (ConFont, CR_RED, x - 16, - currentMenu->y + itemOn*PLAYERSETUP_LINEHEIGHT + + currentMenu->y + int(item*PLAYERSETUP_LINEHEIGHT) + (!(gameinfo.gametype & (GAME_DoomStrifeChex)) ? 6 : -1), "\xd", DTA_Clean, true, TAG_DONE); } } else if (gameinfo.gametype & GAME_DoomChex) { - screen->DrawTexture (TexMan[skullName[whichSkull]], + screen->DrawTexture (TexMan("M_SKULL1"), x + SKULLXOFF, currentMenu->y - 5 + itemOn*LINEHEIGHT, DTA_Clean, true, TAG_DONE); } else if (gameinfo.gametype == GAME_Strife) { - screen->DrawTexture (TexMan[cursName[(MenuTime >> 2) & 7]], + screen->DrawTexture (TexMan("M_CURS1"), x - 28, currentMenu->y - 5 + itemOn*LINEHEIGHT, DTA_Clean, true, TAG_DONE); } else { - screen->DrawTexture (TexMan[MenuTime & 16 ? "M_SLCTR1" : "M_SLCTR2"], + screen->DrawTexture (TexMan("M_SLCTR1"), x + SELECTOR_XOFFSET, currentMenu->y + itemOn*LINEHEIGHT + SELECTOR_YOFFSET, DTA_Clean, true, TAG_DONE); @@ -3859,7 +3943,6 @@ void M_Ticker (void) MenuTime++; if (--skullAnimCounter <= 0) { - whichSkull ^= 1; skullAnimCounter = 8; } if (currentMenu == &PSetupDef || currentMenu == &ClassMenuDef) @@ -3913,7 +3996,6 @@ void M_Init (void) menuactive = MENU_Off; InfoType = 0; itemOn = currentMenu->lastOn; - whichSkull = 0; skullAnimCounter = 10; drawSkull = true; messageToPrint = 0; @@ -4034,4 +4116,5 @@ static void PickPlayerClass () } PlayerClass = &PlayerClasses[pclass]; + P_EnumPlayerColorSets(PlayerClass->Type->TypeName, &PlayerColorSets); } diff --git a/src/m_misc.cpp b/src/m_misc.cpp index e973a4ca9..c828a965a 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -159,7 +159,6 @@ void M_FindResponseFile (void) char **argv; char *file; int argc; - int argcinresp; FILE *handle; int size; long argsize; @@ -183,23 +182,32 @@ void M_FindResponseFile (void) file[size] = 0; fclose (handle); - argsize = ParseCommandLine (file, &argcinresp, NULL); - argc = argcinresp + Args->NumArgs() - 1; + argsize = ParseCommandLine (file, &argc, NULL); + argc = Args->NumArgs() - 1; if (argc != 0) { argv = (char **)M_Malloc (argc*sizeof(char *) + argsize); - argv[i] = (char *)argv + argc*sizeof(char *); - ParseCommandLine (file, NULL, argv+i); + argv[0] = (char *)argv + argc*sizeof(char *); + ParseCommandLine (file, NULL, argv); + // Create a new argument vector + DArgs *newargs = new DArgs; + + // Copy parameters before response file. for (index = 0; index < i; ++index) - argv[index] = Args->GetArg (index); + newargs->AppendArg(Args->GetArg(index)); - for (index = i + 1, i += argcinresp; index < Args->NumArgs (); ++index) - argv[i++] = Args->GetArg (index); + // Copy parameters from response file. + for (index = 0; index < argc; ++i) + newargs->AppendArg(argv[index]); - Args->Destroy(); - Args = new DArgs(i, argv); + // Copy parameters after response file. + for (index = i + 1, i = newargs->NumArgs(); index < Args->NumArgs(); ++index) + newargs->AppendArg(Args->GetArg(index)); + + // Use the new argument vector as the global Args object. + Args = newargs; } delete[] file; diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index 90aaff492..83393f7c3 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -789,7 +789,7 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou newvert.y += fixed_t(frac * double(Vertices[seg->v2].y - newvert.y)); vertnum = VertexMap->SelectVertexClose (newvert); - if (vertnum == seg->v1 || vertnum == seg->v2) + if (vertnum == (unsigned int)seg->v1 || vertnum == (unsigned int)seg->v2) { Printf("SelectVertexClose selected endpoint of seg %u\n", set); } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9d774493e..97680d6e2 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3279,8 +3279,8 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_CheckActorClass: { - AActor *a = args[0] == 0 ? (AActor *)activator : SingleActorFromTID(args[0], NULL); - return a->GetClass()->TypeName == FName(FBehavior::StaticLookupString(args[1])); + AActor *a = args[0] == 0 ? (AActor *)activator : SingleActorFromTID(args[0], NULL); + return a == NULL ? false : a->GetClass()->TypeName == FName(FBehavior::StaticLookupString(args[1])); } case ACSF_SoundSequenceOnActor: @@ -5360,13 +5360,13 @@ int DLevelScript::RunScript () break; case PCD_CLEARACTORINVENTORY: - if (STACK(3) == 0) + if (STACK(1) == 0) { ClearInventory(NULL); } else { - FActorIterator it(STACK(3)); + FActorIterator it(STACK(1)); AActor *actor; for (actor = it.Next(); actor != NULL; actor = it.Next()) { diff --git a/src/p_buildmap.cpp b/src/p_buildmap.cpp index 094fa8f41..de7f1dfc1 100644 --- a/src/p_buildmap.cpp +++ b/src/p_buildmap.cpp @@ -109,6 +109,21 @@ struct spritetype SWORD lotag, hitag, extra; }; +// I used to have all the Xobjects mapped out. Not anymore. +// (Thanks for the great firmware, Seagate!) +struct Xsprite +{ + BYTE NotReallyPadding[16]; + WORD Data1; + WORD Data2; + WORD Data3; + WORD ThisIsntPaddingEither; + DWORD NorThis:2; + DWORD Data4:16; + DWORD WhatIsThisIDontEven:14; + BYTE ThisNeedsToBe56Bytes[28]; +}; + struct SlopeWork { walltype *wal; @@ -128,7 +143,7 @@ void P_AdjustLine (line_t *line); static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **sprites, int *numsprites); static void LoadSectors (sectortype *bsectors); static void LoadWalls (walltype *walls, int numwalls, sectortype *bsectors); -static int LoadSprites (spritetype *sprites, int numsprites, sectortype *bsectors, FMapThing *mapthings); +static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, sectortype *bsectors, FMapThing *mapthings); static vertex_t *FindVertex (fixed_t x, fixed_t y); static void CreateStartSpot (fixed_t *pos, FMapThing *start); static void CalcPlane (SlopeWork &slope, secplane_t &plane); @@ -145,8 +160,10 @@ static void Decrypt (void *to, const void *from, int len, int key); bool P_IsBuildMap(MapData *map) { DWORD len = map->Size(ML_LABEL); - if (len < 4) return false; - + if (len < 4) + { + return false; + } BYTE *data = new BYTE[len]; map->Seek(ML_LABEL); @@ -215,7 +232,7 @@ bool P_LoadBuildMap (BYTE *data, size_t len, FMapThing **sprites, int *numspr) *sprites = new FMapThing[numsprites + 1]; CreateStartSpot ((fixed_t *)(data + 4), *sprites); *numspr = 1 + LoadSprites ((spritetype *)(data + 26 + numsectors*sizeof(sectortype) + numwalls*sizeof(walltype)), - numsprites, (sectortype *)(data + 22), *sprites + 1); + NULL, numsprites, (sectortype *)(data + 22), *sprites + 1); return true; } @@ -251,11 +268,11 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int * { memcpy (infoBlock, data + 6, 37); } - numRevisions = *(DWORD *)(infoBlock + 27); - numsectors = *(WORD *)(infoBlock + 31); - numWalls = *(WORD *)(infoBlock + 33); - numsprites = *(WORD *)(infoBlock + 35); - skyLen = 2 << *(WORD *)(infoBlock + 16); + numRevisions = LittleLong(*(DWORD *)(infoBlock + 27)); + numsectors = LittleShort(*(WORD *)(infoBlock + 31)); + numWalls = LittleShort(*(WORD *)(infoBlock + 33)); + numsprites = LittleShort(*(WORD *)(infoBlock + 35)); + skyLen = 2 << LittleShort(*(WORD *)(infoBlock + 16)); if (mapver == 7) { @@ -275,6 +292,7 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int * sectortype *bsec = new sectortype[numsectors]; walltype *bwal = new walltype[numWalls]; spritetype *bspr = new spritetype[numsprites]; + Xsprite *xspr = new Xsprite[numsprites]; // Read sectors k = numRevisions * sizeof(sectortype); @@ -327,9 +345,15 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int * memcpy (&bspr[i], data, sizeof(spritetype)); } data += sizeof(spritetype); - if (bspr[i].extra > 0) // skip Xsprite + if (bspr[i].extra > 0) // copy Xsprite { - data += 56; + assert(sizeof(Xsprite) == 56); + memcpy(&xspr[i], data, sizeof(Xsprite)); + data += sizeof(Xsprite); + } + else + { + memset(&xspr[i], 0, sizeof(Xsprite)); } } @@ -339,11 +363,12 @@ static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int * LoadWalls (bwal, numWalls, bsec); *mapthings = new FMapThing[numsprites + 1]; CreateStartSpot ((fixed_t *)infoBlock, *mapthings); - *numspr = 1 + LoadSprites (bspr, numsprites, bsec, *mapthings + 1); + *numspr = 1 + LoadSprites (bspr, xspr, numsprites, bsec, *mapthings + 1); delete[] bsec; delete[] bwal; delete[] bspr; + delete[] xspr; return true; } @@ -363,6 +388,8 @@ static void LoadSectors (sectortype *bsec) sec = sectors = new sector_t[numsectors]; memset (sectors, 0, sizeof(sector_t)*numsectors); + sectors[0].e = new extsector_t[numsectors]; + for (int i = 0; i < numsectors; ++i, ++bsec, ++sec) { bsec->wallptr = WORD(bsec->wallptr); @@ -370,6 +397,7 @@ static void LoadSectors (sectortype *bsec) bsec->ceilingstat = WORD(bsec->ceilingstat); bsec->floorstat = WORD(bsec->floorstat); + sec->e = §ors[0].e[i]; sec->SetPlaneTexZ(sector_t::floor, -(LittleLong(bsec->floorz) << 8)); sec->floorplane.d = -sec->GetPlaneTexZ(sector_t::floor); sec->floorplane.c = FRACUNIT; @@ -512,6 +540,8 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec) } sides[i].TexelLength = walls[i].xrepeat * 8; + sides[i].SetTextureYScale(walls[i].yrepeat << (FRACBITS - 3)); + sides[i].SetTextureXScale(FRACUNIT); sides[i].SetLight(SHADE2LIGHT(walls[i].shade)); sides[i].Flags = WALLF_ABSLIGHTING; sides[i].RightSide = walls[i].point2; @@ -631,14 +661,17 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec) R_AlignFlat (linenum, sidenum == bsec->wallptr, 0); } } - for(i = 0; i < numsides; i++) + for (i = 0; i < numlines; i++) { - sides[i].linedef = &lines[intptr_t(sides[i].linedef)]; + intptr_t front = intptr_t(lines[i].sidedef[0]); + intptr_t back = intptr_t(lines[i].sidedef[1]); + lines[i].sidedef[0] = front >= 0 ? &sides[front] : NULL; + lines[i].sidedef[1] = back >= 0 ? &sides[back] : NULL; } - for(i = 0; i < numlines; i++) + for (i = 0; i < numsides; i++) { - lines[i].sidedef[0] = &sides[intptr_t(lines[i].sidedef[0])]; - lines[i].sidedef[1] = &sides[intptr_t(lines[i].sidedef[1])]; + assert(sides[i].sector != NULL); + sides[i].linedef = &lines[intptr_t(sides[i].linedef)]; } } @@ -648,32 +681,46 @@ static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec) // //========================================================================== -static int LoadSprites (spritetype *sprites, int numsprites, sectortype *bsectors, - FMapThing *mapthings) +static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, + sectortype *bsectors, FMapThing *mapthings) { int count = 0; for (int i = 0; i < numsprites; ++i) { - if (sprites[i].cstat & (16|32|32768)) continue; - if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue; - mapthings[count].thingid = 0; mapthings[count].x = (sprites[i].x << 12); mapthings[count].y = -(sprites[i].y << 12); mapthings[count].z = (bsectors[sprites[i].sectnum].floorz - sprites[i].z) << 8; mapthings[count].angle = (((2048-sprites[i].ang) & 2047) * 360) >> 11; - mapthings[count].type = 9988; mapthings[count].ClassFilter = 0xffff; mapthings[count].SkillFilter = 0xffff; mapthings[count].flags = MTF_SINGLE|MTF_COOPERATIVE|MTF_DEATHMATCH; mapthings[count].special = 0; - mapthings[count].args[0] = sprites[i].picnum & 255; - mapthings[count].args[1] = sprites[i].picnum >> 8; - mapthings[count].args[2] = sprites[i].xrepeat; - mapthings[count].args[3] = sprites[i].yrepeat; - mapthings[count].args[4] = (sprites[i].cstat & 14) | ((sprites[i].cstat >> 9) & 1); + if (xsprites != NULL && sprites[i].lotag == 710) + { // Blood ambient sound + mapthings[count].args[0] = xsprites[i].Data3; + // I am totally guessing abount the volume level. 50 seems to be a pretty + // typical value for Blood's standard maps, so I assume it's 100-based. + mapthings[count].args[1] = xsprites[i].Data4; + mapthings[count].args[2] = xsprites[i].Data1; + mapthings[count].args[3] = xsprites[i].Data2; + mapthings[count].args[4] = 0; + mapthings[count].type = 14065; + } + else + { + if (sprites[i].cstat & (16|32|32768)) continue; + if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue; + + mapthings[count].type = 9988; + mapthings[count].args[0] = sprites[i].picnum & 255; + mapthings[count].args[1] = sprites[i].picnum >> 8; + mapthings[count].args[2] = sprites[i].xrepeat; + mapthings[count].args[3] = sprites[i].yrepeat; + mapthings[count].args[4] = (sprites[i].cstat & 14) | ((sprites[i].cstat >> 9) & 1); + } count++; } return count; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index d71aff711..0e64486a5 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -198,16 +198,16 @@ void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soun // //---------------------------------------------------------------------------- -void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash) +void P_NoiseAlert (AActor *target, AActor *emitter, bool splash) { - if (emmiter == NULL) + if (emitter == NULL) return; if (target != NULL && target->player && (target->player->cheats & CF_NOTARGET)) return; validcount++; - P_RecursiveSound (emmiter->Sector, target, splash, 0); + P_RecursiveSound (emitter->Sector, target, splash, 0); } @@ -308,7 +308,7 @@ bool P_CheckMissileRange (AActor *actor) { fixed_t dist; - if (!P_CheckSight (actor, actor->target, 4)) + if (!P_CheckSight (actor, actor->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES)) return false; if (actor->flags & MF_JUSTHIT) @@ -1136,7 +1136,7 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams } // P_CheckSight is by far the most expensive operation in here so let's do it last. - return P_CheckSight(lookee, other, 2); + return P_CheckSight(lookee, other, SF_SEEPASTBLOCKEVERYTHING); } //--------------------------------------------------------------------------- @@ -1154,7 +1154,7 @@ bool P_LookForMonsters (AActor *actor) AActor *mo; TThinkerIterator iterator; - if (!P_CheckSight (players[0].mo, actor, 2)) + if (!P_CheckSight (players[0].mo, actor, SF_SEEPASTBLOCKEVERYTHING)) { // Player can't see monster return false; } @@ -1178,11 +1178,11 @@ bool P_LookForMonsters (AActor *actor) { // Stop searching return false; } - if (mo->IsKindOf (actor->GetClass()) || actor->IsKindOf (mo->GetClass())) + if (mo->GetSpecies() == actor->GetSpecies()) { // [RH] Don't go after same species continue; } - if (!P_CheckSight (actor, mo, 2)) + if (!P_CheckSight (actor, mo, SF_SEEPASTBLOCKEVERYTHING)) { // Out of sight continue; } @@ -1765,7 +1765,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look) if (self->flags & MF_AMBUSH) { - if (P_CheckSight (self, self->target, 2)) + if (P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING)) goto seeyou; } else @@ -1933,7 +1933,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx) if (self->flags & MF_AMBUSH) { dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y); - if (P_CheckSight (self, self->target, 2) && + if (P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING) && (!minseedist || dist > minseedist) && (!maxseedist || dist < maxseedist)) { @@ -2070,7 +2070,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2) { if (self->flags & MF_AMBUSH) { - if (!P_CheckSight (self, targ, 2)) + if (!P_CheckSight (self, targ, SF_SEEPASTBLOCKEVERYTHING)) goto nosee; } self->target = targ; @@ -2745,7 +2745,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) self->target->x, self->target->y); - self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, false, false, false, self->target); + self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, self->target); if (linetarget == NULL) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 3ff9b02bd..45c706a8c 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1274,7 +1274,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage painchance = target->PainChance; if (pc != NULL) { - BYTE * ppc = pc->CheckKey(mod); + int *ppc = pc->CheckKey(mod); if (ppc != NULL) { painchance = *ppc; diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 82fa2efa7..060cd7f4a 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -189,8 +189,11 @@ FUNC(LS_Door_CloseWaitOpen) } FUNC(LS_Door_Animated) -// Door_Animated (tag, speed, delay) +// Door_Animated (tag, speed, delay, lock) { + if (arg3 != 0 && !P_CheckKeys (it, arg3, arg0 != 0)) + return false; + return EV_SlidingDoor (ln, it, arg0, arg1, arg2); } diff --git a/src/p_local.h b/src/p_local.h index 4139f314e..80378fe95 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -394,6 +394,15 @@ void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); bool P_BounceWall (AActor *mo); bool P_BounceActor (AActor *mo, AActor * BlockingMobj); bool P_CheckSight (const AActor* t1, const AActor* t2, int flags=0); + +enum ESightFlags +{ + SF_IGNOREVISIBILITY=1, + SF_SEEPASTSHOOTABLELINES=2, + SF_SEEPASTBLOCKEVERYTHING=4, + SF_IGNOREWATERBOUNDARY=8 +}; + void P_ResetSightCounters (bool full); bool P_TalkFacing (AActor *player); void P_UseLines (player_t* player); @@ -402,7 +411,16 @@ void P_FindFloorCeiling (AActor *actor, bool onlymidtex = false); bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset); -fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, bool forcenosmart=false, bool check3d = false, bool checknonshootable = false, AActor *target=NULL); +fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL); + +enum +{ + ALF_FORCENOSMART = 1, + ALF_CHECK3D = 2, + ALF_CHECKNONSHOOTABLE = 4, + ALF_CHECKCONVERSATION = 8, +}; + AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, PClassActor *pufftype, bool ismelee = false); AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, bool ismelee = false); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); diff --git a/src/p_map.cpp b/src/p_map.cpp index 02eb8aa3f..5df43255b 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -2807,8 +2807,7 @@ struct aim_t AActor * linetarget; AActor * thing_friend, * thing_other; angle_t pitch_friend, pitch_other; - bool notsmart; - bool check3d; + int flags; #ifdef _3DFLOORS sector_t * lastsector; secplane_t * lastfloorplane; @@ -2819,7 +2818,7 @@ struct aim_t bool AimTraverse3DFloors(const divline_t &trace, intercept_t * in); #endif - void AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, bool checknonshootable = false, AActor *target=NULL); + void AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, AActor *target=NULL); }; @@ -2936,7 +2935,7 @@ bool aim_t::AimTraverse3DFloors(const divline_t &trace, intercept_t * in) // //============================================================================ -void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, bool checknonshootable, AActor *target) +void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t endy, AActor *target) { FPathTraverse it(startx, starty, endx, endy, PT_ADDLINES|PT_ADDTHINGS); intercept_t *in; @@ -2994,18 +2993,23 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e if (target != NULL && th != target) continue; // only care about target, and you're not it - if (!checknonshootable) // For info CCMD, ignore stuff about GHOST and SHOOTABLE flags + // If we want to start a conversation anything that has one should be + // found, regardless of other settings. + if (!(flags & ALF_CHECKCONVERSATION) || th->Conversation == NULL) { - if (!(th->flags&MF_SHOOTABLE)) - continue; // corpse or something - - // check for physical attacks on a ghost - if ((th->flags3 & MF3_GHOST) && - shootthing->player && // [RH] Be sure shootthing is a player - shootthing->player->ReadyWeapon && - (shootthing->player->ReadyWeapon->flags2 & MF2_THRUGHOST)) + if (!(flags & ALF_CHECKNONSHOOTABLE)) // For info CCMD, ignore stuff about GHOST and SHOOTABLE flags { - continue; + if (!(th->flags&MF_SHOOTABLE)) + continue; // corpse or something + + // check for physical attacks on a ghost + if ((th->flags3 & MF3_GHOST) && + shootthing->player && // [RH] Be sure shootthing is a player + shootthing->player->ReadyWeapon && + (shootthing->player->ReadyWeapon->flags2 & MF2_THRUGHOST)) + { + continue; + } } } dist = FixedMul (attackrange, in->frac); @@ -3053,7 +3057,7 @@ void aim_t::AimTraverse (fixed_t startx, fixed_t starty, fixed_t endx, fixed_t e if (crossedffloors) { // if 3D floors were in the way do an extra visibility check for safety - if (!P_CheckSight(shootthing, th, 1)) + if (!P_CheckSight(shootthing, th, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) { // the thing can't be seen so we can safely exclude its range from our aiming field if (thingtoppitch>= ANGLETOFINESHIFT; + aim.flags = flags; aim.shootthing = t1; - aim.check3d = check3d; x2 = t1->x + (distance>>FRACBITS)*finecosine[angle]; y2 = t1->y + (distance>>FRACBITS)*finesine[angle]; @@ -3194,7 +3194,6 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p } aim.toppitch = t1->pitch - vrange; aim.bottompitch = t1->pitch + vrange; - aim.notsmart = forcenosmart; aim.attackrange = distance; aim.linetarget = NULL; @@ -3223,7 +3222,7 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p } #endif - aim.AimTraverse (t1->x, t1->y, x2, y2, checknonshootable, target); + aim.AimTraverse (t1->x, t1->y, x2, y2, target); if (!aim.linetarget) { @@ -3239,7 +3238,9 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **p } } if (pLineTarget) + { *pLineTarget = aim.linetarget; + } return aim.linetarget ? aim.aimpitch : t1->pitch; } @@ -3588,7 +3589,7 @@ void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *actor, a { if (bleedtrace.HitType == TRACE_HitWall) { - PalEntry bloodcolor = actor->GetClass()->BloodColor; + PalEntry bloodcolor = actor->GetBloodColor(); if (bloodcolor != 0) { bloodcolor.r>>=1; // the full color is too bright for blood decals @@ -3921,13 +3922,13 @@ bool P_TalkFacing(AActor *player) { AActor *linetarget; - P_AimLineAttack(player, player->angle, TALKRANGE, &linetarget, ANGLE_1*35, true); + P_AimLineAttack(player, player->angle, TALKRANGE, &linetarget, ANGLE_1*35, ALF_FORCENOSMART|ALF_CHECKCONVERSATION); if (linetarget == NULL) { - P_AimLineAttack(player, player->angle + (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1*35, true); + P_AimLineAttack(player, player->angle + (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1*35, ALF_FORCENOSMART|ALF_CHECKCONVERSATION); if (linetarget == NULL) { - P_AimLineAttack(player, player->angle - (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1*35, true); + P_AimLineAttack(player, player->angle - (ANGLE_90 >> 4), TALKRANGE, &linetarget, ANGLE_1*35, ALF_FORCENOSMART|ALF_CHECKCONVERSATION); if (linetarget == NULL) { return false; @@ -4327,7 +4328,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b } points *= thing->GetClass()->RDFactor/(float)FRACUNIT; - if (points > 0.f && P_CheckSight (thing, bombspot, 1)) + if (points > 0.f && P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) { // OK to damage; target is in direct path float velz; float thrust; @@ -4385,7 +4386,7 @@ void P_RadiusAttack (AActor *bombspot, AActor *bombsource, int bombdamage, int b if (dist >= bombdistance) continue; // out of range - if (P_CheckSight (thing, bombspot, 1)) + if (P_CheckSight (thing, bombspot, SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY)) { // OK to damage; target is in direct path dist = clamp(dist - fulldamagedistance, 0, dist); int damage = Scale (bombdamage, bombdistance-dist, bombdistance); @@ -4595,34 +4596,40 @@ void P_DoCrunch (AActor *thing, FChangePosition *cpos) P_DamageMobj (thing, NULL, NULL, cpos->crushchange, NAME_Crush); // spray blood in a random direction - if ((!(thing->flags&MF_NOBLOOD)) && - (!(thing->flags2&(MF2_INVULNERABLE|MF2_DORMANT)))) + if (!(thing->flags2&(MF2_INVULNERABLE|MF2_DORMANT))) { - PalEntry bloodcolor = thing->GetClass()->BloodColor; - PClassActor *bloodcls = PClass::FindActor(thing->GetClass()->BloodType); - - P_TraceBleed (cpos->crushchange, thing); - if (cl_bloodtype <= 1 && bloodcls != NULL) + if (!(thing->flags&MF_NOBLOOD)) { - AActor *mo; - - mo = Spawn (bloodcls, thing->x, thing->y, - thing->z + thing->height/2, ALLOW_REPLACE); - - mo->velx = pr_crunch.Random2 () << 12; - mo->vely = pr_crunch.Random2 () << 12; - if (bloodcolor != 0 && !(mo->flags2 & MF2_DONTTRANSLATE)) + PalEntry bloodcolor = thing->GetBloodColor(); + PClassActor *bloodcls = thing->GetBloodType(); + + P_TraceBleed (cpos->crushchange, thing); + if (cl_bloodtype <= 1 && bloodcls != NULL) { - mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + AActor *mo; + + mo = Spawn (bloodcls, thing->x, thing->y, + thing->z + thing->height/2, ALLOW_REPLACE); + + mo->velx = pr_crunch.Random2 () << 12; + mo->vely = pr_crunch.Random2 () << 12; + if (bloodcolor != 0 && !(mo->flags2 & MF2_DONTTRANSLATE)) + { + mo->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); + } + } + if (cl_bloodtype >= 1) + { + angle_t an; + + an = (M_Random () - 128) << 24; + P_DrawSplash2 (32, thing->x, thing->y, + thing->z + thing->height/2, an, 2, bloodcolor); } } - if (cl_bloodtype >= 1) + if (thing->CrushPainSound != 0 && !S_GetSoundPlayingInfo(thing, thing->CrushPainSound)) { - angle_t an; - - an = (M_Random () - 128) << 24; - P_DrawSplash2 (32, thing->x, thing->y, - thing->z + thing->height/2, an, 2, bloodcolor); + S_Sound(thing, CHAN_VOICE, thing->CrushPainSound, 1.f, ATTN_NORM); } } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2078f9e6c..c339b3c9a 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -270,8 +270,12 @@ void AActor::Serialize (FArchive &arc) << ActiveSound << UseSound << BounceSound - << WallBounceSound - << Speed + << WallBounceSound; + if (SaveVersion >= 2234) + { + arc << CrushPainSound; + } + arc << Speed << FloatSpeed << Mass << PainChance @@ -1069,7 +1073,7 @@ bool AActor::Grind(bool items) if (isgeneric) // Not a custom crush state, so colorize it appropriately. { S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); - PalEntry bloodcolor = GetClass()->BloodColor; + PalEntry bloodcolor = GetBloodColor(); if (bloodcolor!=0) Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); } return false; @@ -1113,7 +1117,7 @@ bool AActor::Grind(bool items) } S_Sound (this, CHAN_BODY, "misc/fallingsplat", 1, ATTN_IDLE); - PalEntry bloodcolor = GetClass()->BloodColor; + PalEntry bloodcolor = GetBloodColor(); if (bloodcolor!=0) gib->Translation = TRANSLATION(TRANSLATION_Blood, bloodcolor.a); } if (flags & MF_ICECORPSE) @@ -2129,8 +2133,9 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) { fixed_t dist; fixed_t delta; - fixed_t oldz = mo->z; - + fixed_t oldz = mo->z; + fixed_t grav = mo->GetGravity(); + // // check for smooth step up // @@ -2155,8 +2160,6 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) if (!mo->waterlevel || mo->flags & MF_CORPSE || (mo->player && !(mo->player->cmd.ucmd.forwardmove | mo->player->cmd.ucmd.sidemove))) { - fixed_t grav = mo->GetGravity(); - // [RH] Double gravity only if running off a ledge. Coming down from // an upward thrust (e.g. a jump) should not double it. if (mo->velz == 0 && oldfloorz > mo->floorz && mo->z == oldfloorz) @@ -2230,12 +2233,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) // teleported the actor so it is no longer below the floor. if (mo->z <= mo->floorz) { - // old code for boss cube disabled - //if ((mo->flags & MF_MISSILE) && (!(gameinfo.gametype & GAME_DoomChex) || !(mo->flags & MF_NOCLIP))) - - // We can't remove this completely because it was abused by some DECORATE definitions - // (e.g. the monster pack's Afrit) - if ((mo->flags & MF_MISSILE) && ((mo->flags & MF_NOGRAVITY) || !(mo->flags & MF_NOCLIP))) + if ((mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP)) { mo->z = mo->floorz; if (mo->BounceFlags & BOUNCE_Floors) @@ -2297,7 +2295,10 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) mo->HitFloor (); if (mo->player) { - mo->player->jumpTics = 7; // delay any jumping for a short while + if (mo->player->jumpTics != 0 && mo->velz < -grav*4) + { // delay any jumping for a short while + mo->player->jumpTics = 7; + } if (mo->velz < minvel && !(mo->flags & MF_NOGRAVITY)) { // Squat down. @@ -2346,8 +2347,7 @@ void P_ZMovement (AActor *mo, fixed_t oldfloorz) } if (mo->velz > 0) mo->velz = 0; - if (mo->flags & MF_MISSILE) - //&& (!(gameinfo.gametype & GAME_DoomChex) || !(mo->flags & MF_NOCLIP))) + if ((mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP)) { if (mo->flags3 & MF3_CEILINGHUGGER) { @@ -2615,11 +2615,6 @@ void AActor::RemoveFromHash () tid = 0; } -angle_t AActor::AngleIncrements () -{ - return ANGLE_45; -} - //========================================================================== // // AActor :: GetMissileDamage @@ -3022,7 +3017,7 @@ void AActor::Tick () && !players[i].enemy && player ? !IsTeammate (players[i].mo) : true && P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST - && P_CheckSight (players[i].mo, this, 2)) + && P_CheckSight (players[i].mo, this, SF_SEEPASTBLOCKEVERYTHING)) { //Probably a monster, so go kill it. players[i].enemy = this; } @@ -3700,8 +3695,6 @@ void AActor::LevelSpawned () { if (tics > 0 && !(flags4 & MF4_SYNCHRONIZED)) tics = 1 + (pr_spawnmapthing() % tics); - angle_t incs = AngleIncrements (); - angle -= angle % incs; flags &= ~MF_DROPPED; // [RH] clear MF_DROPPED flag HandleSpawnFlags (); } @@ -3960,7 +3953,15 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer) { spawn_x = mthing->x; spawn_y = mthing->y; - spawn_angle = ANG45 * (mthing->angle/45); + // Allow full angular precision but avoid roundoff errors for multiples of 45 degrees. + if (mthing->angle % 45 != 0) + { + spawn_angle = mthing->angle * (ANG45 / 45); + } + else + { + spawn_angle = ANG45 * (mthing->angle / 45); + } } mobj = static_cast @@ -3986,11 +3987,15 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer) p->userinfo.skin = R_FindSkin (skins[p->userinfo.skin].name, p->CurrentPlayerClass); StatusBar->SetFace (&skins[p->userinfo.skin]); - // [RH] Be sure the player has the right translation - R_BuildPlayerTranslation (playernum); - // [RH] set color translations for player sprites - mobj->Translation = TRANSLATION(TRANSLATION_Players,playernum); + if (!(mobj->flags2 & MF2_DONTTRANSLATE)) + { + // [RH] Be sure the player has the right translation + R_BuildPlayerTranslation (playernum); + + // [RH] set color translations for player sprites + mobj->Translation = TRANSLATION(TRANSLATION_Players,playernum); + } mobj->angle = spawn_angle; mobj->pitch = mobj->roll = 0; @@ -4506,8 +4511,8 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator) { AActor *th; - PalEntry bloodcolor = originator->GetClass()->BloodColor; - PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType); + PalEntry bloodcolor = originator->GetBloodColor(); + PClassActor *bloodcls = originator->GetBloodType(); int bloodtype = cl_bloodtype; @@ -4568,8 +4573,8 @@ void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AAc void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { - PalEntry bloodcolor = originator->GetClass()->BloodColor; - PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType2); + PalEntry bloodcolor = originator->GetBloodColor(); + PClassActor *bloodcls = originator->GetBloodType(1); int bloodtype = cl_bloodtype; @@ -4606,8 +4611,8 @@ void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) { - PalEntry bloodcolor = originator->GetClass()->BloodColor; - PClassActor *bloodcls = PClass::FindActor(originator->GetClass()->BloodType3); + PalEntry bloodcolor = originator->GetBloodColor(); + PClassActor *bloodcls = originator->GetBloodType(2); int bloodtype = cl_bloodtype; @@ -4645,8 +4650,8 @@ void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator) void P_RipperBlood (AActor *mo, AActor *bleeder) { fixed_t x, y, z; - PalEntry bloodcolor = bleeder->GetClass()->BloodColor; - PClassActor *bloodcls = PClass::FindActor(bleeder->GetClass()->BloodType); + PalEntry bloodcolor = bleeder->GetBloodColor(); + PClassActor *bloodcls = bleeder->GetBloodType(); x = mo->x + (pr_ripperblood.Random2 () << 12); y = mo->y + (pr_ripperblood.Random2 () << 12); diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 0afb49be4..c27da8e56 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -294,8 +294,10 @@ MapData *P_OpenMapData(const char * mapname) { // The following lump is from a different file so whatever this is, // it is not a multi-lump Doom level so let's assume it is a Build map. - map->MapLumps[0].FilePos = Wads.GetLumpOffset(lump_name); + map->MapLumps[0].FilePos = 0; map->MapLumps[0].Size = Wads.LumpLength(lump_name); + map->file = Wads.ReopenLumpNum(lump_name); + map->CloseOnDestruct = true; if (!P_IsBuildMap(map)) { delete map; @@ -312,6 +314,9 @@ MapData *P_OpenMapData(const char * mapname) if (map->Encrypted) { // If it's encrypted, then it's a Blood file, presumably a map. + map->file = Wads.ReopenLumpNum(lump_name); + map->CloseOnDestruct = true; + map->MapLumps[0].FilePos = 0; if (!P_IsBuildMap(map)) { delete map; @@ -322,7 +327,7 @@ MapData *P_OpenMapData(const char * mapname) int index = 0; - if (stricmp(Wads.GetLumpFullName(lump_name + 1), "TEXTMAP")) + if (stricmp(Wads.GetLumpFullName(lump_name + 1), "TEXTMAP") != 0) { for(int i = 1;; i++) { @@ -404,7 +409,8 @@ MapData *P_OpenMapData(const char * mapname) } } DWORD id; - (*map->file) >> id; + + map->file->Read(&id, sizeof(id)); if (id == IWAD_ID || id == PWAD_ID) { @@ -705,9 +711,15 @@ void P_FloodZone (sector_t *sec, int zonenum) continue; if (check->frontsector == sec) + { + assert(check->backsector != NULL); other = check->backsector; + } else + { + assert(check->frontsector != NULL); other = check->frontsector; + } if (other->ZoneNumber != zonenum) P_FloodZone (other, zonenum); @@ -717,6 +729,7 @@ void P_FloodZone (sector_t *sec, int zonenum) void P_FloodZones () { int z = 0, i; + ReverbContainer *reverb; for (i = 0; i < numsectors; ++i) { @@ -727,9 +740,15 @@ void P_FloodZones () } numzones = z; zones = new zone_t[z]; + reverb = S_FindEnvironment(level.DefaultEnvironment); + if (reverb == NULL) + { + Printf("Sound environment %d, %d not found\n", level.DefaultEnvironment >> 8, level.DefaultEnvironment & 255); + reverb = DefaultEnvironments[0]; + } for (i = 0; i < z; ++i) { - zones[i].Environment = DefaultEnvironments[0]; + zones[i].Environment = reverb; } } @@ -3379,7 +3398,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); if (map == NULL) { I_Error("Unable to open map '%s'\n", lumpname); @@ -3395,11 +3414,9 @@ void P_SetupLevel (char *lumpname, int position) BYTE *mapdata = new BYTE[map->MapLumps[0].Size]; map->Seek(0); map->file->Read(mapdata, map->MapLumps[0].Size); - if (map->Encrypted) - { - BloodCrypt (mapdata, 0, MIN (map->MapLumps[0].Size, 256)); - } + times[0].Clock(); buildmap = P_LoadBuildMap (mapdata, map->MapLumps[0].Size, &buildthings, &numbuildthings); + times[0].Unclock(); delete[] mapdata; } diff --git a/src/p_sight.cpp b/src/p_sight.cpp index cc2940d7d..55ab3f13a 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -53,7 +53,7 @@ class SightCheck fixed_t lastzbottom; // z at last line sector_t * lastsector; // last sector being entered by trace fixed_t topslope, bottomslope; // slopes to top and bottom of target - int SeePastBlockEverything, SeePastShootableLines; + int Flags; divline_t trace; int myseethrough; @@ -73,9 +73,8 @@ public: seeingthing=t2; bottomslope = t2->z - sightzstart; topslope = bottomslope + t2->height; + Flags = flags; - SeePastBlockEverything = flags & 6; - SeePastShootableLines = flags & 4; myseethrough = FF_SEETHROUGH; } }; @@ -144,6 +143,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) F3DFloor* rover=s->e->XFloor.ffloors[j]; if((rover->flags & FF_SEETHROUGH) == myseethrough || !(rover->flags & FF_EXISTS)) continue; + if ((Flags & SF_IGNOREWATERBOUNDARY) && (rover->flags & FF_SOLID) == 0) continue; fixed_t ff_bottom=rover->bottom.plane->ZatPoint(trX, trY); fixed_t ff_top=rover->top.plane->ZatPoint(trX, trY); @@ -176,6 +176,7 @@ bool SightCheck::PTR_SightTraverse (intercept_t *in) F3DFloor* rover2=sb->e->XFloor.ffloors[k]; if((rover2->flags & FF_SEETHROUGH) == myseethrough || !(rover2->flags & FF_EXISTS)) continue; + if ((Flags & SF_IGNOREWATERBOUNDARY) && (rover->flags & FF_SOLID) == 0) continue; fixed_t ffb_bottom=rover2->bottom.plane->ZatPoint(trX, trY); fixed_t ffb_top=rover2->top.plane->ZatPoint(trX, trY); @@ -255,7 +256,7 @@ bool SightCheck::P_SightCheckLine (line_t *ld) // [RH] don't see past block everything lines if (ld->flags & ML_BLOCKEVERYTHING) { - if (!SeePastBlockEverything) + if (!(Flags & SF_SEEPASTBLOCKEVERYTHING)) { return false; } @@ -263,7 +264,7 @@ bool SightCheck::P_SightCheckLine (line_t *ld) // that runs a script on the current map. Used to prevent monsters // from trying to attack through a block everything line unless // there's a chance their attack will make it nonblocking. - if (!SeePastShootableLines) + if (!(Flags & SF_SEEPASTSHOOTABLELINES)) { if (!(ld->activation & SPAC_Impact)) { @@ -407,6 +408,7 @@ bool SightCheck::P_SightTraverseIntercepts () F3DFloor* rover = lastsector->e->XFloor.ffloors[i]; if((rover->flags & FF_SOLID) == myseethrough || !(rover->flags & FF_EXISTS)) continue; + if ((Flags & SF_IGNOREWATERBOUNDARY) && (rover->flags & FF_SOLID) == 0) continue; fixed_t ff_bottom=rover->bottom.plane->ZatPoint(seeingthing->x, seeingthing->y); fixed_t ff_top=rover->top.plane->ZatPoint(seeingthing->x, seeingthing->y); @@ -670,7 +672,7 @@ sightcounts[0]++; // // [RH] Andy Baker's stealth monsters: // Cannot see an invisible object - if ((flags & 1) == 0 && ((t2->renderflags & RF_INVISIBLE) || !t2->RenderStyle.IsVisible(t2->alpha))) + if ((flags & SF_IGNOREVISIBILITY) == 0 && ((t2->renderflags & RF_INVISIBLE) || !t2->RenderStyle.IsVisible(t2->alpha))) { // small chance of an attack being made anyway if ((bglobal.m_Thinking ? pr_botchecksight() : pr_checksight()) > 50) { @@ -681,20 +683,23 @@ sightcounts[0]++; // killough 4/19/98: make fake floors and ceilings block monster view - if ((s1->GetHeightSec() && - ((t1->z + t1->height <= s1->heightsec->floorplane.ZatPoint (t1->x, t1->y) && - t2->z >= s1->heightsec->floorplane.ZatPoint (t2->x, t2->y)) || - (t1->z >= s1->heightsec->ceilingplane.ZatPoint (t1->x, t1->y) && - t2->z + t1->height <= s1->heightsec->ceilingplane.ZatPoint (t2->x, t2->y)))) - || - (s2->GetHeightSec() && - ((t2->z + t2->height <= s2->heightsec->floorplane.ZatPoint (t2->x, t2->y) && - t1->z >= s2->heightsec->floorplane.ZatPoint (t1->x, t1->y)) || - (t2->z >= s2->heightsec->ceilingplane.ZatPoint (t2->x, t2->y) && - t1->z + t2->height <= s2->heightsec->ceilingplane.ZatPoint (t1->x, t1->y))))) + if (!(flags & SF_IGNOREWATERBOUNDARY)) { - res = false; - goto done; + if ((s1->GetHeightSec() && + ((t1->z + t1->height <= s1->heightsec->floorplane.ZatPoint (t1->x, t1->y) && + t2->z >= s1->heightsec->floorplane.ZatPoint (t2->x, t2->y)) || + (t1->z >= s1->heightsec->ceilingplane.ZatPoint (t1->x, t1->y) && + t2->z + t1->height <= s1->heightsec->ceilingplane.ZatPoint (t2->x, t2->y)))) + || + (s2->GetHeightSec() && + ((t2->z + t2->height <= s2->heightsec->floorplane.ZatPoint (t2->x, t2->y) && + t1->z >= s2->heightsec->floorplane.ZatPoint (t1->x, t1->y)) || + (t2->z >= s2->heightsec->ceilingplane.ZatPoint (t2->x, t2->y) && + t1->z + t2->height <= s2->heightsec->ceilingplane.ZatPoint (t1->x, t1->y))))) + { + res = false; + goto done; + } } // An unobstructed LOS is possible. diff --git a/src/p_spec.cpp b/src/p_spec.cpp index 95bee9eb3..737ccc226 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -1939,7 +1939,7 @@ void DPusher::Tick () // If speed <= 0, you're outside the effective radius. You also have // to be able to see the push/pull source point. - if ((speed > 0) && (P_CheckSight (thing, m_Source, 1))) + if ((speed > 0) && (P_CheckSight (thing, m_Source, SF_IGNOREVISIBILITY))) { angle_t pushangle = R_PointToAngle2 (thing->x, thing->y, sx, sy); if (m_Source->GetClass()->TypeName == NAME_PointPusher) diff --git a/src/p_user.cpp b/src/p_user.cpp index 5c7c3f632..f2ee29234 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -55,7 +55,6 @@ static FRandom pr_skullpop ("SkullPop"); - // [RH] # of ticks to complete a turn180 #define TURN180_TICKS ((TICRATE / 4) + 1) @@ -2671,3 +2670,47 @@ void player_t::Serialize (FArchive &arc) } } + +static FPlayerColorSetMap *GetPlayerColors(FName classname) +{ + PClassPlayerPawn *cls = dyn_cast(PClass::FindClass(classname)); + + if (cls != NULL) + { + return cls->ColorSets; + } + return NULL; +} + +FPlayerColorSet *P_GetPlayerColorSet(FName classname, int setnum) +{ + FPlayerColorSetMap *map = GetPlayerColors(classname); + if (map == NULL) + { + return NULL; + } + return map->CheckKey(setnum); +} + +static int STACK_ARGS intcmp(const void *a, const void *b) +{ + return *(const int *)a - *(const int *)b; +} + +void P_EnumPlayerColorSets(FName classname, TArray *out) +{ + out->Clear(); + FPlayerColorSetMap *map = GetPlayerColors(classname); + if (map != NULL) + { + FPlayerColorSetMap::Iterator it(*map); + FPlayerColorSetMap::Pair *pair; + + while (it.NextPair(pair)) + { + out->Push(pair->Key); + } + qsort(&(*out)[0], out->Size(), sizeof(int), intcmp); + } +} + diff --git a/src/po_man.cpp b/src/po_man.cpp index 8ed58cf8c..13a5bda91 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -795,25 +795,25 @@ static void UpdateSegBBox (seg_t *seg) line = seg->linedef; - if (seg->v1->x < seg->v2->x) + if (line->v1->x < line->v2->x) { - line->bbox[BOXLEFT] = seg->v1->x; - line->bbox[BOXRIGHT] = seg->v2->x; + line->bbox[BOXLEFT] = line->v1->x; + line->bbox[BOXRIGHT] = line->v2->x; } else { - line->bbox[BOXLEFT] = seg->v2->x; - line->bbox[BOXRIGHT] = seg->v1->x; + line->bbox[BOXLEFT] = line->v2->x; + line->bbox[BOXRIGHT] = line->v1->x; } - if (seg->v1->y < seg->v2->y) + if (line->v1->y < line->v2->y) { - line->bbox[BOXBOTTOM] = seg->v1->y; - line->bbox[BOXTOP] = seg->v2->y; + line->bbox[BOXBOTTOM] = line->v1->y; + line->bbox[BOXTOP] = line->v2->y; } else { - line->bbox[BOXBOTTOM] = seg->v2->y; - line->bbox[BOXTOP] = seg->v1->y; + line->bbox[BOXBOTTOM] = line->v2->y; + line->bbox[BOXTOP] = line->v1->y; } // Update the line's slopetype diff --git a/src/r_draw.cpp b/src/r_draw.cpp index 12cf3c51f..ce836f839 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -2181,7 +2181,7 @@ ESPSResult R_SetPatchStyle (FRenderStyle style, fixed_t alpha, int translation, if (translation != 0) { FRemapTable *table = TranslationToTable(translation); - if (table != NULL) + if (table != NULL && !table->Inactive) { dc_translation = table->Remap; } diff --git a/src/r_main.cpp b/src/r_main.cpp index 080628fe2..9817b4797 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1081,7 +1081,7 @@ void R_SetupFrame (AActor *actor) iview->otic = nowtic; } - R_UpdateAnimations (I_MSTime()); + R_UpdateAnimations (I_FPSTime()); r_TicFrac = I_GetTimeFrac (&r_FrameTime); if (cl_capfps || r_NoInterpolate) { diff --git a/src/r_things.cpp b/src/r_things.cpp index a9c683a70..c557a2a1f 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -2346,7 +2346,7 @@ CUSTOM_CVAR( Int, r_maxparticles, 4000, CVAR_ARCHIVE ) void R_InitParticles () { - char *i; + const char *i; if ((i = Args->CheckValue ("-numparticles"))) NumParticles = atoi (i); diff --git a/src/r_translate.cpp b/src/r_translate.cpp index 8e74f4443..d5ef79a1f 100644 --- a/src/r_translate.cpp +++ b/src/r_translate.cpp @@ -46,6 +46,7 @@ #include "sc_man.h" #include "doomerrors.h" #include "i_system.h" +#include "w_wad.h" #include "gi.h" #include "stats.h" @@ -78,7 +79,7 @@ const BYTE IcePalette[16][3] = FRemapTable::FRemapTable(int count) { assert(count <= 256); - + Inactive = false; Alloc(count); // Note that the tables are left uninitialized. It is assumed that @@ -163,6 +164,7 @@ FRemapTable &FRemapTable::operator=(const FRemapTable &o) { Alloc(o.NumEntries); } + Inactive = o.Inactive; memcpy(Remap, o.Remap, NumEntries*sizeof(*Remap) + NumEntries*sizeof(*Palette)); return *this; } @@ -892,7 +894,8 @@ static void SetRemap(FRemapTable *table, int i, float r, float g, float b) // //---------------------------------------------------------------------------- -static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable) +static void R_CreatePlayerTranslation (float h, float s, float v, const FPlayerColorSet *colorset, + FPlayerSkin *skin, FRemapTable *table, FRemapTable *alttable) { int i; BYTE start = skin->range0start; @@ -915,7 +918,7 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s { for (i = 0; i < table->NumEntries; ++i) { - table->Remap[i] = i; + table->Remap[i] = GPalette.Remap[i]; } memcpy(table->Palette, GPalette.BaseColors, sizeof(*table->Palette) * table->NumEntries); } @@ -927,16 +930,63 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s // [GRB] Don't translate skins with color range 0-0 (APlayerPawn default) if (start == 0 && end == 0) { + table->Inactive = true; table->UpdateNative(); return; } + table->Inactive = false; range = (float)(end-start+1); bases = s; basev = v; - if (gameinfo.gametype & GAME_DoomStrifeChex) + if (colorset != NULL && colorset->Lump >= 0 && Wads.LumpLength(colorset->Lump) < 256) + { // Bad table length. Ignore it. + colorset = NULL; + } + + if (colorset != NULL) + { + bool identity = true; + // Use the pre-defined range instead of a custom one. + if (colorset->Lump < 0) + { + int first = colorset->FirstColor; + if (start == end) + { + table->Remap[i] = (first + colorset->LastColor) / 2; + } + else + { + int palrange = colorset->LastColor - first; + for (i = start; i <= end; ++i) + { + int pi = first + palrange * (i - start) / (end - start); + table->Remap[i] = GPalette.Remap[pi]; + if (pi != i) identity = false; + } + } + } + else + { + FMemLump translump = Wads.ReadLump(colorset->Lump); + const BYTE *trans = (const BYTE *)translump.GetMem(); + for (i = start; i <= end; ++i) + { + table->Remap[i] = GPalette.Remap[trans[i]]; + if (trans[i] != i) identity = false; + } + } + for (i = start; i <= end; ++i) + { + table->Palette[i] = GPalette.BaseColors[table->Remap[i]]; + table->Palette[i].a = 255; + } + // If the colorset created an identity translation mark it as inactive + table->Inactive = identity; + } + else if (gameinfo.gametype & GAME_DoomStrifeChex) { // Build player sprite translation s -= 0.23f; @@ -1014,9 +1064,19 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s SetRemap(table, i, r, g, b); } } - - // Build lifegem translation - if (alttable) + } + if (gameinfo.gametype == GAME_Hexen && alttable != NULL) + { + // Build Hexen's lifegem translation. + + // Is the player's translation range the same as the gem's and we are using a + // predefined translation? If so, then use the same one for the gem. Otherwise, + // build one as per usual. + if (colorset != NULL && start == 164 && end == 185) + { + *alttable = *table; + } + else { for (i = 164; i <= 185; ++i) { @@ -1027,8 +1087,8 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s HSVtoRGB (&r, &g, &b, h, s*bases, v*basev); SetRemap(alttable, i, r, g, b); } - alttable->UpdateNative(); } + alttable->UpdateNative(); } table->UpdateNative(); } @@ -1042,10 +1102,11 @@ static void R_CreatePlayerTranslation (float h, float s, float v, FPlayerSkin *s void R_BuildPlayerTranslation (int player) { float h, s, v; + FPlayerColorSet *colorset; - D_GetPlayerColor (player, &h, &s, &v); + D_GetPlayerColor (player, &h, &s, &v, &colorset); - R_CreatePlayerTranslation (h, s, v, + R_CreatePlayerTranslation (h, s, v, colorset, &skins[players[player].userinfo.skin], translationtables[TRANSLATION_Players][player], translationtables[TRANSLATION_PlayersExtra][player]); @@ -1057,13 +1118,17 @@ void R_BuildPlayerTranslation (int player) // //---------------------------------------------------------------------------- -void R_GetPlayerTranslation (int color, FPlayerSkin *skin, FRemapTable *table) +void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayerSkin *skin, FRemapTable *table) { float h, s, v; + if (colorset != NULL) + { + color = colorset->RepresentativeColor; + } RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f, &h, &s, &v); - R_CreatePlayerTranslation (h, s, v, skin, table, NULL); + R_CreatePlayerTranslation (h, s, v, colorset, skin, table, NULL); } diff --git a/src/r_translate.h b/src/r_translate.h index 730dac541..21488155b 100644 --- a/src/r_translate.h +++ b/src/r_translate.h @@ -46,6 +46,7 @@ struct FRemapTable PalEntry *Palette; // The ideal palette this maps to FNativePalette *Native; // The Palette stored in a HW texture int NumEntries; // # of elements in this table (usually 256) + bool Inactive; // This table is inactive and should be treated as if it was passed as NULL private: void Free(); diff --git a/src/resourcefiles/file_rff.cpp b/src/resourcefiles/file_rff.cpp index bb2616c2b..2e6a3bc5a 100644 --- a/src/resourcefiles/file_rff.cpp +++ b/src/resourcefiles/file_rff.cpp @@ -56,13 +56,15 @@ struct RFFInfo struct RFFLump { - BYTE IDontKnow[16]; + DWORD DontKnow1[4]; DWORD FilePos; DWORD Size; - BYTE IStillDontKnow[8]; + DWORD DontKnow2; + DWORD Time; BYTE Flags; char Extension[3]; - char Name[8+4]; // 4 bytes that I don't know what they are for + char Name[8]; + DWORD IndexNum; // Used by .sfx, possibly others }; //========================================================================== @@ -75,6 +77,10 @@ struct FRFFLump : public FUncompressedLump { virtual FileReader *GetReader(); virtual int FillCache(); + + DWORD IndexNum; + + int GetIndexNum() const { return IndexNum; } }; //========================================================================== @@ -149,33 +155,34 @@ bool FRFFFile::Open(bool quiet) if (!quiet) Printf(", %d lumps\n", NumLumps); for (DWORD i = 0; i < NumLumps; ++i) { - if (lumps[i].Extension[0] == 'S' && lumps[i].Extension[1] == 'F' && - lumps[i].Extension[2] == 'X') - { - Lumps[i].Namespace = ns_bloodsfx; - } - else if (lumps[i].Extension[0] == 'R' && lumps[i].Extension[1] == 'A' && - lumps[i].Extension[2] == 'W') - { - Lumps[i].Namespace = ns_bloodraw; - } - else - { - Lumps[i].Namespace = ns_global; - } - Lumps[i].Position = LittleLong(lumps[i].FilePos); Lumps[i].LumpSize = LittleLong(lumps[i].Size); Lumps[i].Owner = this; - if (lumps[i].Flags & 0x10) Lumps[i].Flags |= LUMPF_BLOODCRYPT; - - // Rearrange the name and extension in a part of the lump record - // that I don't have any use for in order to cnstruct the fullname. - lumps[i].Name[8] = '\0'; - strcpy ((char *)lumps[i].IDontKnow, lumps[i].Name); - strcat ((char *)lumps[i].IDontKnow, "."); - strcat ((char *)lumps[i].IDontKnow, lumps[i].Extension); - Lumps[i].LumpNameSetup((char *)lumps[i].IDontKnow); + if (lumps[i].Flags & 0x10) + { + Lumps[i].Flags |= LUMPF_BLOODCRYPT; + } + Lumps[i].IndexNum = LittleLong(lumps[i].IndexNum); + // Rearrange the name and extension to construct the fullname. + char name[13]; + strncpy(name, lumps[i].Name, 8); + name[8] = 0; + size_t len = strlen(name); + assert(len + 4 <= 12); + name[len+0] = '.'; + name[len+1] = lumps[i].Extension[0]; + name[len+2] = lumps[i].Extension[1]; + name[len+3] = lumps[i].Extension[2]; + name[len+4] = 0; + Lumps[i].LumpNameSetup(name); + if (name[len+1] == 'S' && name[len+2] == 'F' && name[len+3] == 'X') + { + Lumps[i].Namespace = ns_bloodsfx; + } + else if (name[len+1] == 'R' && name[len+2] == 'A' && name[len+3] == 'W') + { + Lumps[i].Namespace = ns_bloodraw; + } } delete[] lumps; return true; @@ -183,7 +190,10 @@ bool FRFFFile::Open(bool quiet) FRFFFile::~FRFFFile() { - if (Lumps != NULL) delete [] Lumps; + if (Lumps != NULL) + { + delete[] Lumps; + } } @@ -197,8 +207,14 @@ FileReader *FRFFLump::GetReader() { // Don't return the reader if this lump is encrypted // In that case always force caching of the lump - if (!(Flags & LUMPF_BLOODCRYPT)) return FUncompressedLump::GetReader(); - else return NULL; + if (!(Flags & LUMPF_BLOODCRYPT)) + { + return FUncompressedLump::GetReader(); + } + else + { + return NULL; + } } //========================================================================== diff --git a/src/resourcefiles/resourcefile.h b/src/resourcefiles/resourcefile.h index ac8499944..e531ddbb3 100644 --- a/src/resourcefiles/resourcefile.h +++ b/src/resourcefiles/resourcefile.h @@ -41,6 +41,7 @@ struct FResourceLump virtual FileReader *GetReader(); virtual FileReader *NewReader(); virtual int GetFileOffset() { return -1; } + virtual int GetIndexNum() const { return 0; } void LumpNameSetup(const char *iname); void CheckEmbedded(); diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index 14742f55d..b5cfc1d82 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -114,7 +114,7 @@ protected: void Free (); }; -static struct AmbientSound +struct FAmbientSound { unsigned type; // type of ambient sound int periodmin; // # of tics between repeats @@ -122,7 +122,8 @@ static struct AmbientSound float volume; // relative volume of sound float attenuation; FString sound; // Logical name of sound to play -} *Ambients[256]; +}; +TMap Ambients; enum SICommands { @@ -509,6 +510,7 @@ int S_AddSoundLump (const char *logicalname, int lump) newsfx.Rolloff.RolloffType = ROLLOFF_Doom; newsfx.Rolloff.MinDistance = 0; newsfx.Rolloff.MaxDistance = 0; + newsfx.LoopStart = -1; return (int)S_sfx.Push (newsfx); } @@ -836,15 +838,7 @@ static void S_ClearSoundData() S_UnloadSound(&S_sfx[i]); } S_sfx.Clear(); - - for(i = 0; i < countof(Ambients); i++) - { - if (Ambients[i] != NULL) - { - delete Ambients[i]; - Ambients[i] = NULL; - } - } + Ambients.Clear(); while (MusicVolumes != NULL) { FMusicVolume *me = MusicVolumes; @@ -967,23 +961,10 @@ static void S_AddSNDINFO (int lump) // $ambient [point [atten] | surround | [world]] // | periodic > // - AmbientSound *ambient, dummy; + FAmbientSound *ambient; sc.MustGetNumber (); - if (sc.Number < 0 || sc.Number > 255) - { - Printf ("Bad ambient index (%d)\n", sc.Number); - ambient = &dummy; - } - else if (Ambients[sc.Number] == NULL) - { - ambient = new AmbientSound; - Ambients[sc.Number] = ambient; - } - else - { - ambient = Ambients[sc.Number]; - } + ambient = &Ambients[sc.Number]; ambient->type = 0; ambient->periodmin = 0; ambient->periodmax = 0; @@ -1366,18 +1347,15 @@ static void S_AddSNDINFO (int lump) static void S_AddBloodSFX (int lumpnum) { - char name[13]; - FMemLump sfxlump = Wads.ReadLump (lumpnum); + FMemLump sfxlump = Wads.ReadLump(lumpnum); const FBloodSFX *sfx = (FBloodSFX *)sfxlump.GetMem(); - int rawlump = Wads.CheckNumForName (sfx->RawName, ns_bloodraw); + int rawlump = Wads.CheckNumForName(sfx->RawName, ns_bloodraw); int sfxnum; if (rawlump != -1) { - Wads.GetLumpName (name, lumpnum); - name[8] = 0; - strcat (name, ".SFX"); - sfxnum = S_AddSound (name, rawlump); + const char *name = Wads.GetLumpFullName(lumpnum); + sfxnum = S_AddSound(name, rawlump); if (sfx->Format == 5) { S_sfx[sfxnum].bForce22050 = true; @@ -1387,6 +1365,17 @@ static void S_AddBloodSFX (int lumpnum) S_sfx[sfxnum].bForce11025 = true; } S_sfx[sfxnum].bLoadRAW = true; + S_sfx[sfxnum].LoopStart = LittleLong(sfx->LoopStart); + // Make an ambient sound out of it, whether it has a loop point + // defined or not. (Because none of the standard Blood ambient + // sounds are explicitly defined as looping.) + FAmbientSound *ambient = &Ambients[Wads.GetLumpIndexNum(lumpnum)]; + ambient->type = CONTINUOUS; + ambient->periodmin = 0; + ambient->periodmax = 0; + ambient->volume = 1; + ambient->attenuation = 1; + ambient->sound = name; } } @@ -1906,12 +1895,18 @@ public: protected: bool bActive; private: - void SetTicker (struct AmbientSound *ambient); + void SetTicker (struct FAmbientSound *ambient); int NextCheck; }; IMPLEMENT_CLASS (AAmbientSound) +//========================================================================== +// +// AmbientSound :: Serialize +// +//========================================================================== + void AAmbientSound::Serialize (FArchive &arc) { Super::Serialize (arc); @@ -1948,6 +1943,11 @@ void AAmbientSound::Serialize (FArchive &arc) } } +//========================================================================== +// +// AmbientSound :: Tick +// +//========================================================================== void AAmbientSound::Tick () { @@ -1956,17 +1956,47 @@ void AAmbientSound::Tick () if (!bActive || gametic < NextCheck) return; - AmbientSound *ambient = Ambients[args[0]]; + FAmbientSound *ambient; int loop = 0; + ambient = Ambients.CheckKey(args[0]); + if (ambient == NULL) + { + return; + } + if ((ambient->type & CONTINUOUS) == CONTINUOUS) { loop = CHAN_LOOP; } - if (ambient->sound[0]) + if (ambient->sound.IsNotEmpty()) { - S_Sound(this, CHAN_BODY | loop, ambient->sound, ambient->volume, ambient->attenuation); + // The second argument scales the ambient sound's volume. + // 0 and 100 are normal volume. The maximum volume level + // possible is always 1. + float volscale = args[1] == 0 ? 1 : args[1] / 100.f; + float usevol = clamp(ambient->volume * volscale, 0.f, 1.f); + + // The third argument is the minimum distance for audible fading, and + // the fourth argument is the maximum distance for audibility. Setting + // either of these to 0 or setting min distance > max distance will + // use the standard rolloff. + if ((args[2] | args[3]) == 0 || args[2] > args[3]) + { + S_Sound(this, CHAN_BODY | loop, ambient->sound, usevol, ambient->attenuation); + } + else + { + float min = float(args[2]), max = float(args[3]); + // The fifth argument acts as a scalar for the preceding two, if it's non-zero. + if (args[4] > 0) + { + min *= args[4]; + max *= args[4]; + } + S_SoundMinMaxDist(this, CHAN_BODY | loop, ambient->sound, usevol, min, max); + } if (!loop) { SetTicker (ambient); @@ -1982,8 +2012,13 @@ void AAmbientSound::Tick () } } +//========================================================================== +// +// AmbientSound :: SetTicker +// +//========================================================================== -void AAmbientSound::SetTicker (struct AmbientSound *ambient) +void AAmbientSound::SetTicker (struct FAmbientSound *ambient) { if ((ambient->type & CONTINUOUS) == CONTINUOUS) { @@ -2001,17 +2036,31 @@ void AAmbientSound::SetTicker (struct AmbientSound *ambient) } } +//========================================================================== +// +// AmbientSound :: BeginPlay +// +//========================================================================== + void AAmbientSound::BeginPlay () { Super::BeginPlay (); Activate (NULL); } +//========================================================================== +// +// AmbientSound :: Activate +// +// Starts playing a sound (or does nothing of the sound is already playing). +// +//========================================================================== + void AAmbientSound::Activate (AActor *activator) { Super::Activate (activator); - AmbientSound *amb = Ambients[args[0]]; + FAmbientSound *amb = Ambients.CheckKey(args[0]); if (amb == NULL) { @@ -2040,13 +2089,23 @@ void AAmbientSound::Activate (AActor *activator) } } +//========================================================================== +// +// AmbientSound :: Deactivate +// +// Stops playing CONTINUOUS sounds immediately. Also prevents further +// occurrences of repeated sounds. +// +//========================================================================== + void AAmbientSound::Deactivate (AActor *activator) { Super::Deactivate (activator); if (bActive) { bActive = false; - if ((Ambients[args[0]]->type & CONTINUOUS) == CONTINUOUS) + FAmbientSound *ambient = Ambients.CheckKey(args[0]); + if (ambient != NULL && (ambient->type & CONTINUOUS) == CONTINUOUS) { S_StopSound (this, CHAN_BODY); } diff --git a/src/s_playlist.cpp b/src/s_playlist.cpp index 1ab294dc1..e92a5ceea 100644 --- a/src/s_playlist.cpp +++ b/src/s_playlist.cpp @@ -198,7 +198,7 @@ int FPlayList::Advance () int FPlayList::Backup () { - if (--Position < 0) + if (Position-- == 0) { Position = Songs.Size() - 1; } diff --git a/src/s_sound.cpp b/src/s_sound.cpp index b0b68897b..290157265 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -108,7 +108,7 @@ static void CalcPosVel(int type, const AActor *actor, const sector_t *sector, co static void CalcSectorSoundOrg(const sector_t *sec, int channum, fixed_t *x, fixed_t *y, fixed_t *z); static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fixed_t *z); static FSoundChan *S_StartSound(AActor *mover, const sector_t *sec, const FPolyObj *poly, - const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation); + const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation, FRolloffInfo *rolloff); static void S_SetListener(SoundListener &listener, AActor *listenactor); // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -165,6 +165,7 @@ void S_NoiseDebug (void) screen->DrawText (SmallFont, CR_GOLD, 340, y, "pri", TAG_DONE); screen->DrawText (SmallFont, CR_GOLD, 380, y, "flags", TAG_DONE); screen->DrawText (SmallFont, CR_GOLD, 460, y, "aud", TAG_DONE); + screen->DrawText (SmallFont, CR_GOLD, 520, y, "pos", TAG_DONE); y += 8; if (Channels == NULL) @@ -253,6 +254,11 @@ void S_NoiseDebug (void) mysnprintf(temp, countof(temp), "%.4f", GSnd->GetAudibility(chan)); screen->DrawText(SmallFont, color, 460, y, temp, TAG_DONE); + // Position + mysnprintf(temp, countof(temp), "%u", GSnd->GetPosition(chan)); + screen->DrawText(SmallFont, color, 520, y, temp, TAG_DONE); + + y += 8; if (chan->PrevChan == &Channels) { @@ -317,7 +323,6 @@ void S_InitData () LastLocalSndInfo = LastLocalSndSeq = ""; S_ParseSndInfo (); S_ParseSndSeq (-1); - S_ParseReverbDef (); } //========================================================================== @@ -808,7 +813,8 @@ static void CalcPolyobjSoundOrg(const FPolyObj *poly, fixed_t *x, fixed_t *y, fi //========================================================================== static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyObj *poly, - const FVector3 *pt, int channel, FSoundID sound_id, double volume, double attenuation) + const FVector3 *pt, int channel, FSoundID sound_id, float volume, float attenuation, + FRolloffInfo *forcedrolloff=NULL) { sfxinfo_t *sfx; int chanflags; @@ -866,7 +872,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO sfx = &S_sfx[sound_id]; // Scale volume according to SNDINFO data. - volume = MIN(volume * sfx->Volume, 1.0); + volume = MIN(volume * sfx->Volume, 1.f); if (volume <= 0) return NULL; @@ -894,7 +900,10 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO near_limit = S_sfx[sound_id].NearLimit; limit_range = S_sfx[sound_id].LimitRange; } - if (rolloff->MinDistance == 0) rolloff = &S_sfx[sound_id].Rolloff; + if (rolloff->MinDistance == 0) + { + rolloff = &S_sfx[sound_id].Rolloff; + } } else { @@ -904,13 +913,25 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO near_limit = S_sfx[sound_id].NearLimit; limit_range = S_sfx[sound_id].LimitRange; } - if (rolloff->MinDistance == 0) rolloff = &S_sfx[sound_id].Rolloff; + if (rolloff->MinDistance == 0) + { + rolloff = &S_sfx[sound_id].Rolloff; + } } sfx = &S_sfx[sound_id]; } - // If no valid rolloff was set use the global default - if (rolloff->MinDistance == 0) rolloff = &S_Rolloff; + // The passed rolloff overrides any sound-specific rolloff. + if (forcedrolloff != NULL && forcedrolloff->MinDistance != 0) + { + rolloff = forcedrolloff; + } + + // If no valid rolloff was set, use the global default. + if (rolloff->MinDistance == 0) + { + rolloff = &S_Rolloff; + } // If this is a singular sound, don't play it if it's already playing. if (sfx->bSingular && S_CheckSingular(sound_id)) @@ -1162,7 +1183,7 @@ void S_RestartSound(FSoundChan *chan) // //========================================================================== -void S_Sound (int channel, FSoundID sound_id, double volume, double attenuation) +void S_Sound (int channel, FSoundID sound_id, float volume, float attenuation) { S_StartSound (NULL, NULL, NULL, NULL, channel, sound_id, volume, attenuation); } @@ -1173,20 +1194,41 @@ void S_Sound (int channel, FSoundID sound_id, double volume, double attenuation) // //========================================================================== -void S_Sound (AActor *ent, int channel, FSoundID sound_id, double volume, double attenuation) +void S_Sound (AActor *ent, int channel, FSoundID sound_id, float volume, float attenuation) { if (ent == NULL || ent->Sector->Flags & SECF_SILENT) return; S_StartSound (ent, NULL, NULL, NULL, channel, sound_id, volume, attenuation); } +//========================================================================== +// +// S_SoundMinMaxDist - An actor is source +// +// Attenuation is specified as min and max distances, rather than a scalar. +// +//========================================================================== + +void S_SoundMinMaxDist(AActor *ent, int channel, FSoundID sound_id, float volume, float mindist, float maxdist) +{ + if (ent == NULL || ent->Sector->Flags & SECF_SILENT) + return; + + FRolloffInfo rolloff; + + rolloff.RolloffType = ROLLOFF_Linear; + rolloff.MinDistance = mindist; + rolloff.MaxDistance = maxdist; + S_StartSound(ent, NULL, NULL, NULL, channel, sound_id, volume, 1, &rolloff); +} + //========================================================================== // // S_Sound - A polyobject is source // //========================================================================== -void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, double volume, double attenuation) +void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, float volume, float attenuation) { S_StartSound (NULL, NULL, poly, NULL, channel, sound_id, volume, attenuation); } @@ -1197,7 +1239,7 @@ void S_Sound (const FPolyObj *poly, int channel, FSoundID sound_id, double volum // //========================================================================== -void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, double volume, double attenuation) +void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, float volume, float attenuation) { FVector3 pt(FIXED2FLOAT(x), FIXED2FLOAT(z), FIXED2FLOAT(y)); S_StartSound (NULL, NULL, NULL, &pt, channel, sound_id, volume, attenuation); @@ -1209,7 +1251,7 @@ void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sound_id, d // //========================================================================== -void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, double volume, double attenuation) +void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation) { S_StartSound (NULL, sec, NULL, NULL, channel, sfxid, volume, attenuation); } @@ -1285,7 +1327,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) } sfxstart = sfxdata + 8; } - sfx->data = GSnd->LoadSoundRaw(sfxstart, len, frequency, 1, 8); + sfx->data = GSnd->LoadSoundRaw(sfxstart, len, frequency, 1, 8, sfx->LoopStart); } else { @@ -1879,8 +1921,8 @@ static void S_SetListener(SoundListener &listener, AActor *listenactor) */ listener.velocity.Zero(); listener.position.X = FIXED2FLOAT(listenactor->x); - listener.position.Y = FIXED2FLOAT(listenactor->y); - listener.position.Z = FIXED2FLOAT(listenactor->z); + listener.position.Y = FIXED2FLOAT(listenactor->z); + listener.position.Z = FIXED2FLOAT(listenactor->y); listener.underwater = listenactor->waterlevel == 3; assert(zones != NULL); listener.Environment = zones[listenactor->Sector->ZoneNumber].Environment; diff --git a/src/s_sound.h b/src/s_sound.h index 98e9b517e..b616b9137 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -59,6 +59,8 @@ struct sfxinfo_t WORD bSingular:1; WORD bTentative:1; + int LoopStart; // -1 means no specific loop defined + unsigned int link; enum { NO_LINK = 0xffffffff }; @@ -216,11 +218,12 @@ void S_PrecacheLevel (); void S_CacheSound (sfxinfo_t *sfx); // Start sound for thing at -void S_Sound (int channel, FSoundID sfxid, double volume, double attenuation); -void S_Sound (AActor *ent, int channel, FSoundID sfxid, double volume, double attenuation); -void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, double volume, double attenuation); -void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, double volume, double attenuation); -void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, double volume, double attenuation); +void S_Sound (int channel, FSoundID sfxid, float volume, float attenuation); +void S_Sound (AActor *ent, int channel, FSoundID sfxid, float volume, float attenuation); +void S_SoundMinMaxDist (AActor *ent, int channel, FSoundID sfxid, float volume, float mindist, float maxdist); +void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, float attenuation); +void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation); +void S_Sound (fixed_t x, fixed_t y, fixed_t z, int channel, FSoundID sfxid, float volume, float attenuation); // sound channels // channel 0 never willingly overrides diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index f8f01f2a9..671b73d21 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1737,7 +1737,7 @@ bool FMODSoundRenderer::HandleChannelDelay(FMOD::Channel *chan, FISoundChannel * if (FMOD_OK == chan->getCurrentSound(&sound)) { unsigned int len; - if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS)) + if (FMOD_OK == sound->getLength(&len, FMOD_TIMEUNIT_MS) && len) { difftime %= len; } @@ -1994,11 +1994,11 @@ void FMODSoundRenderer::UpdateListener(SoundListener *listener) // Set velocity to 0 to prevent crazy doppler shifts just from running. vel.x = listener->velocity.X; - vel.z = listener->velocity.Y; - vel.y = listener->velocity.Z; + vel.y = listener->velocity.Y; + vel.z = listener->velocity.Z; pos.x = listener->position.X; - pos.z = listener->position.Y; - pos.y = listener->position.Z; + pos.y = listener->position.Y; + pos.z = listener->position.Z; float angle = listener->angle; forward.x = cos(angle); @@ -2190,12 +2190,16 @@ void FMODSoundRenderer::UpdateSounds() // //========================================================================== -SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits) +SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart) { FMOD_CREATESOUNDEXINFO exinfo; SoundHandle retval = { NULL }; + int numsamples; - if (length == 0) return retval; + if (length <= 0) + { + return retval; + } InitCreateSoundExInfo(&exinfo); exinfo.length = length; @@ -2212,14 +2216,17 @@ SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequ case -8: exinfo.format = FMOD_SOUND_FORMAT_PCM8; + numsamples = length; break; case 16: exinfo.format = FMOD_SOUND_FORMAT_PCM16; + numsamples = length >> 1; break; case 32: exinfo.format = FMOD_SOUND_FORMAT_PCM32; + numsamples = length >> 2; break; default: @@ -2236,6 +2243,12 @@ SoundHandle FMODSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequ DPrintf("Failed to allocate sample: Error %d\n", result); return retval; } + + if (loopstart >= 0) + { + sample->setLoopPoints(loopstart, FMOD_TIMEUNIT_PCM, numsamples - 1, FMOD_TIMEUNIT_PCM); + } + retval.data = sample; return retval; } diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 3f31481bf..1460b697b 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -14,7 +14,7 @@ public: void SetSfxVolume (float volume); void SetMusicVolume (float volume); SoundHandle LoadSound(BYTE *sfxdata, int length); - SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits); + SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart); void UnloadSound (SoundHandle sfx); unsigned int GetMSLength(SoundHandle sfx); unsigned int GetSampleLength(SoundHandle sfx); diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 83c75410d..38e820c8b 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -112,7 +112,10 @@ CUSTOM_CVAR (Float, snd_musicvolume, 0.5f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) else { // Set general music volume. - GSnd->SetMusicVolume(clamp(self * relative_volume, 0, 1)); + if (GSnd != NULL) + { + GSnd->SetMusicVolume(clamp(self * relative_volume, 0, 1)); + } // For music not implemented through the digital sound system, // let them know about the change. if (currSong != NULL) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 0009b48e2..b25bbd6fb 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -123,7 +123,7 @@ public: SoundHandle retval = { NULL }; return retval; } - SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits) + SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart) { SoundHandle retval = { NULL }; return retval; diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index 31f401093..d8cf166fc 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -92,7 +92,7 @@ public: virtual void SetSfxVolume (float volume) = 0; virtual void SetMusicVolume (float volume) = 0; virtual SoundHandle LoadSound(BYTE *sfxdata, int length) = 0; - virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits) = 0; + virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart) = 0; virtual void UnloadSound (SoundHandle sfx) = 0; // unloads a sound from memory virtual unsigned int GetMSLength(SoundHandle sfx) = 0; // Gets the length of a sound at its default frequency virtual unsigned int GetSampleLength(SoundHandle sfx) = 0; // Gets the length of a sound at its default frequency diff --git a/src/st_stuff.cpp b/src/st_stuff.cpp index a1ac0f290..59b65ef85 100644 --- a/src/st_stuff.cpp +++ b/src/st_stuff.cpp @@ -171,7 +171,7 @@ static BYTE CheatDigitalCafe[] = { 'd','i','g','i','t','a','l','c','a','f','e',2 static BYTE CheatJoshuaStorms[] = { 'j','o','s','h','u','a','s','t','o','r','m','s',255 }; static BYTE CheatLeeSnyder[] = { 'l','e','e','s','n','y','d','e','r',0,0,255 }; static BYTE CheatKimHyers[] = { 'k','i','m','h','y','e','r','s',255 }; -static BYTE CheatShrrill[] = { 's','h','r','r','i','l','l',255 }; +static BYTE CheatShrrill[] = { 's','h','e','r','r','i','l','l',255 }; static BYTE CheatTNTem[] = { 't','n','t','e','m',255 }; @@ -274,8 +274,8 @@ static cheatseq_t ChexCheats[] = { CheatKimHyers, 0, 1, 0, {0,0}, Cht_MyPos }, { CheatShrrill, 0, 0, 0, {0,0}, Cht_AutoMap }, { CheatDavidBrus, 0, 0, 0, {CHT_IDDQD,0}, Cht_Generic }, - { CheatMikeKoenigs, 0, 0, 0, {CHT_IDKFA,0}, Cht_Generic }, - { CheatScottHolman, 0, 0, 0, {CHT_IDFA,0}, Cht_Generic }, + { CheatScottHolman, 0, 0, 0, {CHT_IDKFA,0}, Cht_Generic }, + { CheatMikeKoenigs, 0, 0, 0, {CHT_IDFA,0}, Cht_Generic }, { CheatCharlesJacobi, 0, 0, 0, {CHT_NOCLIP,0}, Cht_Generic }, { CheatAndrewBenson, 0, 0, 0, {CHT_BEHOLDV,0}, Cht_Generic }, { CheatDeanHyers, 0, 0, 0, {CHT_BEHOLDS,0}, Cht_Generic }, diff --git a/src/tarray.h b/src/tarray.h index afea5db1e..b325a640b 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -745,7 +745,11 @@ protected: Node *mp = MainPosition(key), **mpp; HashTraits Traits; - if (!mp->IsNil() && !Traits.Compare(mp->Pair.Key, key)) /* the key is in its main position */ + if (mp->IsNil()) + { + /* the key is definitely not present, because there is nothing at its main position */ + } + else if (!Traits.Compare(mp->Pair.Key, key)) /* the key is in its main position */ { if (mp->Next != NULL) /* move next node to its main position */ { diff --git a/src/textures/buildtexture.cpp b/src/textures/buildtexture.cpp index 21e3cc41f..5f4172a60 100644 --- a/src/textures/buildtexture.cpp +++ b/src/textures/buildtexture.cpp @@ -158,7 +158,7 @@ const BYTE *FBuildTexture::GetColumn (unsigned int column, const Span **spans_ou // //=========================================================================== -static void AddTiles (void *tiles) +void AddTiles (void *tiles) { // int numtiles = LittleLong(((DWORD *)tiles)[1]); // This value is not reliable int tilestart = LittleLong(((DWORD *)tiles)[2]); @@ -224,29 +224,29 @@ static void AddTiles (void *tiles) if (rotType == 1) { spriteframe_t rot; - rot.Texture[0] = texnum; + rot.Texture[0] = rot.Texture[1] = texnum; for (int j = 1; j < 4; ++j) { - rot.Texture[j*2] = texnum + j; - rot.Texture[j*2+1] = texnum + j; - rot.Texture[16-j*2] = texnum + j; - rot.Texture[17-j*2] = texnum + j; + rot.Texture[j*2] = + rot.Texture[j*2+1] = + rot.Texture[16-j*2] = + rot.Texture[17-j*2] = texnum.GetIndex() + j; } - rot.Texture[8] = texnum + 4; - rot.Texture[9] = texnum + 4; + rot.Texture[8] = + rot.Texture[9] = texnum.GetIndex() + 4; rot.Flip = 0x00FC; tex->Rotations = SpriteFrames.Push (rot); } else if (rotType == 2) { spriteframe_t rot; - rot.Texture[0] = texnum; + rot.Texture[0] = rot.Texture[1] = texnum; for (int j = 1; j < 8; ++j) { - rot.Texture[16-j*2] = texnum + j; - rot.Texture[17-j*2] = texnum + j; + rot.Texture[16-j*2] = + rot.Texture[17-j*2] = texnum.GetIndex() + j; } rot.Flip = 0; tex->Rotations = SpriteFrames.Push (rot); diff --git a/src/textures/ddstexture.cpp b/src/textures/ddstexture.cpp index 3d68c4177..f26180f02 100644 --- a/src/textures/ddstexture.cpp +++ b/src/textures/ddstexture.cpp @@ -634,7 +634,7 @@ void FDDSTexture::DecompressDXT1 (FWadLump &lump, BYTE *tcbuf) bMasked = true; } // Pick colors from the palette for each of the four colors. - if (!tcbuf) for (i = 3; i >= 0; --i) + /*if (!tcbuf)*/ for (i = 3; i >= 0; --i) { palcol[i] = color[i].a ? RGB32k[color[i].r >> 3][color[i].g >> 3][color[i].b >> 3] : 0; } @@ -652,18 +652,18 @@ void FDDSTexture::DecompressDXT1 (FWadLump &lump, BYTE *tcbuf) { break; } + int ci = (yslice >> (x + x)) & 3; if (!tcbuf) { - Pixels[oy + y + (ox + x) * Height] = palcol[(yslice >> (x + x)) & 3]; + Pixels[oy + y + (ox + x) * Height] = palcol[ci]; } else { - BYTE * tcp = &tcbuf[ox + x + (oy + y) * Width*4]; - int c = (yslice >> (x + x)) & 3; - tcp[0] = color[c].r; - tcp[1] = color[c].g; - tcp[2] = color[c].b; - tcp[3] = color[c].a; + BYTE * tcp = &tcbuf[(ox + x)*4 + (oy + y) * Width*4]; + tcp[0] = color[ci].r; + tcp[1] = color[ci].g; + tcp[2] = color[ci].b; + tcp[3] = color[ci].a; } } } @@ -740,7 +740,7 @@ void FDDSTexture::DecompressDXT3 (FWadLump &lump, bool premultiplied, BYTE *tcbu } else { - BYTE * tcp = &tcbuf[ox + x + (oy + y) * Width*4]; + BYTE * tcp = &tcbuf[(ox + x)*4 + (oy + y) * Width*4]; int c = (yslice >> (x + x)) & 3; tcp[0] = color[c].r; tcp[1] = color[c].g; @@ -769,7 +769,7 @@ void FDDSTexture::DecompressDXT5 (FWadLump &lump, bool premultiplied, BYTE *tcbu BYTE *block; PalEntry color[4]; BYTE palcol[4]; - DWORD yalphaslice; + DWORD yalphaslice = 0; int ox, oy, x, y, i; for (oy = 0; oy < Height; oy += 4) @@ -831,7 +831,7 @@ void FDDSTexture::DecompressDXT5 (FWadLump &lump, bool premultiplied, BYTE *tcbu break; } // Alpha values are stored in 3 bytes for 2 rows - if ((y & 0) == 0) + if ((y & 1) == 0) { yalphaslice = block[y*3] | (block[y*3+1] << 8) | (block[y*3+2] << 16); } @@ -853,7 +853,7 @@ void FDDSTexture::DecompressDXT5 (FWadLump &lump, bool premultiplied, BYTE *tcbu } else { - BYTE * tcp = &tcbuf[ox + x + (oy + y) * Width*4]; + BYTE * tcp = &tcbuf[(ox + x)*4 + (oy + y) * Width*4]; int c = (yslice >> (x + x)) & 3; tcp[0] = color[c].r; tcp[1] = color[c].g; diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 2d3e2fc9f..34e2f4ae6 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -140,7 +140,9 @@ FTextureID FTextureManager::CheckForTexture (const char *name, int usetype, BITF else { if (firsttype == FTexture::TEX_Null || - (firsttype == FTexture::TEX_MiscPatch && tex->UseType != FTexture::TEX_Null) + (firsttype == FTexture::TEX_MiscPatch && + tex->UseType != firsttype && + tex->UseType != FTexture::TEX_Null) ) { firstfound = i; @@ -1005,7 +1007,7 @@ FArchive &operator<< (FArchive &arc, FTextureID &tex) //========================================================================== // // FTextureID::operator+ -// Does not return incvalid texture IDs +// Does not return invalid texture IDs // //========================================================================== diff --git a/src/textures/textures.h b/src/textures/textures.h index ab4595bf0..053d03fb9 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -41,6 +41,8 @@ protected: FTextureID(int num) { texnum = num; } private: int texnum; + + friend void AddTiles (void *tiles); }; class FNullTextureID : public FTextureID diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 4cc1b9bf7..d9667fb07 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -153,6 +153,12 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par ti->PainChances = new PainChanceList; *ti->PainChances = *parent->PainChances; } + if (parent->ColorSets != NULL) + { + // copy color sets from parent + ti->ColorSets = new FPlayerColorSetMap; + *ti->ColorSets = *parent->ColorSets; + } ti->Replacee = ti->Replacement = NULL; ti->DoomEdNum = -1; return ti; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e76597728..56aa425d1 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1280,7 +1280,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun) self->target->x, self->target->y); } - self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, false, false, false, aim ? self->target : NULL); + self->pitch = P_AimLineAttack (self, self->angle, MISSILERANGE, &linetarget, ANGLE_1*60, 0, aim ? self->target : NULL); if (linetarget == NULL && aim) { // We probably won't hit the target, but aim at it anyway so we don't look stupid. @@ -2016,7 +2016,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) for (int i = 0; i < MAXPLAYERS; i++) { - if (playeringame[i] && P_CheckSight(players[i].camera, self, true)) + if (playeringame[i] && P_CheckSight(players[i].camera, self, SF_IGNOREVISIBILITY)) return 0; } @@ -2024,6 +2024,61 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) return 0; } +//=========================================================================== +// +// A_CheckSightOrRange +// Jumps if this actor is out of range of all players *and* out of sight. +// Useful for maps with many multi-actor special effects. +// +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) +{ + PARAM_ACTION_PROLOGUE; + PARAM_FLOAT(range); + PARAM_STATE(jump); + + ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + + range = range * range * (double(FRACUNIT) * FRACUNIT); // no need for square roots + for (int i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + AActor *camera = players[i].camera; + + // Check distance first, since it's cheaper than checking sight. + double dx = self->x - camera->x; + double dy = self->y - camera->y; + double dz; + fixed_t eyez = (camera->z + camera->height - (camera->height>>2)); // same eye height as P_CheckSight + if (eyez > self->z + self->height) + { + dz = self->z + self->height - eyez; + } + else if (eyez < self->z) + { + dz = self->z - eyez; + } + else + { + dz = 0; + } + if ((dx*dx) + (dy*dy) + (dz*dz) <= range) + { // Within range + return 0; + } + + // Now check LOS. + if (P_CheckSight(camera, self, SF_IGNOREVISIBILITY)) + { // Visible + return 0; + } + } + } + ACTION_JUMP(jump); + return 0; +} + //=========================================================================== // @@ -2493,7 +2548,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInLOS) if (target == NULL) return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case. - if (!P_CheckSight (self, target, 1)) + if (!P_CheckSight (self, target, SF_IGNOREVISIBILITY)) return 0; if (fov && (fov < ANGLE_MAX)) @@ -2555,7 +2610,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfInTargetLOS) if (target == NULL) return 0; // [KS] Let's not call P_CheckSight unnecessarily in this case. - if (!P_CheckSight (target, self, 1)) + if (!P_CheckSight (target, self, SF_IGNOREVISIBILITY)) return 0; if (fov && (fov < ANGLE_MAX)) @@ -2963,7 +3018,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_MonsterRefire) if (self->target == NULL || P_HitFriend (self) || self->target->health <= 0 - || !P_CheckSight(self, self->target, 0) ) + || !P_CheckSight (self, self->target, SF_SEEPASTBLOCKEVERYTHING|SF_SEEPASTSHOOTABLELINES) ) { ACTION_JUMP(jump); } @@ -3132,16 +3187,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserVar) PARAM_NAME (varname); PARAM_INT (value); - PSymbolVariable *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); + PSymbolVariable *var = dyn_cast(stateowner->GetClass()->Symbols.FindSymbol(varname, true)); if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Int) { Printf("%s is not a user variable in class %s\n", varname.GetChars(), - self->GetClass()->TypeName.GetChars()); + stateowner->GetClass()->TypeName.GetChars()); return 0; } // Set the value of the specified user variable. - *(int *)(reinterpret_cast(self) + var->offset) = value; + *(int *)(reinterpret_cast(stateowner) + var->offset) = value; return 0; } @@ -3158,22 +3213,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) PARAM_INT (pos); PARAM_INT (value); - PSymbolVariable *var = dyn_cast(self->GetClass()->Symbols.FindSymbol(varname, true)); + PSymbolVariable *var = dyn_cast(stateowner->GetClass()->Symbols.FindSymbol(varname, true)); if (var == NULL || !var->bUserVar || var->ValueType.Type != VAL_Array || var->ValueType.BaseType != VAL_Int) { Printf("%s is not a user array in class %s\n", varname.GetChars(), - self->GetClass()->TypeName.GetChars()); + stateowner->GetClass()->TypeName.GetChars()); return 0; } if (pos < 0 || pos >= var->ValueType.size) { Printf("%d is out of bounds in array %s in class %s\n", pos, varname.GetChars(), - self->GetClass()->TypeName.GetChars()); + stateowner->GetClass()->TypeName.GetChars()); return 0; } // Set the value of the specified user array at index pos. - ((int *)(reinterpret_cast(self) + var->offset))[pos] = value; + ((int *)(reinterpret_cast(stateowner) + var->offset))[pos] = value; return 0; } diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 1d7018907..01919e85e 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -310,6 +310,7 @@ static FFlagDef WeaponFlags[] = DEFINE_FLAG(WIF, NOAUTOAIM, AWeapon, WeaponFlags), DEFINE_DUMMY_FLAG(NOLMS), + DEFINE_DUMMY_FLAG(ALLOW_WITH_RESPAWN_INVUL), }; static FFlagDef PlayerPawnFlags[] = @@ -612,3 +613,4 @@ void InitThingdef() qsort(&variables[0], variables.Size(), sizeof(variables[0]), varcmp); } } + diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 1a0c0b062..c6f4c285c 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -370,8 +370,7 @@ DEFINE_PROPERTY(painchance, ZI, Actor) if (!stricmp(str, "Normal")) painType = NAME_None; else painType=str; - if (info->PainChances == NULL) info->PainChances=new PainChanceList; - (*info->PainChances)[painType] = (BYTE)id; + info->SetPainChance(painType, id); } } @@ -568,6 +567,15 @@ DEFINE_PROPERTY(howlsound, S, Actor) static_cast(info)->HowlSound = str; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(crushpainsound, S, Actor) +{ + PROP_STRING_PARM(str, 0); + defaults->CrushPainSound = str; +} + //========================================================================== // //========================================================================== @@ -978,13 +986,11 @@ DEFINE_PROPERTY(damagefactor, ZF, Actor) } else { - if (info->DamageFactors == NULL) info->DamageFactors=new DmgFactors; - FName dmgType; if (!stricmp(str, "Normal")) dmgType = NAME_None; else dmgType=str; - (*info->DamageFactors)[dmgType]=id; + info->SetDamageFactor(dmgType, id); } } @@ -1606,6 +1612,15 @@ DEFINE_CLASS_PROPERTY(slotpriority, F, Weapon) static_cast(info)->SlotPriority = i; } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY(preferredskin, S, Weapon) +{ + PROP_STRING_PARM(str, 0); + // NoOp - only for Skulltag compatibility +} + //========================================================================== // //========================================================================== @@ -1892,6 +1907,75 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, colorrange, I_I, PlayerPawn) static_cast(info)->ColorRangeEnd = end; } +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, colorset, ISIII, PlayerPawn) +{ + PROP_INT_PARM(setnum, 0); + PROP_STRING_PARM(setname, 1); + PROP_INT_PARM(rangestart, 2); + PROP_INT_PARM(rangeend, 3); + PROP_INT_PARM(representative_color, 4); + + FPlayerColorSet color; + color.Name = setname; + color.Lump = -1; + color.FirstColor = rangestart; + color.LastColor = rangeend; + color.RepresentativeColor = representative_color; + + if (setnum < 0) + { + bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n"); + } + else + { + info->SetColorSet(setnum, &color); + } +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, colorsetfile, ISSI, PlayerPawn) +{ + PROP_INT_PARM(setnum, 0); + PROP_STRING_PARM(setname, 1); + PROP_STRING_PARM(rangefile, 2); + PROP_INT_PARM(representative_color, 3); + + FPlayerColorSet color; + color.Name = setname; + color.Lump = Wads.CheckNumForName(rangefile); + color.RepresentativeColor = representative_color; + if (setnum < 0) + { + bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n"); + } + else if (color.Lump >= 0) + { + info->SetColorSet(setnum, &color); + } +} + +//========================================================================== +// +//========================================================================== +DEFINE_CLASS_PROPERTY_PREFIX(player, clearcolorset, I, PlayerPawn) +{ + PROP_INT_PARM(setnum, 0); + + if (setnum < 0) + { + bag.ScriptPosition.Message(MSG_WARNING, "Color set number must not be negative.\n"); + } + else + { + info->SetColorSet(setnum, NULL); + } +} + //========================================================================== // //========================================================================== diff --git a/src/v_draw.cpp b/src/v_draw.cpp index e46a99d12..42b0b5145 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -527,6 +527,10 @@ bool DCanvas::ParseDrawTextureTags (FTexture *img, double x, double y, DWORD tag case DTA_Translation: parms->remap = va_arg(tags, FRemapTable *); + if (parms->remap != NULL && parms->remap->Inactive) + { // If it's inactive, pretend we were passed NULL instead. + parms->remap = NULL; + } break; case DTA_ColorOverlay: diff --git a/src/v_font.cpp b/src/v_font.cpp index ead32a8c5..ea6feb149 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -130,7 +130,10 @@ protected: bool rescale, PalEntry *out_palette); void LoadFON1 (int lump, const BYTE *data); void LoadFON2 (int lump, const BYTE *data); + void LoadBMF (int lump, const BYTE *data); void CreateFontFromPic (FTextureID picnum); + + static int STACK_ARGS BMFCompare(const void *a, const void *b); }; class FSinglePicFont : public FFont @@ -175,7 +178,7 @@ protected: class FFontChar2 : public FTexture { public: - FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height); + FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height, int leftofs=0, int topofs=0); ~FFontChar2 (); const BYTE *GetColumn (unsigned int column, const Span **spans_out); @@ -261,12 +264,13 @@ FFont *V_GetFont(const char *name) if (lump != -1) { - char head[3]; + uint32 head; { FWadLump lumpy = Wads.OpenLumpNum (lump); - lumpy.Read (head, 3); + lumpy.Read (&head, 4); } - if (head[0] == 'F' && head[1] == 'O' && head[2] == 'N') + if ((head & MAKE_ID(255,255,255,0)) == MAKE_ID('F','O','N',0) || + head == MAKE_ID(0xE1,0xE6,0xD5,0x1A)) { font = new FSingleLumpFont (name, lump); } @@ -399,21 +403,26 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, if (charlumps[i] != NULL) { Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap); + Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); } else { Chars[i].Pic = NULL; + Chars[i].XMove = INT_MIN; } } - if ('N'-first>=0 && 'N'-first= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL) { - SpaceWidth = (Chars['N' - first].Pic->GetScaledWidth() + 1) / 2; + SpaceWidth = (Chars['N' - first].XMove + 1) / 2; } else { SpaceWidth = 4; } + + FixXMoves(); + BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, NULL); delete[] luminosity; @@ -717,6 +726,33 @@ FRemapTable *FFont::GetColorTranslation (EColorRange range) const return &Ranges[range]; } +//========================================================================== +// +// FFont :: GetCharCode +// +// If the character code is in the font, returns it. If it is not, but it +// is lowercase and has an uppercase variant present, return that. Otherwise +// return -1. +// +//========================================================================== + +int FFont::GetCharCode(int code, bool needpic) const +{ + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL)) + { + return code; + } + if (myislower[code]) + { + code -= 32; + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL)) + { + return code; + } + } + return -1; +} + //========================================================================== // // FFont :: GetChar @@ -725,31 +761,28 @@ FRemapTable *FFont::GetColorTranslation (EColorRange range) const FTexture *FFont::GetChar (int code, int *const width) const { - if (code < FirstChar || - code > LastChar || - Chars[code - FirstChar].Pic == NULL) + code = GetCharCode(code, false); + int xmove = SpaceWidth; + + if (code >= 0) { - if (myislower[code]) + code -= FirstChar; + xmove = Chars[code].XMove; + if (Chars[code].Pic == NULL) { - code -= 32; - if (code < FirstChar || - code > LastChar || - Chars[code - FirstChar].Pic == NULL) + code = GetCharCode(code + FirstChar, true); + if (code >= 0) { - if (width != NULL) *width = SpaceWidth; - return NULL; + code -= FirstChar; + xmove = Chars[code].XMove; } } - else - { - if (width != NULL) *width = SpaceWidth; - return NULL; - } } - - code -= FirstChar; - if (width != NULL) *width = Chars[code].Pic->GetScaledWidth(); - return Chars[code].Pic; + if (width != NULL) + { + *width = xmove; + } + return (code < 0) ? NULL : Chars[code].Pic; } //========================================================================== @@ -760,27 +793,8 @@ FTexture *FFont::GetChar (int code, int *const width) const int FFont::GetCharWidth (int code) const { - if (code < FirstChar || - code > LastChar || - Chars[code - FirstChar].Pic == NULL) - { - if (myislower[code]) - { - code -= 32; - if (code < FirstChar || - code > LastChar || - Chars[code - FirstChar].Pic == NULL) - { - return SpaceWidth; - } - } - else - { - return SpaceWidth; - } - } - - return Chars[code - FirstChar].Pic->GetScaledWidth(); + code = GetCharCode(code, false); + return (code < 0) ? SpaceWidth : Chars[code - FirstChar].XMove; } //========================================================================== @@ -858,7 +872,11 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) FMemLump data1 = Wads.ReadLump (lump); const BYTE *data = (const BYTE *)data1.GetMem(); - if (data[0] != 'F' || data[1] != 'O' || data[2] != 'N' || + if (data[0] == 0xE1 && data[1] == 0xE6 && data[2] == 0xD5 && data[3] == 0x1A) + { + LoadBMF(lump, data); + } + else if (data[0] != 'F' || data[1] != 'O' || data[2] != 'N' || (data[3] != '1' && data[3] != '2')) { I_FatalError ("%s is not a recognizable font", name); @@ -1012,6 +1030,7 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) for (i = 0; i < count; ++i) { int destSize = widths2[i] * FontHeight; + Chars[i].XMove = widths2[i]; if (destSize <= 0) { Chars[i].Pic = NULL; @@ -1045,6 +1064,157 @@ void FSingleLumpFont::LoadFON2 (int lump, const BYTE *data) delete[] widths2; } +//========================================================================== +// +// FSingleLumpFont :: LoadBMF +// +// Loads a BMF font. The file format is described at +// +// +//========================================================================== + +void FSingleLumpFont::LoadBMF(int lump, const BYTE *data) +{ + const BYTE *chardata; + int numchars, count, totalwidth, nwidth; + int infolen; + int i, chari; + BYTE raw_palette[256*3]; + PalEntry sort_palette[256]; + PalEntry local_palette[256]; + double luminosity[256]; + BYTE identity[256]; + + FontHeight = data[5]; + GlobalKerning = (SBYTE)data[8]; + ActiveColors = data[16]; + SpaceWidth = -1; + nwidth = -1; + + infolen = data[17 + ActiveColors*3]; + chardata = data + 18 + ActiveColors*3 + infolen; + numchars = chardata[0] + 256*chardata[1]; + chardata += 2; + + // Scan for lowest and highest characters defined and total font width. + FirstChar = 256; + LastChar = 0; + totalwidth = 0; + for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2]) + { + if ((chardata[chari+1] == 0 || chardata[chari+2] == 0) && chardata[chari+5] == 0) + { // Don't count empty characters. + continue; + } + if (chardata[chari] < FirstChar) + { + FirstChar = chardata[chari]; + } + if (chardata[chari] > LastChar) + { + LastChar = chardata[chari]; + } + totalwidth += chardata[chari+1]; + } + if (LastChar < FirstChar) + { + I_FatalError("BMF font defines no characters"); + } + count = LastChar - FirstChar + 1; + Chars = new CharData[count]; + for (i = 0; i < count; ++i) + { + Chars[i].Pic = NULL; + Chars[i].XMove = INT_MIN; + } + + // BMF palettes are only six bits per component. Fix that. + for (i = 0; i < ActiveColors*3; ++i) + { + raw_palette[i] = (data[17 + i] << 2) | (data[17 + i] >> 4); + } + + // Sort the palette by increasing brightness + for (i = 0; i < ActiveColors; ++i) + { + PalEntry *pal = &sort_palette[i]; + pal->a = i; // Use alpha part to point back to original entry + pal->r = raw_palette[i*3 + 0]; + pal->g = raw_palette[i*3 + 1]; + pal->b = raw_palette[i*3 + 2]; + } + qsort(sort_palette + 1, ActiveColors - 1, sizeof(PalEntry), BMFCompare); + + // Create the PatchRemap table from the sorted "alpha" values. + PatchRemap = new BYTE[ActiveColors]; + PatchRemap[0] = 0; + for (i = 1; i < ActiveColors; ++i) + { + PatchRemap[sort_palette[i].a] = i; + } + + FixupPalette(identity, luminosity, raw_palette, true, local_palette); + + // Now scan through the characters again, creating glyphs for each one. + for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2]) + { + assert(chardata[chari] - FirstChar >= 0); + assert(chardata[chari] - FirstChar < count); + if (chardata[chari] == ' ') + { + SpaceWidth = chardata[chari+5]; + } + else if (chardata[chari] == 'N') + { + nwidth = chardata[chari+5]; + } + Chars[chardata[chari] - FirstChar].XMove = chardata[chari+5]; + if (chardata[chari+1] == 0 || chardata[chari+2] == 0) + { // Empty character: skip it. + continue; + } + Chars[chardata[chari] - FirstChar].Pic = new FFontChar2(lump, PatchRemap, int(chardata + chari + 6 - data), + chardata[chari+1], // width + chardata[chari+2], // height + -(SBYTE)chardata[chari+3], // x offset + -(SBYTE)chardata[chari+4] // y offset + ); + } + + // If the font did not define a space character, determine a suitable space width now. + if (SpaceWidth < 0) + { + if (nwidth >= 0) + { + SpaceWidth = nwidth; + } + else + { + SpaceWidth = totalwidth * 2 / (3 * count); + } + } + + FixXMoves(); + BuildTranslations(luminosity, identity, &TranslationParms[0][0], ActiveColors, local_palette); +} + +//========================================================================== +// +// FSingleLumpFont :: BMFCompare STATIC +// +// Helper to sort BMF palettes. +// +//========================================================================== + +int STACK_ARGS FSingleLumpFont::BMFCompare(const void *a, const void *b) +{ + const PalEntry *pa = (const PalEntry *)a; + const PalEntry *pb = (const PalEntry *)b; + + return (pa->r * 299 + pa->g * 587 + pa->b * 114) - + (pb->r * 299 + pb->g * 587 + pb->b * 114); +} + //========================================================================== // // FSingleLumpFont :: CheckFON1Chars @@ -1069,6 +1239,7 @@ void FSingleLumpFont::CheckFON1Chars (int lump, const BYTE *data, double *lumino int destSize = SpaceWidth * FontHeight; Chars[i].Pic = new FFontChar2 (lump, PatchRemap, int(data_p - data), SpaceWidth, FontHeight); + Chars[i].XMove = SpaceWidth; // Advance to next char's data and count the used colors. do @@ -1181,8 +1352,8 @@ FSinglePicFont::FSinglePicFont(const char *picname) FTexture *pic = TexMan[picnum]; Name = copystring(picname); - FontHeight = pic->GetHeight(); - SpaceWidth = pic->GetWidth(); + FontHeight = pic->GetScaledHeight(); + SpaceWidth = pic->GetScaledWidth(); GlobalKerning = 0; FirstChar = LastChar = 'A'; ActiveColors = 0; @@ -1332,14 +1503,14 @@ FFontChar1::~FFontChar1 () // //========================================================================== -FFontChar2::FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height) +FFontChar2::FFontChar2 (int sourcelump, const BYTE *sourceremap, int sourcepos, int width, int height, int leftofs, int topofs) : SourceLump (sourcelump), SourcePos (sourcepos), Pixels (0), Spans (0), SourceRemap(sourceremap) { UseType = TEX_FontChar; Width = width; Height = height; - TopOffset = 0; - LeftOffset = 0; + LeftOffset = leftofs; + TopOffset = topofs; CalcBitSize (); } @@ -1427,10 +1598,11 @@ void FFontChar2::MakeTexture () FWadLump lump = Wads.OpenLumpNum (SourceLump); int destSize = Width * Height; BYTE max = 255; + bool rle = true; // This is to "fix" bad fonts { - BYTE buff[8]; + BYTE buff[16]; lump.Read (buff, 4); if (buff[3] == '2') { @@ -1438,6 +1610,13 @@ void FFontChar2::MakeTexture () max = buff[6]; lump.Seek (SourcePos - 11, SEEK_CUR); } + else if (buff[3] == 0x1A) + { + lump.Read(buff, 13); + max = buff[12] - 1; + lump.Seek (SourcePos - 17, SEEK_CUR); + rle = false; + } else { lump.Seek (SourcePos - 4, SEEK_CUR); @@ -1452,55 +1631,81 @@ void FFontChar2::MakeTexture () int dest_adv = Height; int dest_rew = destSize - 1; - for (int y = Height; y != 0; --y) + if (rle) { - for (int x = Width; x != 0; ) + for (int y = Height; y != 0; --y) { - if (runlen != 0) + for (int x = Width; x != 0; ) { - BYTE color; - - lump >> color; - *dest_p = MIN (color, max); - if (SourceRemap != NULL) - { - *dest_p = SourceRemap[*dest_p]; - } - dest_p += dest_adv; - x--; - runlen--; - } - else if (setlen != 0) - { - *dest_p = setval; - dest_p += dest_adv; - x--; - setlen--; - } - else - { - SBYTE code; - - lump >> code; - if (code >= 0) - { - runlen = code + 1; - } - else if (code != -128) + if (runlen != 0) { BYTE color; lump >> color; - setlen = (-code) + 1; - setval = MIN (color, max); + color = MIN (color, max); if (SourceRemap != NULL) { - setval = SourceRemap[setval]; + color = SourceRemap[color]; + } + *dest_p = color; + dest_p += dest_adv; + x--; + runlen--; + } + else if (setlen != 0) + { + *dest_p = setval; + dest_p += dest_adv; + x--; + setlen--; + } + else + { + SBYTE code; + + lump >> code; + if (code >= 0) + { + runlen = code + 1; + } + else if (code != -128) + { + BYTE color; + + lump >> color; + setlen = (-code) + 1; + setval = MIN (color, max); + if (SourceRemap != NULL) + { + setval = SourceRemap[setval]; + } } } } + dest_p -= dest_rew; + } + } + else + { + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + BYTE color; + lump >> color; + if (color > max) + { + color = max; + } + if (SourceRemap != NULL) + { + color = SourceRemap[color]; + } + *dest_p = color; + dest_p += dest_adv; + } + dest_p -= dest_rew; } - dest_p -= dest_rew; } if (destSize < 0) @@ -1593,23 +1798,27 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l if (charlumps[i] != NULL) { Chars[i].Pic = new FFontChar1 (charlumps[i], PatchRemap); + Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); } else { Chars[i].Pic = NULL; + Chars[i].XMove = INT_MIN; } } // Special fonts normally don't have all characters so be careful here! - if ('N'-first>=0 && 'N'-first= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL) { - SpaceWidth = (Chars['N' - first].Pic->GetScaledWidth() + 1) / 2; + SpaceWidth = (Chars['N' - first].XMove + 1) / 2; } else { SpaceWidth = 4; } + FixXMoves(); + BuildTranslations (luminosity, identity, &TranslationParms[0][0], TotalColors, NULL); // add the untranslated colors to the Ranges tables @@ -1632,6 +1841,36 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l delete[] charlumps; } +//========================================================================== +// +// FFont :: FixXMoves +// +// If a font has gaps in its characters, set the missing characters' +// XMoves to either SpaceWidth or the uppercase variant's XMove. Missing +// XMoves must be initialized with INT_MIN beforehand. +// +//========================================================================== + +void FFont::FixXMoves() +{ + for (int i = 0; i <= LastChar - FirstChar; ++i) + { + if (Chars[i].XMove == INT_MIN) + { + if (myislower[i + FirstChar]) + { + int upper = i - 32; + if (upper >= 0) + { + Chars[i].XMove = Chars[upper].XMove; + continue; + } + } + Chars[i].XMove = SpaceWidth; + } + } +} + //========================================================================== // diff --git a/src/v_font.h b/src/v_font.h index 123b70ff1..4cdba31af 100644 --- a/src/v_font.h +++ b/src/v_font.h @@ -94,11 +94,14 @@ public: int StringWidth (const BYTE *str) const; inline int StringWidth (const char *str) const { return StringWidth ((const BYTE *)str); } + int GetCharCode(int code, bool needpic) const; + protected: FFont (); void BuildTranslations (const double *luminosity, const BYTE *identity, const void *ranges, int total_colors, const PalEntry *palette); + void FixXMoves(); static int SimpleTranslation (BYTE *colorsused, BYTE *translation, BYTE *identity, double **luminosity); @@ -110,6 +113,7 @@ protected: struct CharData { FTexture *Pic; + int XMove; } *Chars; int ActiveColors; TArray Ranges; diff --git a/src/v_text.cpp b/src/v_text.cpp index be386e992..55dbcc774 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -276,7 +276,7 @@ int FFont::StringWidth (const BYTE *string) const ++string; } } - else if (*string != '\0') + if (*string != '\0') { ++string; } @@ -317,14 +317,15 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string) FBrokenLines lines[128]; // Support up to 128 lines (should be plenty) const BYTE *space = NULL, *start = string; - int i, c, w, nw; + size_t i, ii; + int c, w, nw; FString lastcolor, linecolor; bool lastWasSpace = false; int kerning = font->GetDefaultKerning (); i = w = 0; - while ( (c = *string++) && i < 128 ) + while ( (c = *string++) && i < countof(lines) ) { if (c == TEXTCOLOR_ESCAPE) { @@ -400,7 +401,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string) } // String here is pointing one character after the '\0' - if (i < 128 && --string - start >= 1) + if (i < countof(lines) && --string - start >= 1) { const BYTE *s = start; @@ -418,11 +419,11 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string) // Make a copy of the broken lines and return them FBrokenLines *broken = new FBrokenLines[i+1]; - for (c = 0; c < i; ++c) + for (ii = 0; ii < i; ++ii) { - broken[c] = lines[c]; + broken[ii] = lines[ii]; } - broken[c].Width = -1; + broken[ii].Width = -1; return broken; } diff --git a/src/v_video.cpp b/src/v_video.cpp index f6e0eb546..24ed1a562 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1523,7 +1523,7 @@ CCMD (vid_setmode) void V_Init (void) { - char *i; + const char *i; int width, height, bits; atterm (V_Shutdown); diff --git a/src/w_wad.cpp b/src/w_wad.cpp index bb8deb384..5727c8bcc 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -848,6 +848,46 @@ int FWadCollection::FindLump (const char *name, int *lastlump, bool anyns) return -1; } +//========================================================================== +// +// W_FindLumpMulti +// +// Find a named lump. Specifically allows duplicates for merging of e.g. +// SNDINFO lumps. Returns everything having one of the passed names. +// +//========================================================================== + +int FWadCollection::FindLumpMulti (const char **names, int *lastlump, bool anyns, int *nameindex) +{ + LumpRecord *lump_p; + + assert(lastlump != NULL && *lastlump >= 0); + lump_p = &LumpInfo[*lastlump]; + while (lump_p < &LumpInfo[NumLumps]) + { + FResourceLump *lump = lump_p->lump; + + if (anyns || lump->Namespace == ns_global) + { + + for(const char **name = names; *name != NULL; name++) + { + if (!strnicmp(*name, lump->Name, 8)) + { + int lump = int(lump_p - &LumpInfo[0]); + *lastlump = lump + 1; + if (nameindex != NULL) *nameindex = int(name - names); + return lump; + } + } + } + lump_p++; + } + + *lastlump = NumLumps; + return -1; +} + //========================================================================== // // W_CheckLumpName @@ -927,6 +967,24 @@ int FWadCollection::GetLumpNamespace (int lump) const return LumpInfo[lump].lump->Namespace; } +//========================================================================== +// +// FWadCollection :: GetLumpIndexNum +// +// Returns the index number for this lump. This is *not* the lump's position +// in the lump directory, but rather a special value that RFF can associate +// with files. Other archive types will return 0, since they don't have it. +// +//========================================================================== + +int FWadCollection::GetLumpIndexNum(int lump) const +{ + if ((size_t)lump >= NumLumps) + return 0; + else + return LumpInfo[lump].lump->GetIndexNum(); +} + //========================================================================== // // W_GetLumpFile diff --git a/src/w_wad.h b/src/w_wad.h index 2edd71587..dc1ea7794 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -182,6 +182,7 @@ public: FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication + int FindLumpMulti (const char **names, int *lastlump, bool anyns = false, int *nameindex = NULL); // same with multiple possible names bool CheckLumpName (int lump, const char *name); // [RH] True if lump's name == name static DWORD LumpNameHash (const char *name); // [RH] Create hash key from an 8-char name @@ -194,6 +195,7 @@ public: FString GetLumpFullPath (int lump) const; // [RH] Returns wad's name + lump's full name int GetLumpFile (int lump) const; // [RH] Returns wadnum for a specified lump int GetLumpNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to + int GetLumpIndexNum (int lump) const; // Returns the RFF index number for this lump bool CheckLumpName (int lump, const char *name) const; // [RH] Returns true if the names match bool IsUncompressedFile(int lump) const; diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index a01d15346..7c07ae783 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -1935,15 +1935,13 @@ void WI_loadData(void) } else { - int dummywidth; - star = BigFont->GetChar('*', &dummywidth); // just a dummy to avoid an error if it is being used + star = BigFont->GetChar('*', NULL); bstar = star; } } else // Strife needs some handling, too! { - int dummywidth; - star = BigFont->GetChar('*', &dummywidth); // just a dummy to avoid an error if it is being used + star = BigFont->GetChar('*', NULL); bstar = star; } diff --git a/src/win32/i_crash.cpp b/src/win32/i_crash.cpp index 5996be87a..727e4b7ed 100644 --- a/src/win32/i_crash.cpp +++ b/src/win32/i_crash.cpp @@ -503,6 +503,71 @@ void __cdecl Writef (HANDLE file, const char *format, ...) WriteFile (file, buffer, len, &len, NULL); } +//========================================================================== +// +// WriteLogFileStreamer +// +// The callback function to stream a Rich Edit's contents to a file. +// +//========================================================================== + +static DWORD CALLBACK WriteLogFileStreamer(DWORD_PTR cookie, LPBYTE buffer, LONG cb, LONG *pcb) +{ + DWORD didwrite; + LONG p, pp; + + // Replace gray foreground color with black. + static const char *badfg = "\\red223\\green223\\blue223;"; + // 4321098 765432109 876543210 + // 2 1 0 + for (p = pp = 0; p < cb; ++p) + { + if (buffer[p] == badfg[pp]) + { + ++pp; + if (pp == 25) + { + buffer[p - 1] = buffer[p - 2] = buffer[p - 3] = + buffer[p - 9] = buffer[p -10] = buffer[p -11] = + buffer[p -18] = buffer[p -19] = buffer[p -20] = '0'; + break; + } + } + else + { + pp = 0; + } + } + + if (!WriteFile((HANDLE)cookie, buffer, cb, &didwrite, NULL)) + { + return 1; + } + *pcb = didwrite; + return 0; +} + +//========================================================================== +// +// WriteLogFile +// +// Writes the contents of a Rich Edit control to a file. +// +//========================================================================== + +HANDLE WriteLogFile(HWND edit) +{ + HANDLE file; + + file = CreateTempFile(); + if (file != INVALID_HANDLE_VALUE) + { + EDITSTREAM streamer = { (DWORD_PTR)file, 0, WriteLogFileStreamer }; + SendMessage(edit, EM_STREAMOUT, SF_RTF, (LPARAM)&streamer); + } + return file; +} + //========================================================================== // // CreateCrashLog @@ -511,7 +576,7 @@ void __cdecl Writef (HANDLE file, const char *format, ...) // //========================================================================== -void CreateCrashLog (char *custominfo, DWORD customsize) +void CreateCrashLog (char *custominfo, DWORD customsize, HWND richlog) { // Do not collect information more than once. if (NumFiles != 0) @@ -561,6 +626,10 @@ void CreateCrashLog (char *custominfo, DWORD customsize) AddFile (file, "local.txt"); } } + if (richlog != NULL) + { + AddFile (WriteLogFile(richlog), "log.rtf"); + } CloseHandle (DbgProcess); } @@ -1984,7 +2053,6 @@ static INT_PTR CALLBACK CrashDlgProc (HWND hDlg, UINT message, WPARAM wParam, LP static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { - HGDIOBJ font; HWND ctrl; int i, j; @@ -1996,15 +2064,9 @@ static INT_PTR CALLBACK DetailsDlgProc (HWND hDlg, UINT message, WPARAM wParam, pEnableThemeDialogTexture (hDlg, ETDT_ENABLETAB); } - // Set up the file contents display: Use a fixed width font, - // no undos. The control's userdata stores the index of the - // file currently displayed. + // Set up the file contents display: No undos. The control's + // userdata stores the index of the file currently displayed. ctrl = GetDlgItem (hDlg, IDC_CRASHFILECONTENTS); - font = GetStockObject (ANSI_FIXED_FONT); - if (font != INVALID_HANDLE_VALUE) - { - SendMessage (ctrl, WM_SETFONT, (WPARAM)font, FALSE); - } SendMessage (ctrl, EM_SETUNDOLIMIT, 0, 0); SetWindowLongPtr (ctrl, GWLP_USERDATA, -1); SetEditControl (ctrl, GetDlgItem(hDlg, IDC_CRASHFILESIZE), 0); @@ -2178,6 +2240,8 @@ static void SetEditControl (HWND edit, HWND sizedisplay, int filenum) EDITSTREAM stream; DWORD size; POINT pt = { 0, 0 }; + const char *rtf = NULL; + HGDIOBJ font; // Don't refresh the control if it's already showing the file we want. if (GetWindowLongPtr (edit, GWLP_USERDATA) == filenum) @@ -2201,10 +2265,19 @@ static void SetEditControl (HWND edit, HWND sizedisplay, int filenum) SetFilePointer (TarFiles[filenum].File, 0, NULL, FILE_BEGIN); SendMessage (edit, EM_SETSCROLLPOS, 0, (LPARAM)&pt); + // Set the font now, in case log.rtf was previously viewed, because + // that file changes it. + font = GetStockObject (ANSI_FIXED_FONT); + if (font != INVALID_HANDLE_VALUE) + { + SendMessage (edit, WM_SETFONT, (WPARAM)font, FALSE); + } + // Text files are streamed in as-is. // Binary files are streamed in as color-coded hex dumps. stream.dwError = 0; - if (strstr (TarFiles[filenum].Filename, ".txt") != NULL) + if (strstr (TarFiles[filenum].Filename, ".txt") != NULL || + (rtf = strstr (TarFiles[filenum].Filename, ".rtf")) != NULL) { CHARFORMAT beBlack; @@ -2215,7 +2288,7 @@ static void SetEditControl (HWND edit, HWND sizedisplay, int filenum) SendMessage (edit, EM_SETCHARFORMAT, 0, (LPARAM)&beBlack); stream.dwCookie = (DWORD_PTR)TarFiles[filenum].File; stream.pfnCallback = StreamEditText; - SendMessage (edit, EM_STREAMIN, SF_TEXT, (LPARAM)&stream); + SendMessage (edit, EM_STREAMIN, rtf ? SF_RTF : SF_TEXT | SF_USECODEPAGE | (1252 << 16), (LPARAM)&stream); } else { diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index aa4af6a3d..18b3990f1 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -105,7 +105,7 @@ // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); -void CreateCrashLog (char *custominfo, DWORD customsize); +void CreateCrashLog (char *custominfo, DWORD customsize, HWND richedit); void DisplayCrashLog (); extern BYTE *ST_Util_BitsForBitmap (BITMAPINFO *bitmap_info); @@ -423,7 +423,7 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) TEXTMETRIC tm; HINSTANCE inst = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_HINSTANCE); DRAWITEMSTRUCT *drawitem; - CHARFORMAT2 format; + CHARFORMAT2W format; switch (msg) { @@ -454,7 +454,7 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) SelectObject (hdc, oldfont); // Create log read-only edit control - view = CreateWindowEx (WS_EX_NOPARENTNOTIFY, RICHEDIT_CLASS, NULL, + view = CreateWindowEx (WS_EX_NOPARENTNOTIFY, "RichEdit20W", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | WS_CLIPSIBLINGS, 0, 0, 0, 0, @@ -472,13 +472,14 @@ LRESULT CALLBACK LConProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) // Setup default font for the log. //SendMessage (view, WM_SETFONT, (WPARAM)GetStockObject (DEFAULT_GUI_FONT), FALSE); format.cbSize = sizeof(format); - format.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_SIZE; + format.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_SIZE | CFM_CHARSET; format.dwEffects = 0; format.yHeight = 200; format.crTextColor = RGB(223,223,223); + format.bCharSet = ANSI_CHARSET; format.bPitchAndFamily = FF_SWISS | VARIABLE_PITCH; - strcpy (format.szFaceName, "Bitstream Vera Sans"); // At least I have it. :p - SendMessage (view, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&format); + wcscpy(format.szFaceName, L"DejaVu Sans"); // At least I have it. :p + SendMessageW(view, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&format); ConWindow = view; ReleaseDC (hWnd, hdc); @@ -1176,7 +1177,7 @@ LONG WINAPI CatchAllExceptions (LPEXCEPTION_POINTERS info) CrashPointers = *info; DoomSpecificInfo (custominfo, 16384); - CreateCrashLog (custominfo, (DWORD)strlen(custominfo)); + CreateCrashLog (custominfo, (DWORD)strlen(custominfo), ConWindow); // If the main thread crashed, then make it clean up after itself. // Otherwise, put the crashing thread to sleep and signal the main thread to clean up. @@ -1248,7 +1249,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n *(int *)0 = 0; } __except(CrashPointers = *GetExceptionInformation(), - CreateCrashLog (__argv[1], 9), EXCEPTION_EXECUTE_HANDLER) + CreateCrashLog (__argv[1], 9, NULL), EXCEPTION_EXECUTE_HANDLER) { } DisplayCrashLog (); @@ -1261,7 +1262,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n infiniterecursion(1); } __except(CrashPointers = *GetExceptionInformation(), - CreateCrashLog (__argv[1], 14), EXCEPTION_EXECUTE_HANDLER) + CreateCrashLog (__argv[1], 14, NULL), EXCEPTION_EXECUTE_HANDLER) { } DisplayCrashLog (); @@ -1291,7 +1292,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE nothing, LPSTR cmdline, int n _CrtSetDbgFlag (_CrtSetDbgFlag(0) | _CRTDBG_LEAK_CHECK_DF); // Use this to break at a specific allocation number. - //_crtBreakAlloc = 68843; + //_crtBreakAlloc = 30055; #endif DoMain (hInstance); diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 6320c33f5..04e2694d6 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -233,7 +233,7 @@ static void I_SelectTimer() if (NewTicArrived) { UINT delay; - char *cmdDelay; + const char *cmdDelay; cmdDelay = Args->CheckValue("-timerdelay"); delay = 0; @@ -832,6 +832,74 @@ void I_SetIWADInfo(const IWADInfo *info) LayoutMainWindow(Window, NULL); } +//========================================================================== +// +// ToEditControl +// +// Converts string to Unicode and inserts it into the control. +// +//========================================================================== + +void ToEditControl(HWND edit, const char *buf, wchar_t *wbuf, int bpos) +{ + // Let's just do this ourself. It's not hard, and we can compensate for + // special console characters at the same time. +#if 0 + MultiByteToWideChar(1252 /* Western */, 0, buf, bpos, wbuf, countof(wbuf)); + wbuf[bpos] = 0; +#else + static wchar_t notlatin1[32] = // code points 0x80-0x9F + { + 0x20AC, // Euro sign + 0x0081, // Undefined + 0x201A, // Single low-9 quotation mark + 0x0192, // Latin small letter f with hook + 0x201E, // Double low-9 quotation mark + 0x2026, // Horizontal ellipsis + 0x2020, // Dagger + 0x2021, // Double dagger + 0x02C6, // Modifier letter circumflex accent + 0x2030, // Per mille sign + 0x0160, // Latin capital letter S with caron + 0x2039, // Single left-pointing angle quotation mark + 0x0152, // Latin capital ligature OE + 0x008D, // Undefined + 0x017D, // Latin capital letter Z with caron + 0x008F, // Undefined + 0x0090, // Undefined + 0x2018, // Left single quotation mark + 0x2019, // Right single quotation mark + 0x201C, // Left double quotation mark + 0x201D, // Right double quotation mark + 0x2022, // Bullet + 0x2013, // En dash + 0x2014, // Em dash + 0x02DC, // Small tilde + 0x2122, // Trade mark sign + 0x0161, // Latin small letter s with caron + 0x203A, // Single right-pointing angle quotation mark + 0x0153, // Latin small ligature oe + 0x009D, // Undefined + 0x017E, // Latin small letter z with caron + 0x0178 // Latin capital letter Y with diaeresis + }; + for (int i = 0; i <= bpos; ++i) + { + wchar_t code = (BYTE)buf[i]; + if (code >= 0x1D && code <= 0x1F) + { // The bar characters, most commonly used to indicate map changes + code = 0x2550; // Box Drawings Double Horizontal + } + else if (code >= 0x80 && code <= 0x9F) + { + code = notlatin1[code - 0x80]; + } + wbuf[i] = code; + } +#endif + SendMessageW(edit, EM_REPLACESEL, FALSE, (LPARAM)wbuf); +} + //========================================================================== // // I_PrintStr @@ -848,6 +916,7 @@ void I_PrintStr(const char *cp) HWND edit = ConWindow; char buf[256]; + wchar_t wbuf[countof(buf)]; int bpos = 0; CHARRANGE selection; CHARRANGE endselection; @@ -877,7 +946,7 @@ void I_PrintStr(const char *cp) buf[bpos] = 0; if (edit != NULL) { - SendMessage(edit, EM_REPLACESEL, FALSE, (LPARAM)buf); + ToEditControl(edit, buf, wbuf, bpos); } if (StdOut != NULL) { @@ -944,7 +1013,7 @@ void I_PrintStr(const char *cp) buf[bpos] = 0; if (edit != NULL) { - SendMessage(edit, EM_REPLACESEL, FALSE, (LPARAM)buf); + ToEditControl(edit, buf, wbuf, bpos); } if (StdOut != NULL) { diff --git a/src/win32/st_start.cpp b/src/win32/st_start.cpp index d343fb2b4..8fe844f70 100644 --- a/src/win32/st_start.cpp +++ b/src/win32/st_start.cpp @@ -51,6 +51,7 @@ #include "gi.h" #include "w_wad.h" #include "s_sound.h" +#include "m_argv.h" // MACROS ------------------------------------------------------------------ @@ -152,10 +153,15 @@ class FHexenStartupScreen : public FGraphicalStartupScreen { public: FHexenStartupScreen(int max_progress, HRESULT &hr); + ~FHexenStartupScreen(); void Progress(); void NetProgress(int count); void NetDone(); + + // Hexen's notch graphics, converted to chunky pixels. + BYTE * NotchBits; + BYTE * NetNotchBits; }; class FStrifeStartupScreen : public FGraphicalStartupScreen @@ -252,55 +258,6 @@ static const RGBQUAD TextModePalette[16] = { HI, HI, HI, 0 }, // F white }; -// Hexen's notch graphics, converted to chunky pixels. - -static const BYTE NotchBits[] = -{ - 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x68, 0x86, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x78, 0x87, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd8, 0x8d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd8, 0x8d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd8, 0x8d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd8, 0x8d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd8, 0x87, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xd7, 0x7d, 0x60, 0x00, 0x00, - 0x00, 0x66, 0x99, 0x99, 0x96, 0x69, 0x66, 0x00, - 0x00, 0x69, 0x96, 0x99, 0x69, 0x96, 0x96, 0x00, - 0x06, 0x9d, 0x99, 0x69, 0x96, 0xd9, 0x79, 0x60, - 0x06, 0x7d, 0xdd, 0xdd, 0xdd, 0xdd, 0x77, 0x60, - 0x06, 0x78, 0x88, 0x88, 0x88, 0x88, 0xd6, 0x60, - 0x06, 0x7a, 0xaa, 0xaa, 0xaa, 0xaa, 0xd6, 0x60, - 0x06, 0x7a, 0x77, 0x77, 0x77, 0xa7, 0x96, 0x60, - 0x06, 0x77, 0xa7, 0x77, 0x77, 0xa7, 0x96, 0x60, - 0x06, 0x97, 0xa7, 0x79, 0x77, 0x77, 0x96, 0x60, - 0x00, 0x67, 0x79, 0x99, 0x99, 0xd7, 0x96, 0x60, - 0x00, 0x69, 0x99, 0x66, 0x69, 0x69, 0x66, 0x00 -}; - -static const BYTE NetNotchBits[] = -{ - 0x52, 0x20, - 0x23, 0x25, - 0x33, 0x25, - 0x31, 0x35, - 0x31, 0x35, - 0x31, 0x35, - 0x33, 0x35, - 0x31, 0x35, - 0x31, 0x35, - 0x31, 0x25, - 0x33, 0x35, - 0x31, 0x20, - 0x21, 0x35, - 0x23, 0x25, - 0x52, 0x20, - 0x05, 0x50 -}; - // CODE -------------------------------------------------------------------- //========================================================================== @@ -317,22 +274,25 @@ FStartupScreen *FStartupScreen::CreateInstance(int max_progress) FStartupScreen *scr = NULL; HRESULT hr; - if (gameinfo.gametype == GAME_Hexen) + if (!Args->CheckParm("-nostartup")) { - scr = new FHexenStartupScreen(max_progress, hr); - } - else if (gameinfo.gametype == GAME_Heretic) - { - scr = new FHereticStartupScreen(max_progress, hr); - } - else if (gameinfo.gametype == GAME_Strife) - { - scr = new FStrifeStartupScreen(max_progress, hr); - } - if (scr != NULL && FAILED(hr)) - { - delete scr; - scr = NULL; + if (gameinfo.gametype == GAME_Hexen) + { + scr = new FHexenStartupScreen(max_progress, hr); + } + else if (gameinfo.gametype == GAME_Heretic) + { + scr = new FHereticStartupScreen(max_progress, hr); + } + else if (gameinfo.gametype == GAME_Strife) + { + scr = new FStrifeStartupScreen(max_progress, hr); + } + if (scr != NULL && FAILED(hr)) + { + delete scr; + scr = NULL; + } } if (scr == NULL) { @@ -674,13 +634,23 @@ FHexenStartupScreen::FHexenStartupScreen(int max_progress, HRESULT &hr) : FGraphicalStartupScreen(max_progress) { int startup_lump = Wads.CheckNumForName ("STARTUP"); + int netnotch_lump = Wads.CheckNumForName ("NETNOTCH"); + int notch_lump = Wads.CheckNumForName ("NOTCH"); hr = E_FAIL; - if (startup_lump < 0 || Wads.LumpLength (startup_lump) != 153648 || !ST_Util_CreateStartupWindow()) + if (startup_lump < 0 || Wads.LumpLength (startup_lump) != 153648 || !ST_Util_CreateStartupWindow() || + netnotch_lump < 0 || Wads.LumpLength (netnotch_lump) != ST_NETNOTCH_WIDTH / 2 * ST_NETNOTCH_HEIGHT || + notch_lump < 0 || Wads.LumpLength (notch_lump) != ST_NOTCH_WIDTH / 2 * ST_NOTCH_HEIGHT) { + NetNotchBits = NotchBits = NULL; return; } + NetNotchBits = new BYTE[ST_NETNOTCH_WIDTH / 2 * ST_NETNOTCH_HEIGHT]; + Wads.ReadLump (netnotch_lump, NetNotchBits); + NotchBits = new BYTE[ST_NOTCH_WIDTH / 2 * ST_NOTCH_HEIGHT]; + Wads.ReadLump (notch_lump, NotchBits); + BYTE startup_screen[153648]; union { @@ -719,6 +689,22 @@ FHexenStartupScreen::FHexenStartupScreen(int max_progress, HRESULT &hr) hr = S_OK; } +//========================================================================== +// +// FHexenStartupScreen Deconstructor +// +// Frees the notch pictures. +// +//========================================================================== + +FHexenStartupScreen::~FHexenStartupScreen() +{ + if (NotchBits) + delete[] NotchBits; + if (NetNotchBits) + delete[] NetNotchBits; +} + //========================================================================== // // FHexenStartupScreen :: Progress diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 5e0c3c992..7427112c3 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -270,6 +270,8 @@ ACTOR Actor native //: Thinker action native A_SetSpecial(int spec, int arg0 = 0, int arg1 = 0, int arg2 = 0, int arg3 = 0, int arg4 = 0); action native A_Quake(int intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); + action native A_CheckSightOrRange(float distance, state label); + States { Spawn: diff --git a/wadsrc/static/actors/chex/chexplayer.txt b/wadsrc/static/actors/chex/chexplayer.txt index 5003ea809..210a68470 100644 --- a/wadsrc/static/actors/chex/chexplayer.txt +++ b/wadsrc/static/actors/chex/chexplayer.txt @@ -16,4 +16,14 @@ actor ChexPlayer : DoomPlayer player.WeaponSlot 5, ZorchPropulsor player.WeaponSlot 6, PhasingZorcher player.WeaponSlot 7, LAZDevice + + Player.Colorset 0, "Light Blue", 0xC0, 0xCF, 0xC2 + Player.Colorset 1, "Green", 0x70, 0x7F, 0x72 + Player.Colorset 2, "Gray", 0x60, 0x6F, 0x62 + Player.Colorset 3, "Brown", 0x40, 0x4F, 0x42 + Player.Colorset 4, "Red", 0x20, 0x2F, 0x22 + Player.Colorset 5, "Light Gray", 0x58, 0x67, 0x5A + Player.Colorset 6, "Light Brown", 0x38, 0x47, 0x3A + Player.Colorset 7, "Light Red", 0xB0, 0xBF, 0xB2 + } diff --git a/wadsrc/static/actors/doom/doomarmor.txt b/wadsrc/static/actors/doom/doomarmor.txt index 0474ee041..486fc0611 100644 --- a/wadsrc/static/actors/doom/doomarmor.txt +++ b/wadsrc/static/actors/doom/doomarmor.txt @@ -9,7 +9,7 @@ Actor ArmorBonus : BasicArmorBonus 2015 Height 16 Inventory.Pickupmessage "$GOTARMBONUS" Inventory.Icon "ARM1A0" - Armor.Savepercent 33.33333 + Armor.Savepercent 33.335 Armor.Saveamount 1 Armor.Maxsaveamount 200 +COUNTITEM diff --git a/wadsrc/static/actors/doom/doomplayer.txt b/wadsrc/static/actors/doom/doomplayer.txt index 9138fc649..3f81eaaca 100644 --- a/wadsrc/static/actors/doom/doomplayer.txt +++ b/wadsrc/static/actors/doom/doomplayer.txt @@ -11,7 +11,6 @@ ACTOR DoomPlayer : PlayerPawn Height 56 Mass 100 PainChance 255 - Player.ColorRange 112, 127 Player.DisplayName "Marine" Player.CrouchSprite "PLYC" Player.StartItem "Pistol" @@ -24,6 +23,17 @@ ACTOR DoomPlayer : PlayerPawn Player.WeaponSlot 5, RocketLauncher Player.WeaponSlot 6, PlasmaRifle Player.WeaponSlot 7, BFG9000 + + Player.ColorRange 112, 127 + Player.Colorset 0, "Green", 0x70, 0x7F, 0x72 + Player.Colorset 1, "Gray", 0x60, 0x6F, 0x62 + Player.Colorset 2, "Brown", 0x40, 0x4F, 0x42 + Player.Colorset 3, "Red", 0x20, 0x2F, 0x22 + // Doom Legacy additions + Player.Colorset 4, "Light Gray", 0x58, 0x67, 0x5A + Player.Colorset 5, "Light Brown", 0x38, 0x47, 0x3A + Player.Colorset 6, "Light Red", 0xB0, 0xBF, 0xB2 + Player.Colorset 7, "Light Blue", 0xC0, 0xCF, 0xC2 States { diff --git a/wadsrc/static/actors/heretic/hereticplayer.txt b/wadsrc/static/actors/heretic/hereticplayer.txt index 9e36f8d7f..77ec994d8 100644 --- a/wadsrc/static/actors/heretic/hereticplayer.txt +++ b/wadsrc/static/actors/heretic/hereticplayer.txt @@ -6,7 +6,6 @@ ACTOR HereticPlayer : PlayerPawn Mass 100 Painchance 255 Speed 1 - Player.ColorRange 225, 240 Player.DisplayName "Corvus" Player.StartItem "GoldWand" Player.StartItem "Staff" @@ -18,7 +17,20 @@ ACTOR HereticPlayer : PlayerPawn Player.WeaponSlot 5, SkullRod Player.WeaponSlot 6, PhoenixRod Player.WeaponSlot 7, Mace - + + Player.ColorRange 225, 240 + Player.Colorset 0, "Green", 225, 240, 238 + Player.Colorset 1, "Yellow", 114, 129, 127 + Player.Colorset 2, "Red", 145, 160, 158 + Player.Colorset 3, "Blue", 190, 205, 203 + // Doom Legacy additions + Player.Colorset 4, "Brown", 67, 82, 80 + Player.Colorset 5, "Light Gray", 9, 24, 22 + Player.Colorset 6, "Light Brown", 74, 89, 87 + Player.Colorset 7, "Light Red", 150, 165, 163 + Player.Colorset 8, "Light Blue", 192, 207, 205 + Player.Colorset 9, "Beige", 95, 110, 108 + States { Spawn: diff --git a/wadsrc/static/actors/hexen/clericplayer.txt b/wadsrc/static/actors/hexen/clericplayer.txt index 493faffde..4fe6629e2 100644 --- a/wadsrc/static/actors/hexen/clericplayer.txt +++ b/wadsrc/static/actors/hexen/clericplayer.txt @@ -15,7 +15,6 @@ ACTOR ClericPlayer : PlayerPawn RadiusDamageFactor 0.25 Player.JumpZ 9 Player.Viewheight 48 - Player.ColorRange 146, 163 Player.SpawnClass "Cleric" Player.DisplayName "Cleric" Player.SoundClass "cleric" @@ -29,6 +28,16 @@ ACTOR ClericPlayer : PlayerPawn Player.WeaponSlot 3, CWeapFlame Player.WeaponSlot 4, CWeapWraithverge + Player.ColorRange 146, 163 + Player.Colorset 0, "Blue", 146, 163, 161 + Player.ColorsetFile 1, "Red", "TRANTBL7", 0xB3 + Player.ColorsetFile 2, "Gold", "TRANTBL8", 0x8C + Player.ColorsetFile 3, "Dull Green", "TRANTBL9", 0x41 + Player.ColorsetFile 4, "Green", "TRANTBLA", 0xC9 + Player.ColorsetFile 5, "Gray", "TRANTBLB", 0x30 + Player.ColorsetFile 6, "Brown", "TRANTBLC", 0x72 + Player.ColorsetFile 7, "Purple", "TRANTBLD", 0xEE + States { Spawn: diff --git a/wadsrc/static/actors/hexen/fighterplayer.txt b/wadsrc/static/actors/hexen/fighterplayer.txt index 5c307bd60..2253ba5b6 100644 --- a/wadsrc/static/actors/hexen/fighterplayer.txt +++ b/wadsrc/static/actors/hexen/fighterplayer.txt @@ -14,7 +14,6 @@ ACTOR FighterPlayer : PlayerPawn RadiusDamageFactor 0.25 Player.JumpZ 9 Player.Viewheight 48 - Player.ColorRange 246, 254 Player.SpawnClass "Fighter" Player.DisplayName "Fighter" Player.SoundClass "fighter" @@ -29,6 +28,16 @@ ACTOR FighterPlayer : PlayerPawn Player.WeaponSlot 3, FWeapHammer Player.WeaponSlot 4, FWeapQuietus + Player.ColorRange 246, 254 + Player.Colorset 0, "Gold", 246, 254, 253 + Player.ColorsetFile 1, "Red", "TRANTBL0", 0xAC + Player.ColorsetFile 2, "Blue", "TRANTBL1", 0x9D + Player.ColorsetFile 3, "Dull Green", "TRANTBL2", 0x3E + Player.ColorsetFile 4, "Green", "TRANTBL3", 0xC8 + Player.ColorsetFile 5, "Gray", "TRANTBL4", 0x2D + Player.ColorsetFile 6, "Brown", "TRANTBL5", 0x6F + Player.ColorsetFile 7, "Purple", "TRANTBL6", 0xEE + States { Spawn: @@ -55,7 +64,7 @@ ACTOR FighterPlayer : PlayerPawn Stop XDeath: PLAY O 5 A_PlayerScream - PLAY P 5 A_SkullPop + PLAY P 5 A_SkullPop("BloodyFighterSkull") PLAY R 5 A_NoBlocking PLAY STUV 5 PLAY W -1 @@ -90,3 +99,28 @@ ACTOR FighterPlayer : PlayerPawn } } +// The fighter's bloody skull -------------------------------------------------------------- + +Actor BloodyFighterSkull : PlayerChunk +{ + Game Hexen + Radius 4 + Height 4 + +NOBLOCKMAP + +DROPOFF + +LOWGRAVITY + +CANNOTPUSH + +SKYEXPLODE + +NOBLOCKMONST + +NOSKIN + States + { + Spawn: + BSKL A 0 + BSKL ABCDFGH 5 A_CheckFloor("Hit") + Goto Spawn+1 + Hit: + BSKL I 16 A_CheckPlayerDone + Wait + } +} diff --git a/wadsrc/static/actors/hexen/mageplayer.txt b/wadsrc/static/actors/hexen/mageplayer.txt index 2f67d35bf..a34698366 100644 --- a/wadsrc/static/actors/hexen/mageplayer.txt +++ b/wadsrc/static/actors/hexen/mageplayer.txt @@ -15,7 +15,6 @@ ACTOR MagePlayer : PlayerPawn RadiusDamageFactor 0.25 Player.JumpZ 9 Player.Viewheight 48 - Player.ColorRange 146, 163 Player.SpawnClass "Mage" Player.DisplayName "Mage" Player.SoundClass "mage" @@ -31,6 +30,16 @@ ACTOR MagePlayer : PlayerPawn Player.WeaponSlot 3, MWeapLightning Player.WeaponSlot 4, MWeapBloodscourge + Player.ColorRange 146, 163 + Player.Colorset 0, "Blue", 146, 163, 161 + Player.ColorsetFile 1, "Red", "TRANTBL7", 0xB3 + Player.ColorsetFile 2, "Gold", "TRANTBL8", 0x8C + Player.ColorsetFile 3, "Dull Green", "TRANTBL9", 0x41 + Player.ColorsetFile 4, "Green", "TRANTBLA", 0xC9 + Player.ColorsetFile 5, "Gray", "TRANTBLB", 0x30 + Player.ColorsetFile 6, "Brown", "TRANTBLC", 0x72 + Player.ColorsetFile 7, "Purple", "TRANTBLD", 0xEE + States { Spawn: diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index c527db26b..a3c93b738 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -185,7 +185,7 @@ ACTOR PowerGhost : PowerInvisibility Powerup.Mode "None" } -ACTOR PowerShadow : PowerInvisibility native +ACTOR PowerShadow : PowerInvisibility { +INVENTORY.HUBPOWER Powerup.Duration -55 diff --git a/wadsrc/static/actors/strife/macil.txt b/wadsrc/static/actors/strife/macil.txt index ea701dd9f..ba99be435 100644 --- a/wadsrc/static/actors/strife/macil.txt +++ b/wadsrc/static/actors/strife/macil.txt @@ -21,6 +21,7 @@ ACTOR Macil1 64 SeeSound "macil/sight" PainSound "macil/pain" ActiveSound "macil/active" + CrushPainSound "misc/pcrush" Tag "MACIL" Obituary "$OB_MACIL" DropItem "BoxOfBullets" diff --git a/wadsrc/static/actors/strife/merchants.txt b/wadsrc/static/actors/strife/merchants.txt index d06ee607d..65f5ac653 100644 --- a/wadsrc/static/actors/strife/merchants.txt +++ b/wadsrc/static/actors/strife/merchants.txt @@ -7,6 +7,7 @@ ACTOR Merchant Radius 20 Height 56 Mass 5000 + CrushPainSound "misc/pcrush" +SOLID +SHOOTABLE +NOTDMATCH diff --git a/wadsrc/static/actors/strife/strifehumanoid.txt b/wadsrc/static/actors/strife/strifehumanoid.txt index c81f40f34..375f5bbcf 100644 --- a/wadsrc/static/actors/strife/strifehumanoid.txt +++ b/wadsrc/static/actors/strife/strifehumanoid.txt @@ -7,6 +7,7 @@ ACTOR StrifeHumanoid MaxStepHeight 16 MaxDropoffHeight 32 + CrushPainSound "misc/pcrush" States { Burn: diff --git a/wadsrc/static/actors/strife/strifeplayer.txt b/wadsrc/static/actors/strife/strifeplayer.txt index d42dc1ba4..5b0bdc750 100644 --- a/wadsrc/static/actors/strife/strifeplayer.txt +++ b/wadsrc/static/actors/strife/strifeplayer.txt @@ -9,7 +9,7 @@ ACTOR StrifePlayer : PlayerPawn PainChance 255 Speed 1 MaxStepHeight 16 - Player.ColorRange 128, 143 + CrushPainSound "misc/pcrush" Player.DisplayName "Rebel" Player.StartItem "PunchDagger" Player.RunHealth 15 @@ -22,6 +22,16 @@ ACTOR StrifePlayer : PlayerPawn Player.WeaponSlot 7, Mauler2, Mauler Player.WeaponSlot 8, Sigil + Player.ColorRange 128, 143 + Player.Colorset 0, "Brown", 0x80, 0x8F, 0x82 + Player.Colorset 1, "Red", 0x40, 0x4F, 0x42 + Player.Colorset 2, "Rust", 0xB0, 0xBF, 0xB2 + Player.Colorset 3, "Gray", 0x10, 0x1F, 0x12 + Player.Colorset 4, "Dark Green", 0x30, 0x3F, 0x32 + Player.Colorset 5, "Gold", 0x50, 0x5F, 0x52 + Player.Colorset 6, "Bright Green", 0x60, 0x6F, 0x62 + Player.Colorset 7, "Blue", 0x90, 0x9F, 0x92 + action native A_ItBurnsItBurns(); action native A_CrispyPlayer(); action native A_HandLower(); diff --git a/wadsrc/static/actors/strife/templar.txt b/wadsrc/static/actors/strife/templar.txt index fd8351c89..214804b34 100644 --- a/wadsrc/static/actors/strife/templar.txt +++ b/wadsrc/static/actors/strife/templar.txt @@ -19,6 +19,7 @@ ACTOR Templar 3003 PainSound "templar/pain" DeathSound "templar/death" ActiveSound "templar/active" + CrushPainSound "misc/pcrush" Tag "TEMPLAR" HitObituary "$OB_TEMPLARHIT" Obituary "$OB_TEMPLAR" diff --git a/wadsrc/static/actors/strife/zombie.txt b/wadsrc/static/actors/strife/zombie.txt index e26f8b266..9788bc00f 100644 --- a/wadsrc/static/actors/strife/zombie.txt +++ b/wadsrc/static/actors/strife/zombie.txt @@ -20,6 +20,7 @@ ACTOR Zombie : StrifeHumanoid 169 Translation 0 ConversationID 28, -1, -1 DeathSound "zombie/death" + CrushPainSound "misc/pcrush" States { Spawn: @@ -34,7 +35,7 @@ ACTOR Zombie : StrifeHumanoid 169 GIBS O 5 A_NoBlocking GIBS PQRST 4 A_TossGib GIBS U 5 - GIBS V 1400 + GIBS V -1 Stop } } diff --git a/wadsrc/static/animdefs.txt b/wadsrc/static/animdefs.txt index 388a4f360..f4b33eaab 100644 --- a/wadsrc/static/animdefs.txt +++ b/wadsrc/static/animdefs.txt @@ -1,3 +1,24 @@ +// Doom menu cursor +texture optional M_SKULL1 +pic M_SKULL1 tics 8 +pic M_SKULL2 tics 8 + +// Heretic/Hexen menu cursor +texture optional M_SLCTR1 +pic M_SLCTR1 tics 16 +pic M_SLCTR2 tics 16 + +// Strife menu cursor +texture optional M_CURS1 +pic M_CURS1 tics 4 +pic M_CURS2 tics 4 +pic M_CURS3 tics 4 +pic M_CURS4 tics 4 +pic M_CURS5 tics 4 +pic M_CURS6 tics 4 +pic M_CURS7 tics 4 +pic M_CURS8 tics 4 + // Tome of Power texture optional SPINBK0 pic SPINBK0 tics 3 diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 4cb444d0f..53d74a483 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -570,6 +570,19 @@ PD_ALL6 = "You need all six keys to open this door"; PD_ALL6O = "You need all six keys to activate this object"; PD_ALLKEYS = "You need all the keys"; +// MBF (BOOM?) narration backgrounds +bgflatE1 = "FLOOR4_8"; +bgflatE2 = "SFLR6_1"; +bgflatE3 = "MFLR8_4"; +bgflatE4 = "MFLR8_3"; +bgflat06 = "SLIME16"; +bgflat11 = "RROCK14"; +bgflat20 = "RROCK07"; +bgflat30 = "RROCK17"; +bgflat15 = "RROCK13"; +bgflat31 = "RROCK19"; +bgcastcall = "BOSSBACK"; + // Gameflow messages TXT_FRAGLIMIT = "Fraglimit hit."; TXT_TIMELIMIT = "Timelimit hit."; diff --git a/wadsrc/static/mapinfo/doom1.txt b/wadsrc/static/mapinfo/doom1.txt index 5c8fc1dc9..b3e631650 100644 --- a/wadsrc/static/mapinfo/doom1.txt +++ b/wadsrc/static/mapinfo/doom1.txt @@ -501,28 +501,28 @@ map E4M9 lookup "HUSTR_E4M9" cluster 1 { - flat = "FLOOR4_8" + flat = "$bgflatE1" music = "$MUSIC_VICTOR" exittext = lookup, "E1TEXT" } cluster 2 { - flat = "SFLR6_1" + flat = "$bgflatE2" music = "$MUSIC_VICTOR" exittext = lookup, "E2TEXT" } cluster 3 { - flat = "MFLR8_4" + flat = "$bgflatE3" music = "$MUSIC_VICTOR" exittext = lookup, "E3TEXT" } cluster 4 { - flat = "MFLR8_3" + flat = "$bgflatE4" music = "$MUSIC_VICTOR" exittext = lookup, "E4TEXT" } diff --git a/wadsrc/static/mapinfo/doom2.txt b/wadsrc/static/mapinfo/doom2.txt index 50bae7d9d..6dc9815b1 100644 --- a/wadsrc/static/mapinfo/doom2.txt +++ b/wadsrc/static/mapinfo/doom2.txt @@ -372,7 +372,7 @@ map MAP32 lookup "HUSTR_32" cluster 5 { - flat = "SLIME16" + flat = "$BGFLAT06" music = "$MUSIC_READ_M" exittext = lookup, "C1TEXT" @@ -382,7 +382,7 @@ cluster 5 cluster 6 { - flat = "RROCK14" + flat = "$BGFLAT11" music = "$MUSIC_READ_M" exittext = lookup, "C2TEXT" @@ -392,7 +392,7 @@ cluster 6 cluster 7 { - flat = "RROCK07" + flat = "$BGFLAT20" music = "$MUSIC_READ_M" exittext = lookup, "C3TEXT" } @@ -401,7 +401,7 @@ cluster 7 cluster 8 { - flat = "RROCK17" + flat = "$BGFLAT30" music = "$MUSIC_READ_M" exittext = lookup, "C4TEXT" } @@ -410,7 +410,7 @@ cluster 8 cluster 9 { - flat = "RROCK13" + flat = "$BGFLAT15" music = "$MUSIC_READ_M" entertext = lookup, "C5TEXT" } @@ -419,7 +419,7 @@ cluster 9 cluster 10 { - flat = "RROCK19" + flat = "$BGFLAT31" music = "$MUSIC_READ_M" entertext = lookup, "C6TEXT" } diff --git a/wadsrc/static/mapinfo/plutonia.txt b/wadsrc/static/mapinfo/plutonia.txt index 612aaf264..34101541b 100644 --- a/wadsrc/static/mapinfo/plutonia.txt +++ b/wadsrc/static/mapinfo/plutonia.txt @@ -373,7 +373,7 @@ map MAP32 lookup "PHUSTR_32" cluster 5 { - flat = "SLIME16" + flat = "$BGFLAT06" music = "$MUSIC_READ_M" exittext = lookup, "P1TEXT" } @@ -382,7 +382,7 @@ cluster 5 cluster 6 { - flat = "RROCK14" + flat = "$BGFLAT11" music = "$MUSIC_READ_M" exittext = lookup, "P2TEXT" } @@ -391,7 +391,7 @@ cluster 6 cluster 7 { - flat = "RROCK07" + flat = "$BGFLAT20" music = "$MUSIC_READ_M" exittext = lookup, "P3TEXT" } @@ -400,7 +400,7 @@ cluster 7 cluster 8 { - flat = "RROCK17" + flat = "$BGFLAT30" music = "$MUSIC_READ_M" exittext = lookup, "P4TEXT" } @@ -409,7 +409,7 @@ cluster 8 cluster 9 { - flat = "RROCK13" + flat = "$BGFLAT15" music = "$MUSIC_READ_M" entertext = lookup, "P5TEXT" } @@ -418,7 +418,7 @@ cluster 9 cluster 10 { - flat = "RROCK19" + flat = "$BGFLAT31" music = "$MUSIC_READ_M" entertext = lookup, "P6TEXT" } diff --git a/wadsrc/static/mapinfo/tnt.txt b/wadsrc/static/mapinfo/tnt.txt index 438b61ff1..9d069c8d5 100644 --- a/wadsrc/static/mapinfo/tnt.txt +++ b/wadsrc/static/mapinfo/tnt.txt @@ -373,7 +373,7 @@ map MAP32 lookup "THUSTR_32" cluster 5 { - flat = "SLIME16" + flat = "$BGFLAT06" music = "$MUSIC_READ_M" exittext = lookup, "T1TEXT" } @@ -382,7 +382,7 @@ cluster 5 cluster 6 { - flat = "RROCK14" + flat = "$BGFLAT11" music = "$MUSIC_READ_M" exittext = lookup, "T2TEXT" } @@ -391,7 +391,7 @@ cluster 6 cluster 7 { - flat = "RROCK07" + flat = "$BGFLAT20" music = "$MUSIC_READ_M" exittext = lookup, "T3TEXT" } @@ -400,7 +400,7 @@ cluster 7 cluster 8 { - flat = "RROCK17" + flat = "$BGFLAT30" music = "$MUSIC_READ_M" exittext = lookup, "T4TEXT" } @@ -409,7 +409,7 @@ cluster 8 cluster 9 { - flat = "RROCK13" + flat = "$BGFLAT15" music = "$MUSIC_READ_M" entertext = lookup, "T5TEXT" } @@ -418,7 +418,7 @@ cluster 9 cluster 10 { - flat = "RROCK19" + flat = "$BGFLAT31" music = "$MUSIC_READ_M" entertext = lookup, "T6TEXT" } diff --git a/wadsrc/static/netnotch.dat b/wadsrc/static/netnotch.dat new file mode 100644 index 000000000..d1a430adf Binary files /dev/null and b/wadsrc/static/netnotch.dat differ diff --git a/wadsrc/static/notch.dat b/wadsrc/static/notch.dat new file mode 100644 index 000000000..ef0b13af6 Binary files /dev/null and b/wadsrc/static/notch.dat differ diff --git a/wadsrc/static/sndinfo.txt b/wadsrc/static/sndinfo.txt index c534808bb..100485e28 100644 --- a/wadsrc/static/sndinfo.txt +++ b/wadsrc/static/sndinfo.txt @@ -1124,6 +1124,7 @@ misc/teleport dstelept misc/swish dsswish misc/meathit dsmeatht misc/metalhit dsmtalht +misc/pcrush dspcrush misc/gibbed dsslop misc/explosion dsexplod misc/reactor dsreactr