diff --git a/Makefile.common b/Makefile.common index 73afc5d4..1d08edb3 100644 --- a/Makefile.common +++ b/Makefile.common @@ -113,8 +113,9 @@ SOURCES_C += $(CORE_DIR)/am_map.c \ $(CORE_DIR)/flplayer.c \ $(CORE_DIR)/midifile.c \ $(CORE_DIR)/madplayer.c \ - $(CORE_DIR)/u_mapinfo.c \ $(CORE_DIR)/u_scanner.c \ + $(CORE_DIR)/u_mapinfo.c \ + $(CORE_DIR)/u_musinfo.c \ ifeq ($(WANT_FLUIDSYNTH), 1) diff --git a/src/info.c b/src/info.c index c32c845c..7d0a8994 100644 --- a/src/info.c +++ b/src/info.c @@ -5526,4 +5526,36 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { 0, // maxattackrange 200, // minmissilechance }, + + // Will change music according to MUSINFO lump + { // MT_MUSICCHANGER + "MusicChanger", // actorname + 14165, // doomednum // 14100-14164 should also be reserved + S_TNT1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + MT_NULL, // droppeditem + 0, // speed + 16, // radius + 16, // height + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP, // flags + S_NULL, // raisestate + 0, // meleethreshold + 0, // maxattackrange + 200, // minmissilechance + }, }; diff --git a/src/info.h b/src/info.h index ecdb89b4..7a090e25 100644 --- a/src/info.h +++ b/src/info.h @@ -1411,6 +1411,8 @@ typedef enum { MT_PUSH, /* controls push source - phares */ MT_PULL, /* controls pull source - phares 3/20/98 */ + MT_MUSICCHANGER, /* MUSINFO Music Changer thing */ + /* proff 11/22/98: Andy Baker's stealth monsters (next 12) * cph - moved below the MBF stuff, no need to displace them */ MT_STEALTHBABY, diff --git a/src/p_mobj.c b/src/p_mobj.c index eb3071ce..6ed02bff 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -47,6 +47,7 @@ #include "p_inter.h" #include "lprintf.h" #include "r_demo.h" +#include "u_musinfo.h" // // P_SetMobjState @@ -729,45 +730,50 @@ void P_MobjThinker (mobj_t* mobj) // removed old code which looked at target references // (we use pointer reference counting now) + if (mobj->type == MT_MUSICCHANGER) + { + P_MusInfoMobjThinker(mobj); + return; + } + mobj->PrevX = mobj->x; mobj->PrevY = mobj->y; mobj->PrevZ = mobj->z; // momentum movement if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY) - { - P_XYMovement(mobj); - if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed - return; // killough - mobj was removed - } + { + P_XYMovement(mobj); + if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed + return; // killough - mobj was removed + } if (mobj->z != mobj->floorz || mobj->momz) - { - P_ZMovement(mobj); - if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed - return; // killough - mobj was removed - } - else - if (!(mobj->momx | mobj->momy) && !sentient(mobj)) - { // non-sentient objects at rest - mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest + { + P_ZMovement(mobj); + if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed + return; // killough - mobj was removed + } + else if (!(mobj->momx | mobj->momy) && !sentient(mobj)) + { // non-sentient objects at rest + mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest - // killough 9/12/98: objects fall off ledges if they are hanging off - // slightly push off of ledge if hanging more than halfway off + // killough 9/12/98: objects fall off ledges if they are hanging off + // slightly push off of ledge if hanging more than halfway off - if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff - !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall - !comp[comp_falloff]) // Not in old demos - P_ApplyTorque(mobj); // Apply torque - else - mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque - } + if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff + !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall + !comp[comp_falloff]) // Not in old demos + P_ApplyTorque(mobj); // Apply torque + else + mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque + } // cycle through states, // calling action functions at transitions if (mobj->tics != -1) - { + { mobj->tics--; // you can cycle through multiple states in a tic @@ -775,9 +781,9 @@ void P_MobjThinker (mobj_t* mobj) if (!mobj->tics) if (!P_SetMobjState (mobj, mobj->state->nextstate) ) return; // freed itself - } + } else - { + { // check for nightmare respawn @@ -799,7 +805,7 @@ void P_MobjThinker (mobj_t* mobj) return; P_NightmareRespawn (mobj); - } + } } @@ -1156,19 +1162,21 @@ void P_SpawnMapThing (const mapthing_t* mthing) fixed_t y; fixed_t z; int options = mthing->options; /* cph 2001/07/07 - make writable copy */ + short thingtype = mthing->type; + int iden_num = 0; // killough 2/26/98: Ignore type-0 things as NOPs // phares 5/14/98: Ignore Player 5-8 starts (for now) - switch(mthing->type) - { - case 0: - case DEN_PLAYER5: - case DEN_PLAYER6: - case DEN_PLAYER7: - case DEN_PLAYER8: - return; - } + switch(thingtype) + { + case 0: + case DEN_PLAYER5: + case DEN_PLAYER6: + case DEN_PLAYER7: + case DEN_PLAYER8: + return; + } // killough 11/98: clear flags unused by Doom // @@ -1183,54 +1191,54 @@ void P_SpawnMapThing (const mapthing_t* mthing) options & MTF_RESERVED)) { if (!demo_compatibility) // cph - Add warning about bad thing flags lprintf(LO_WARN, "P_SpawnMapThing: correcting bad flags (%u) (thing type %d)\n", - options, mthing->type); + options, thingtype); options &= MTF_EASY|MTF_NORMAL|MTF_HARD|MTF_AMBUSH|MTF_NOTSINGLE; } // count deathmatch start positions // doom2.exe has at most 10 deathmatch starts - if (mthing->type == 11) - { + if (thingtype == 11) + { if (!(!compatibility || deathmatch_p-deathmatchstarts < 10)) { - return; - } else { - // 1/11/98 killough -- new code removes limit on deathmatch starts: + return; + } else { + // 1/11/98 killough -- new code removes limit on deathmatch starts: - size_t offset = deathmatch_p - deathmatchstarts; + size_t offset = deathmatch_p - deathmatchstarts; - if (offset >= num_deathmatchstarts) + if (offset >= num_deathmatchstarts) { - num_deathmatchstarts = num_deathmatchstarts ? + num_deathmatchstarts = num_deathmatchstarts ? num_deathmatchstarts*2 : 16; - deathmatchstarts = realloc(deathmatchstarts, + deathmatchstarts = realloc(deathmatchstarts, num_deathmatchstarts * sizeof(*deathmatchstarts)); - deathmatch_p = deathmatchstarts + offset; + deathmatch_p = deathmatchstarts + offset; } - memcpy(deathmatch_p++, mthing, sizeof(*mthing)); - (deathmatch_p-1)->options = 1; - return; - } + memcpy(deathmatch_p++, mthing, sizeof(*mthing)); + (deathmatch_p-1)->options = 1; + return; } + } // check for players specially - if (mthing->type <= 4 && mthing->type > 0) // killough 2/26/98 -- fix crashes - { + if (thingtype <= 4 && thingtype > 0) // killough 2/26/98 -- fix crashes + { // save spots for respawning in coop games - playerstarts[mthing->type-1] = *mthing; + playerstarts[thingtype-1] = *mthing; /* cph 2006/07/24 - use the otherwise-unused options field to flag that * this start is present (so we know which elements of the array are filled * in, in effect). Also note that the call below to P_SpawnPlayer must use * the playerstarts version with this field set */ - playerstarts[mthing->type-1].options = 1; + playerstarts[thingtype-1].options = 1; if (!deathmatch) - P_SpawnPlayer (mthing->type-1, &playerstarts[mthing->type-1]); + P_SpawnPlayer (thingtype-1, &playerstarts[thingtype-1]); return; - } + } // check for apropriate skill level @@ -1257,18 +1265,27 @@ void P_SpawnMapThing (const mapthing_t* mthing) // find which type to spawn - // killough 8/23/98: use table for faster lookup - i = P_FindDoomedNum(mthing->type); + // Thing types from 14100 to 14164 are used for MUSINFO entities + // this means they are actually the same MusicChanger thingtype but + // each different type should have a different ambient music id. + // -- See https://doomwiki.org/wiki/MUSINFO -- + if (thingtype >= 14100 && thingtype <= 14164) + { + iden_num = thingtype - 14100; // Ambient music to change + i = MT_MUSICCHANGER; + } + else // killough 8/23/98: use table for faster lookup + i = P_FindDoomedNum(thingtype); // phares 5/16/98: // Do not abort because of an unknown thing. Ignore it, but post a // warning message for the player. if (i == NUMMOBJTYPES) - { + { doom_printf("Unknown Thing type %i at (%i, %i)",mthing->type,mthing->x,mthing->y); return; - } + } // don't spawn keycards and players in deathmatch @@ -1292,6 +1309,7 @@ void P_SpawnMapThing (const mapthing_t* mthing) mobj = P_SpawnMobj (x,y,z, i); mobj->spawnpoint = *mthing; + mobj->iden_num = iden_num; if (mobj->tics > 0) mobj->tics = 1 + (P_Random (pr_spawnthing) % mobj->tics); @@ -1299,10 +1317,10 @@ void P_SpawnMapThing (const mapthing_t* mthing) if (!(mobj->flags & MF_FRIEND) && options & MTF_FRIEND && mbf_features) - { - mobj->flags |= MF_FRIEND; // killough 10/98: - P_UpdateThinker(&mobj->thinker); // transfer friendliness flag - } + { + mobj->flags |= MF_FRIEND; // killough 10/98: + P_UpdateThinker(&mobj->thinker); // transfer friendliness flag + } /* killough 7/20/98: exclude friends */ if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) diff --git a/src/p_mobj.h b/src/p_mobj.h index 10f69aaf..95290dff 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -324,7 +324,7 @@ typedef struct mobj_s int tics; // state tic counter state_t* state; - uint64_t flags; + uint64_t flags; int intflags; // killough 9/15/98: internal flags int health; @@ -380,6 +380,9 @@ typedef struct mobj_s fixed_t PrevY; fixed_t PrevZ; + // Extra id based on thing type that's used in MUSINFO + short iden_num; + fixed_t pad; // cph - needed so I can get the size unambiguously on amd64 // SEE WARNING ABOVE ABOUT POINTER FIELDS!!! diff --git a/src/p_setup.c b/src/p_setup.c index 6212bcb4..bbf1bc3d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -50,6 +50,7 @@ #include "v_video.h" #include "r_demo.h" #include "r_fps.h" +#include "u_musinfo.h" // // MAP related Lookup tables. @@ -1880,6 +1881,9 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill) if (gamemode==commercial) P_SpawnBrainTargets(); + // load MUSINFO from the map, if it exists + U_ParseMusInfo(lumpname); + // clear special respawning que iquehead = iquetail = 0; diff --git a/src/p_tick.c b/src/p_tick.c index 55792393..5a88fa63 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -37,6 +37,7 @@ #include "p_tick.h" #include "p_map.h" #include "r_fps.h" +#include "u_musinfo.h" int leveltime; @@ -261,6 +262,9 @@ static void P_RunThinkers (void) currentthinker->function(currentthinker); } newthinkerpresent = FALSE; + + // Dedicated thinkers + P_MapMusicThinker(); } /* diff --git a/src/s_sound.c b/src/s_sound.c index d4d62be0..d6fcaa01 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -112,7 +112,6 @@ int S_AdjustSoundParams(mobj_t *listener, mobj_t *source, int *vol, int *sep, int *pitch); static int S_getChannel(void *origin, sfxinfo_t *sfxinfo, int is_pickup); -static void S_ChangeMusicByName(char* lumpname, int looping); // Initializes sound stuff, including volume // Sets channels, SFX and music volume, diff --git a/src/s_sound.h b/src/s_sound.h index 4c935970..453128a0 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -71,6 +71,7 @@ void S_StartMusic(int music_id); // Start music using from sounds.h, and set whether looping void S_ChangeMusic(int music_id, int looping); +void S_ChangeMusicByName(char* lumpname, int looping); // Stops the music fer sure. void S_StopMusic(void); diff --git a/src/u_musinfo.c b/src/u_musinfo.c new file mode 100644 index 00000000..9d8a2d03 --- /dev/null +++ b/src/u_musinfo.c @@ -0,0 +1,167 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: MUSINFO Support + * + *-----------------------------------------------------------------------------*/ + +// killough 3/7/98: modified to allow arbitrary listeners in spy mode +// killough 5/2/98: reindented, removed useless code, beautified +// ferk 10/1/19: cleanup/refactor, reuse u_scanner, support id:0 default music like ZDoom + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "doomstat.h" +#include "doomtype.h" +#include "d_main.h" +#include "p_mobj.h" +#include "m_misc.h" +#include "sounds.h" +#include "s_sound.h" +#include "i_sound.h" +#include "r_defs.h" +#include "w_wad.h" +#include "lprintf.h" +#include "u_scanner.h" + +#include "u_musinfo.h" + +#define MAX_MUS_ENTRIES 64 + +// +//MUSINFO lump +// + +typedef struct musinfo_s +{ + mobj_t *mapthing; + mobj_t *lastmapthing; + int tics; + int items[MAX_MUS_ENTRIES]; +} musinfo_t; + +musinfo_t musinfo; + +// +// U_ParseMusInfo +// Parses MUSINFO lump. +// +void U_ParseMusInfo(const char *mapid) +{ + memset(&musinfo, 0, sizeof(musinfo)); + + S_music[NUMMUSIC].lumpnum = -1; + + int musinfolump = W_GetNumForName("MUSINFO"); + if (musinfolump != -1) + { + const char *data = W_CacheLumpNum(musinfolump); + int datalength = W_LumpLength(musinfolump); + int lumpnum; + int inMap = false; + + u_scanner_t s = U_ScanOpen(data, datalength); + while (U_HasTokensLeft(&s)) + { + if (inMap || U_CheckToken(&s, TK_Identifier)) + { + if (!inMap) + inMap = true; + + // If there's a new map as identifier, stop search + if (U_CheckToken(&s, TK_Identifier) && + (s.string[0] == 'E' || s.string[0] == 'e' || + s.string[0] == 'M' || s.string[0] == 'm')) + { + break; + } + + U_MustGetInteger(&s); + + // Check number in range + if (s.number > 0 && s.number < MAX_MUS_ENTRIES) + { + if (U_MustGetToken(&s, TK_Identifier)) + { + lumpnum = W_CheckNumForName(s.string); + + if (lumpnum >= 0) + musinfo.items[s.number] = lumpnum; + else + U_Error(&s, "U_ParseMusInfo: Unknown MUS lump %s", s.string); + } + } + else + U_Error(&s, "U_ParseMusInfo: Number not in range 1 to %d", MAX_MUS_ENTRIES); + } + else + U_GetNextToken(&s, TRUE); + } + + U_ScanClose(&s); + } +} + +// Thinker for Music Changer mapthing +// It'll configure the music to play when player is in the same sector +void P_MusInfoMobjThinker(mobj_t *thing) +{ + if (musinfo.mapthing != thing && + thing->subsector->sector == players[displayplayer].mo->subsector->sector) + { + musinfo.lastmapthing = musinfo.mapthing; + musinfo.mapthing = thing; + musinfo.tics = 30; + } +} + +void P_MapMusicThinker(void) +{ + if (musinfo.tics < 0 || !musinfo.mapthing) + return; + + if (musinfo.tics > 0) + musinfo.tics--; + else if (musinfo.lastmapthing != musinfo.mapthing) + { + int musitem = musinfo.mapthing->iden_num; + + if (musitem == 0) // play default level music + { + S_Start(); + } + else if (musitem > 0 && musitem < MAX_MUS_ENTRIES) + { + char* musicname = W_GetNameForNum(musinfo.items[musitem]); + if (musicname) + S_ChangeMusicByName(musicname, true); + } + musinfo.tics = -1; + } +} diff --git a/src/u_musinfo.h b/src/u_musinfo.h new file mode 100644 index 00000000..d345f995 --- /dev/null +++ b/src/u_musinfo.h @@ -0,0 +1,41 @@ +/* Emacs style mode select -*- C++ -*- + *----------------------------------------------------------------------------- + * + * PrBoom: a Doom port merged with LxDoom and LSDLDoom + * based on BOOM, a modified and improved DOOM engine + * Copyright (C) 1999 by + * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman + * Copyright (C) 1999-2000 by + * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze + * Copyright 2005, 2006 by + * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * DESCRIPTION: + * MUSINFO support + *-----------------------------------------------------------------------------*/ + +#ifndef __U_MUSINFO__ +#define __U_MUSINFO__ + +#include "p_mobj.h" + +void U_ParseMusInfo(const char *mapid); +void P_MusInfoMobjThinker(mobj_t *thing); +void P_MapMusicThinker(void); + +#endif diff --git a/src/w_wad.c b/src/w_wad.c index a35c951c..3c157903 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -411,7 +411,13 @@ int W_GetNumForName (const char* name) // killough -- const added return i; } - +// W_GetNameForNum +// Returns the name for the giiven lump number +// +char* W_GetNameForNum (const int lump) +{ + return (lump >=0 && lump < numlumps)? lumpinfo[lump].name : NULL; +} // W_ListNumFromName // calls W_FindNumFromName and returns the lumps in ascending order diff --git a/src/w_wad.h b/src/w_wad.h index 82a4e6a3..cc5d68f8 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -137,6 +137,7 @@ int W_ListNumFromName(const char *name, int lump); static INLINE int (W_CheckNumForName)(const char *name, lumpinfo_namespace_t ns) { return (W_FindNumFromName)(name, ns, -1); } int W_GetNumForName (const char* name); +char* W_GetNameForNum (const int lump); int W_LumpLength (int lump); void W_ReadLump (int lump, void *dest); // CPhipps - modified for 'new' lump locking