diff --git a/src/doom/CMakeLists.txt b/src/doom/CMakeLists.txt index 4350145ce6..7cdff1bccc 100644 --- a/src/doom/CMakeLists.txt +++ b/src/doom/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(doom STATIC deh_sound.c deh_thing.c deh_weapon.c + d_dmapinfo.c d_dmapinfo.h d_englsh.h d_items.c d_items.h d_main.c d_main.h diff --git a/src/doom/Makefile.am b/src/doom/Makefile.am index cb312eb1e5..172d879193 100644 --- a/src/doom/Makefile.am +++ b/src/doom/Makefile.am @@ -19,6 +19,7 @@ deh_ptr.c \ deh_sound.c \ deh_thing.c \ deh_weapon.c \ +d_dmapinfo.c d_dmapinfo.h \ d_englsh.h \ d_items.c d_items.h \ d_main.c d_main.h \ diff --git a/src/doom/d_dmapinfo.c b/src/doom/d_dmapinfo.c new file mode 100644 index 0000000000..4a8e382906 --- /dev/null +++ b/src/doom/d_dmapinfo.c @@ -0,0 +1,680 @@ +// +// Copyright(C) 2021 James Canete +// +// 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. +// + +#include +#include +#include + +#include "i_system.h" // I_Realloc() +#include "w_wad.h" +#include "z_zone.h" + +#include "doomstat.h" +#include "d_mode.h" +#include "p_setup.h" + +#include "d_dmapinfo.h" + +dmapinfo_t dmapinfo; + +static int dmapinfo_initialized = 0; + + +static const char *skip_whitespace(const char *in, const char *in_end) +{ + for (; in < in_end; in++) + { + if (!isspace(*in)) + break; + } + + return in; +} + +static const char *skip_quote(const char *in, const char *in_end) +{ + if (*in != '"') + return in; + + for (in++; in < in_end; in++) + { + if (*in == '"') + return in + 1; + + if (*in == '\\' && in + 1 < in_end) + in++; + } + + return in; +} + +static const char *skip_block(const char *in, const char *in_end) +{ + int depth = 0; + + for (; in < in_end; in++) + { + if (*in == '{') + depth++; + else if (*in == '}') + depth--; + + if (depth == 0) + return in + 1; + + if (*in == '"') + in = skip_quote(in, in_end) - 1; + } + + return in; +} + +static const char *skip_token(const char *in, const char *in_end) +{ + if (*in == '"') + return skip_quote(in, in_end); + + if (*in == '{') + return skip_block(in, in_end); + + for (; in < in_end; in++) + { + if (isspace(*in)) + break; + } + + return in; +} + +static int is_comment(const char *in, const char *in_end) +{ + if (in + 1 < in_end && *in == '/' && in[1] == '/') + return 1; + return 0; +} + +static const char *skip_comment(const char *in, const char *in_end) +{ + if (is_comment(in, in_end)) + { + in += 2; + while (in < in_end && *in != '\n') + in++; + } + + return in; +} + +static const char *first_token(const char *in, const char *in_end) +{ + in = skip_whitespace(in, in_end); + while (is_comment(in, in_end)) + { + in = skip_comment(in, in_end); + in = skip_whitespace(in, in_end); + } + + return in; +} + +static const char *next_token(const char *in, const char *in_end) +{ + in = skip_token(in, in_end); + return first_token(in, in_end); +} + +static int escape_string(const char *in, const char *in_end, char *out, char *out_end) +{ + int len = 0; + + in_end = skip_token(in, in_end); + + if (in >= in_end) + return 0; + + if (*in != '"') + { + if (out) + { + for (; in < in_end && out < out_end; len++) + *out++ = *in++; + } + + for (; in < in_end; len++) + in++; + + if (out) + { + if (out >= out_end) + out = out_end - 1; + + *out++ = '\0'; + } + len++; + + return len; + } + + in++; + + if (in_end > in && in_end[-1] == '"') + in_end--; + + if (out) + { + for (; in < in_end && out < out_end; len++) + { + char c; + + if (*in == '\\') + { + in++; + if (in >= in_end) + break; + + switch(*in++) + { + case 'a': + c = '\a'; break; + case 'b': + c = '\b'; break; + case 'e': + c = '\e'; break; + case 'f': + c = '\f'; break; + case 'n': + c = '\n'; break; + case 'r': + c = '\r'; break; + case 't': + c = '\t'; break; + case 'v': + c = '\v'; break; + case '\\': + c = '\\'; break; + case '\'': + c = '\''; break; + case '"': + c = '\"'; break; + case '0': + c = '\0'; break; + default: + c = '?'; break; + } + } + else + { + c = *in++; + } + + *out++ = c; + } + } + + for (; in < in_end; len++) + { + if (*in == '\\') + { + in++; + if (in >= in_end) + break; + } + in++; + } + + if (out) + { + if (out >= out_end) + out = out_end - 1; + + *out++ = '\0'; + } + len++; + + return len; +} + +static int dmapinfo_add_escape_string(const char *in, const char *in_end) +{ + int p = dmapinfo.strings_len; + int l = escape_string(in, in_end, NULL, NULL); + int s = dmapinfo.strings_maxlen; + + while (p + l >= s) + { + if (!s) + s = 1024; + else + s *= 2; + } + + if (dmapinfo.strings_maxlen != s) + { + dmapinfo.strings = I_Realloc(dmapinfo.strings, s); + dmapinfo.strings_maxlen = s; + } + + escape_string(in, in_end, dmapinfo.strings + p, dmapinfo.strings + p + l); + dmapinfo.strings_len += l; + + return p; +} + +static int range_icmp(const char *a, const char *a_end, const char *b, const char *b_end) +{ + for (;a < a_end && b < b_end; a++, b++) + { + int r = tolower(*(unsigned char *)a) - tolower(*(unsigned char *)b); + if (r) + return r; + } + + if (a != a_end) + return tolower(*(unsigned char *)a); + + if (b != b_end) + return -tolower(*(unsigned char *)b); + + return 0; +} + +static int token_stricmp(const char *s, const char *t, const char *t_end) +{ + t_end = skip_token(t, t_end); + return range_icmp(s, s + strlen(s), t, t_end); +} + +static int dmapinfo_add_string_from_field(int *out, const char *field, const char **in, const char *in_end) +{ + if (token_stricmp(field, *in, in_end) != 0) + return 0; + + *in = next_token(*in, in_end); + *in = next_token(*in, in_end); + + *out = dmapinfo_add_escape_string(*in, in_end); + *in = next_token(*in, in_end); + + return 1; +} + +static int get_int_from_token(const char *in, const char *in_end) +{ + char s[256]; + int l; + + in_end = skip_token(in, in_end); + + if (*in == '"') + { + in++; + + if (in < in_end && in_end[-1] == '"') + in_end--; + } + + l = in_end - in; + if (l > 255) + l = 255; + + strncpy(s, in, l); + s[l] = '\0'; + + return atoi(s); +} + +static int dmapinfo_get_int_from_field(int *out, const char *field, const char **in, const char *in_end) +{ + if (token_stricmp(field, *in, in_end) != 0) + return 0; + + *in = next_token(*in, in_end); + *in = next_token(*in, in_end); + + if (*in < in_end) + *out = get_int_from_token(*in, in_end); + + *in = next_token(*in, in_end); + + return 1; +} + +static int dmapinfo_get_bool_from_field(int *out, const char *field, const char **in, const char *in_end) +{ + if (token_stricmp(field, *in, in_end) != 0) + return 0; + + *in = next_token(*in, in_end); + + *out = 1; + return 1; +} + +int DMAPINFO_Init() +{ + dmapinfo_initialized = 1; + memset(&dmapinfo, 0, sizeof(dmapinfo)); + return 1; +} + +int DMAPINFO_LoadLump(int lumpnum) +{ + const char *lump, *token; + int size, i; + + dmapinfo_map_t *map; + dmapinfo_episode_t *episode; + dmapinfo_endsequence_t *endseq; + + int num_maps, num_episodes, num_endseqs; + + if (!dmapinfo_initialized) + DMAPINFO_Init(); + + lump = W_CacheLumpNum(lumpnum, PU_STATIC); + size = W_LumpLength(lumpnum); + + num_maps = 0; + num_episodes = 0; + num_endseqs = 0; + + token = first_token(lump, lump + size); + while (token < lump + size) + { + if (token_stricmp("map", token, lump + size) == 0) + num_maps++; + else if (token_stricmp("episode", token, lump + size) == 0) + num_episodes++; + else if (token_stricmp("endsequence", token, lump + size) == 0) + num_endseqs++; + token = next_token(token, lump + size); + } + + //printf("%d maps\n", dmapinfo.num_maps); + //printf("%d episodes\n", dmapinfo.num_episodes); + //printf("%d endsequences\n", dmapinfo.num_endsequences); + + dmapinfo.maps = I_Realloc(dmapinfo.maps, sizeof(*dmapinfo.maps) * (dmapinfo.num_maps + num_maps)); + dmapinfo.episodes = I_Realloc(dmapinfo.episodes, sizeof(*dmapinfo.episodes) * (dmapinfo.num_episodes + num_episodes)); + dmapinfo.endsequences = I_Realloc(dmapinfo.endsequences, sizeof(*dmapinfo.endsequences) * (dmapinfo.num_endsequences + num_endseqs)); + + map = dmapinfo.maps + dmapinfo.num_maps; + for (i = 0; i < num_maps; i++, map++) + { + map->ofs_lump = -1; + map->ofs_displayed_name = -1; + map->ofs_next = -1; + map->ofs_secret_next = -1; + map->par = 0; + map->ofs_music = -1; + map->episode_number = 0; + map->map_number = 0; + map->ofs_endsequence = -1; + map->ofs_sky1 = -1; + map->sky_scroll_speed = 0; + map->map07special = 0; + } + + episode = dmapinfo.episodes + dmapinfo.num_episodes; + for (i = 0; i < num_episodes; i++, episode++) + { + episode->ofs_first_level_lump = -1; + episode->ofs_episode_name = -1; + } + + endseq = dmapinfo.endsequences + dmapinfo.num_endsequences; + for (i = 0; i < num_endseqs; i++, endseq++) + { + endseq->ofs_id = -1; + endseq->ofs_text = -1; + endseq->ofs_flat = -1; + endseq->ofs_music = -1; + } + + map = dmapinfo.maps + dmapinfo.num_maps; + episode = dmapinfo.episodes + dmapinfo.num_episodes; + endseq = dmapinfo.endsequences + dmapinfo.num_endsequences; + + token = first_token(lump, lump + size); + while (token < lump + size) + { + if (token_stricmp("map", token, lump + size) == 0) + { + token = next_token(token, lump + size); + map->ofs_lump = dmapinfo_add_escape_string(token, lump + size); + + token = next_token(token, lump + size); + map->ofs_displayed_name = dmapinfo_add_escape_string(token, lump + size); + + token = next_token(token, lump + size); + if (token < lump + size && *token == '{') + { + const char *block = token; + const char *block_end = skip_token(token, lump + size); + const char *token; + + block++; + if (block < block_end && block_end[-1] == '}') + block_end--; + + token = first_token(block, block_end); + while (token < block_end) + { + if (dmapinfo_add_string_from_field(&map->ofs_next, "next", &token, block_end)) continue; + if (dmapinfo_add_string_from_field(&map->ofs_secret_next, "secretnext", &token, block_end)) continue; + if (dmapinfo_get_int_from_field( &map->par, "par", &token, block_end)) continue; + if (dmapinfo_add_string_from_field(&map->ofs_music, "music", &token, block_end)) continue; + if (dmapinfo_get_int_from_field( &map->episode_number, "episodenumber", &token, block_end)) + { + // hack to allow multiple episodes from multiple pwads + // not that useful, since levels with same named lumps still override each other + map->episode_number += dmapinfo.num_episodes; + continue; + } + if (dmapinfo_get_int_from_field( &map->map_number, "mapnumber", &token, block_end)) continue; + if (dmapinfo_add_string_from_field(&map->ofs_endsequence, "endsequence", &token, block_end)) continue; + + if (dmapinfo_add_string_from_field(&map->ofs_sky1, "sky1", &token, block_end)) + { + if (token < block_end && *token == ',') + { + token = next_token(token, block_end); + + map->sky_scroll_speed = get_int_from_token(token, block_end); + token = next_token(token, block_end); + } + continue; + } + + if (dmapinfo_get_bool_from_field (&map->map07special, "map07special", &token, block_end)) continue; + + printf("unknown token \"%.*s\"\n", (int)(skip_token(token, block_end) - token), token); + token = next_token(token, block_end); + } + } + map++; + } + else if (token_stricmp("episode", token, lump + size) == 0) + { + token = next_token(token, lump + size); + episode->ofs_first_level_lump = dmapinfo_add_escape_string(token, lump + size); + + token = next_token(token, lump + size); + if (token < lump + size && *token == '{') + { + const char *block = token; + const char *block_end = skip_token(token, lump + size); + const char *token; + + block++; + if (block < block_end && block_end[-1] == '}') + block_end--; + + token = first_token(block, block_end); + while (token < block_end) + { + if (dmapinfo_add_string_from_field(&episode->ofs_episode_name, "name", &token, block_end)) continue; + + printf("unknown token \"%.*s\"\n", (int)(skip_token(token, block_end) - token), token); + token = next_token(token, block_end); + } + } + episode++; + } + else if (token_stricmp("endsequence", token, lump + size) == 0) + { + token = next_token(token, lump + size); + endseq->ofs_id = dmapinfo_add_escape_string(token, lump + size); + + token = next_token(token, lump + size); + if (token < lump + size && *token == '{') + { + const char *block = token; + const char *block_end = skip_token(token, lump + size); + const char *token; + + block++; + if (block < block_end && block_end[-1] == '}') + block_end--; + + token = first_token(block, block_end); + while (token < block_end) + { + if (dmapinfo_add_string_from_field(&endseq->ofs_text, "text", &token, block_end)) + { + // special casing to extend text + while (token < block_end && *token == '"') + { + dmapinfo.strings[dmapinfo.strings_len - 1] = '\n'; + dmapinfo_add_escape_string(token, block_end); + token = next_token(token, block_end); + } + + continue; + } + if (dmapinfo_add_string_from_field(&endseq->ofs_flat, "flat", &token, block_end)) continue; + if (dmapinfo_add_string_from_field(&endseq->ofs_music, "music", &token, block_end)) continue; + + printf("unknown token \"%.*s\"\n", (int)(skip_token(token, block_end) - token), token); + token = next_token(token, block_end); + } + } + endseq++; + } + + token = next_token(token, lump + size); + } + + dmapinfo.num_maps += num_maps; + dmapinfo.num_episodes += num_episodes; + dmapinfo.num_endsequences += num_endseqs; + + return 1; +} + +const char *DMAPINFO_GetString(int offset) +{ + if (offset == -1) + return NULL; + return dmapinfo.strings + offset; +} + +int DMAPINFO_GetLevelMusic(int *lump) +{ + dmapinfo_map_t *d_map = DMAPINFO_GetMap(gameepisode, gamemap); + const char *lumpname; + + if (!d_map) + return -1; + + lumpname = DMAPINFO_GetString(d_map->ofs_music); + if (!lumpname) + return -1; + + return W_CheckNumForName(lumpname); +} + +void DMAPINFO_GetFinale(const char **text, const char **flat, int *music) +{ + dmapinfo_map_t *map; + const char *endseq_name; + dmapinfo_endsequence_t *endseq; + int i; + + if (!dmapinfo.num_endsequences) + return; + + map = DMAPINFO_GetMap(gameepisode, gamemap); + if (!map) + return; + + endseq_name = DMAPINFO_GetString(map->ofs_endsequence); + + if (!endseq_name) + return; + + endseq = dmapinfo.endsequences; + for (i = 0; i < dmapinfo.num_endsequences; i++, endseq++) + { + if (strcmp(DMAPINFO_GetString(endseq->ofs_id), endseq_name) == 0) + break; + } + + if (i == dmapinfo.num_endsequences) + return; + + *music = W_CheckNumForName(DMAPINFO_GetString(endseq->ofs_music)); + *flat = DMAPINFO_GetString(endseq->ofs_flat); + *text = DMAPINFO_GetString(endseq->ofs_text); +} + +dmapinfo_map_t *DMAPINFO_GetMap(int episode, int map) +{ + dmapinfo_map_t *d_map = dmapinfo.maps; + int i; + + for (i = 0; i < dmapinfo.num_maps; i++, d_map++) + { + if (d_map->episode_number == episode && d_map->map_number == map) + { + break; + } + } + + if (i == dmapinfo.num_maps) + { + return NULL; + } + + return d_map; +} + +dmapinfo_map_t *DMAPINFO_GetMapByLumpname(const char *lumpname) +{ + dmapinfo_map_t *d_map = dmapinfo.maps; + int i; + + for (i = 0; i < dmapinfo.num_maps; i++, d_map++) + { + if (strcmp(DMAPINFO_GetString(d_map->ofs_lump), lumpname) == 0) + { + break; + } + } + + if (i == dmapinfo.num_maps) + return NULL; + + return d_map; +} diff --git a/src/doom/d_dmapinfo.h b/src/doom/d_dmapinfo.h new file mode 100644 index 0000000000..4c223a2f52 --- /dev/null +++ b/src/doom/d_dmapinfo.h @@ -0,0 +1,77 @@ +// +// Copyright(C) 2021 James Canete +// +// 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. +// + +#ifndef __DDMAPINFO_H__ +#define __DDMAPINFO_H__ + +typedef struct +{ + int ofs_lump; + int ofs_displayed_name; + int ofs_next; + int ofs_secret_next; + int par; + int ofs_music; + int episode_number; + int map_number; + int ofs_endsequence; + int ofs_sky1; + int sky_scroll_speed; + int map07special; +} +dmapinfo_map_t; + +typedef struct +{ + int ofs_first_level_lump; + int ofs_episode_name; +} +dmapinfo_episode_t; + +typedef struct +{ + int ofs_id; + int ofs_text; + int ofs_flat; + int ofs_music; +} +dmapinfo_endsequence_t; + +typedef struct +{ + dmapinfo_map_t *maps; + int num_maps; + + dmapinfo_episode_t *episodes; + int num_episodes; + + dmapinfo_endsequence_t *endsequences; + int num_endsequences; + + char *strings; + int strings_len; + int strings_maxlen; +} +dmapinfo_t; + +extern dmapinfo_t dmapinfo; + +int DMAPINFO_LoadLump(int lumpnum); +const char *DMAPINFO_GetString(int offset); +int DMAPINFO_GetLevelMusic(); +void DMAPINFO_GetFinale(const char **text, const char **flat, int *music); +dmapinfo_map_t *DMAPINFO_GetMap(int episode, int map); +dmapinfo_map_t *DMAPINFO_GetMapByLumpname(const char *lumpname); + +#endif diff --git a/src/doom/d_main.c b/src/doom/d_main.c index 0cb33ae3e0..03ee5fc22d 100644 --- a/src/doom/d_main.c +++ b/src/doom/d_main.c @@ -34,6 +34,7 @@ #include "dstrings.h" #include "sounds.h" +#include "d_dmapinfo.h" #include "d_iwad.h" #include "d_pwad.h" // [crispy] D_Load{Sigil,Nerve,Masterlevels}Wad() @@ -1915,6 +1916,23 @@ void D_DoomMain (void) printf(" loaded %i DEHACKED lumps from PWAD files.\n", loaded); } + // [crispy] load DMAPINFO lumps + if (!M_ParmExists("-nodmapinfo")) + { + int i, loaded = 0; + + for (i = numiwadlumps; i < numlumps; ++i) + { + if (!strncmp(lumpinfo[i]->name, "DMAPINFO", 8)) + { + DMAPINFO_LoadLump(i); + loaded++; + } + } + + printf(" loaded %i DMAPINFO lumps from PWAD files.\n", loaded); + } + // Set the gamedescription string. This is only possible now that // we've finished loading Dehacked patches. D_SetGameDescription(); diff --git a/src/doom/f_finale.c b/src/doom/f_finale.c index ff665c9171..93d0781604 100644 --- a/src/doom/f_finale.c +++ b/src/doom/f_finale.c @@ -35,6 +35,7 @@ #include "dstrings.h" #include "sounds.h" +#include "d_dmapinfo.h" #include "doomstat.h" #include "r_state.h" #include "m_controls.h" // [crispy] key_* @@ -120,13 +121,22 @@ extern void A_RandomJump(); void F_StartFinale (void) { size_t i; + lumpindex_t dmapinfo_music = -1; + const char *dmapinfo_flat = NULL; + const char *dmapinfo_text = NULL; gameaction = ga_nothing; gamestate = GS_FINALE; viewactive = false; automapactive = false; - if (logical_gamemission == doom) + DMAPINFO_GetFinale(&dmapinfo_text, &dmapinfo_flat, &dmapinfo_music); + + if (dmapinfo_music != -1) + { + S_ChangeMusInfoMusic(dmapinfo_music, true); + } + else if (logical_gamemission == doom) { S_ChangeMusic(mus_victor, true); } @@ -159,8 +169,9 @@ void F_StartFinale (void) // Do dehacked substitutions of strings - finaletext = DEH_String(finaletext); - finaleflat = DEH_String(finaleflat); + finaletext = dmapinfo_text ? dmapinfo_text : DEH_String(finaletext); + finaleflat = dmapinfo_flat ? dmapinfo_flat : DEH_String(finaleflat); + // [crispy] do the "char* vs. const char*" dance if (finaletext_rw) { @@ -203,6 +214,13 @@ void F_Ticker (void) if (i < MAXPLAYERS) { + // [crispy] DMAPINFO end sequence + dmapinfo_map_t *d_map = DMAPINFO_GetMap(gameepisode, gamemap); + if (d_map && d_map->ofs_endsequence != -1) + { + F_StartCast(); + } + else if (gamemission == pack_nerve && gamemap == 8) F_StartCast (); else diff --git a/src/doom/g_game.c b/src/doom/g_game.c index 7d6df7a3cb..ebd426202b 100644 --- a/src/doom/g_game.c +++ b/src/doom/g_game.c @@ -25,6 +25,8 @@ #include "doomkeys.h" #include "doomstat.h" +#include "d_dmapinfo.h" + #include "deh_main.h" #include "deh_misc.h" #include "deh_bexpars.h" // [crispy] bex_pars[] @@ -848,6 +850,19 @@ void G_DoLoadLevel (void) skytexture = R_TextureNumForName(skytexturename); } + + // [crispy] DMAPINFO skies + if (dmapinfo.num_episodes) + { + dmapinfo_map_t *d_map = DMAPINFO_GetMap(gameepisode, gamemap); + + if (d_map && d_map->ofs_sky1 != -1) + { + const char *skytexturename = DMAPINFO_GetString(d_map->ofs_sky1); + skytexture = R_TextureNumForName(skytexturename); + } + } + // [crispy] sky texture scales R_InitSkyMap(); @@ -1969,6 +1984,40 @@ void G_DoCompleted (void) wminfo.partime = TICRATE*cpars[gamemap]; } + // [crispy] DMAPINFO next map and par time + if (dmapinfo.maps) + { + dmapinfo_map_t *d_map = DMAPINFO_GetMap(gameepisode, gamemap); + + if (d_map) + { + const char *next_map_lump = NULL; + int ofs; + + ofs = d_map->ofs_next; + if (secretexit && d_map->ofs_secret_next != -1) + { + ofs = d_map->ofs_secret_next; + } + + next_map_lump = DMAPINFO_GetString(ofs); + if (next_map_lump) + { + dmapinfo_map_t *d_map2 = DMAPINFO_GetMapByLumpname(next_map_lump); + + if (d_map2) + { + wminfo.next = d_map2->map_number - 1; + } + } + + if (d_map->par) + { + wminfo.partime = TICRATE * d_map->par; + } + } + } + wminfo.pnum = consoleplayer; for (i=0 ; iofs_endsequence != -1) + { + gameaction = ga_victory; + return; + } + + // continue if next map exists + if (d_map && d_map->ofs_next != -1) + { + return; + } + } + if (secretexit) // [crispy] special-casing for E1M10 "Sewers" support // i.e. avoid drawing the splat for E1M9 already @@ -2560,6 +2627,18 @@ G_InitNew skytexture = R_TextureNumForName(skytexturename); } + // [crispy] DMAPINFO skies + if (dmapinfo.num_maps) + { + dmapinfo_map_t *d_map = DMAPINFO_GetMap(episode, map); + + if (d_map && d_map->ofs_sky1 != -1) + { + skytexturename = DMAPINFO_GetString(d_map->ofs_sky1); + skytexture = R_TextureNumForName(skytexturename); + } + } + G_DoLoadLevel (); } diff --git a/src/doom/hu_stuff.c b/src/doom/hu_stuff.c index ab01191011..dbebd71c09 100644 --- a/src/doom/hu_stuff.c +++ b/src/doom/hu_stuff.c @@ -24,6 +24,7 @@ #include "z_zone.h" +#include "d_dmapinfo.h" #include "deh_main.h" #include "i_input.h" #include "i_swap.h" @@ -735,6 +736,16 @@ void HU_Start(void) // dehacked substitution to get modified level name s = DEH_String(s); + + // [crispy] DMAPINFO map names + if (dmapinfo.num_maps) + { + dmapinfo_map_t *d_map = DMAPINFO_GetMap(gameepisode, gamemap); + if (d_map) + { + s = DMAPINFO_GetString(d_map->ofs_displayed_name); + } + } // [crispy] print the map title in white from the first colon onward M_snprintf(buf, sizeof(buf), "%s%s", ":", crstr[CR_GRAY]); diff --git a/src/doom/m_menu.c b/src/doom/m_menu.c index 9d1eaec751..fec2e9515f 100644 --- a/src/doom/m_menu.c +++ b/src/doom/m_menu.c @@ -27,6 +27,7 @@ #include "dstrings.h" #include "d_main.h" +#include "d_dmapinfo.h" #include "deh_main.h" #include "i_input.h" @@ -301,7 +302,9 @@ enum ep_end } episodes_e; -menuitem_t EpisodeMenu[]= +#define MAX_EPISODES 10 + +menuitem_t EpisodeMenu[MAX_EPISODES]= { {1,"M_EPI1", M_Episode,'k'}, {1,"M_EPI2", M_Episode,'t'}, @@ -3142,6 +3145,28 @@ void M_Init (void) } } + // [crispy] DMAPINFO episodes + if (dmapinfo.num_episodes) + { + dmapinfo_episode_t *ep; + int i; + + EpiDef.numitems = dmapinfo.num_episodes; + if (EpiDef.numitems > MAX_EPISODES) + EpiDef.numitems = MAX_EPISODES; + + ep = dmapinfo.episodes; + for (i = 0; i < EpiDef.numitems; i++, ep++) + { + EpisodeMenu[i].status = 1; + M_snprintf(EpisodeMenu[i].name, sizeof(EpisodeMenu[i].name), + "M_EPI%d", i); + EpisodeMenu[i].routine = M_Episode; + EpisodeMenu[i].alphaKey = 0; + EpisodeMenu[i].alttext = DMAPINFO_GetString(ep->ofs_episode_name); + } + } + // [crispy] rearrange Load Game and Save Game menus { const patch_t *patchl, *patchs, *patchm; diff --git a/src/doom/p_enemy.c b/src/doom/p_enemy.c index f2c595187c..ae46c92f36 100644 --- a/src/doom/p_enemy.c +++ b/src/doom/p_enemy.c @@ -32,6 +32,7 @@ #include "g_game.h" // State. +#include "d_dmapinfo.h" #include "doomstat.h" #include "r_state.h" @@ -1733,10 +1734,21 @@ void A_BossDeath (mobj_t* mo) mobj_t* mo2; line_t junk; int i; + int map07special = 0; + // [crispy] DMAPINFO map07special + if (dmapinfo.num_maps) + { + dmapinfo_map_t *d_map = DMAPINFO_GetMap(gameepisode, gamemap); + + map07special = (d_map && d_map->map07special); + } + if ( gamemode == commercial) { if (gamemap != 7 && + // [crispy] DMAPINFO map07special + !map07special && // [crispy] Master Levels in PC slot 7 !(gamemission == pack_master && (gamemap == 14 || gamemap == 15 || gamemap == 16))) return; @@ -1782,6 +1794,8 @@ void A_BossDeath (mobj_t* mo) if ( gamemode == commercial) { if (gamemap == 7 || + // [crispy] DMAPINFO map07special + map07special || // [crispy] Master Levels in PC slot 7 (gamemission == pack_master && (gamemap == 14 || gamemap == 15 || gamemap == 16))) { diff --git a/src/doom/p_setup.c b/src/doom/p_setup.c index 54db1a9266..c07d7a8fd8 100644 --- a/src/doom/p_setup.c +++ b/src/doom/p_setup.c @@ -24,6 +24,7 @@ #include "z_zone.h" +#include "d_dmapinfo.h" #include "deh_main.h" #include "i_swap.h" #include "m_argv.h" @@ -1076,6 +1077,18 @@ int P_GetNumForMap (int episode, int map, boolean critical) strcat(lumpname, "M"); } + // [crispy] DMAPINFO + if (dmapinfo.num_maps) + { + dmapinfo_map_t *d_map = DMAPINFO_GetMap(episode, map); + + if (d_map) + { + strncpy(lumpname, DMAPINFO_GetString(d_map->ofs_lump), 8); + lumpname[8] = '\0'; + } + } + return critical ? W_GetNumForName(lumpname) : W_CheckNumForName(lumpname); } diff --git a/src/doom/s_sound.c b/src/doom/s_sound.c index 9b1eb50ebc..3e443dd8c1 100644 --- a/src/doom/s_sound.c +++ b/src/doom/s_sound.c @@ -21,6 +21,7 @@ #include "i_sound.h" #include "i_system.h" +#include "d_dmapinfo.h" #include "deh_str.h" #include "doomstat.h" @@ -359,6 +360,7 @@ static short prevmap = -1; void S_Start(void) { + int dmapinfo_music_lump = -1; int cnum; int mnum; @@ -449,7 +451,11 @@ void S_Start(void) // [crispy] reset musinfo data at the start of a new map memset(&musinfo, 0, sizeof(musinfo)); - S_ChangeMusic(mnum, true); + dmapinfo_music_lump = DMAPINFO_GetLevelMusic(); + if (dmapinfo_music_lump != -1) + S_ChangeMusInfoMusic(dmapinfo_music_lump, true); + else + S_ChangeMusic(mnum, true); } void S_StopSound(mobj_t *origin) diff --git a/src/doom/wi_stuff.c b/src/doom/wi_stuff.c index ba090df000..a54a9c4dc0 100644 --- a/src/doom/wi_stuff.c +++ b/src/doom/wi_stuff.c @@ -24,6 +24,7 @@ #include "m_misc.h" #include "m_random.h" +#include "d_dmapinfo.h" #include "deh_main.h" #include "deh_bexpars.h" // [crispy] bex_pars[] #include "i_swap.h" @@ -839,6 +840,27 @@ void WI_drawShowNextLoc(void) // draw animated background WI_drawAnimatedBack(); + // [crispy] DMAPINFO next level + if (dmapinfo.num_maps) + { + dmapinfo_map_t *d_map = DMAPINFO_GetMap(gameepisode, gamemap); + + if (d_map) + { + int next = d_map->ofs_next; + if (secretexit && d_map->ofs_secret_next != -1) + { + next = d_map->ofs_secret_next; + } + + if (next != -1) + { + WI_drawEL(); + } + } + return; + } + if ( gamemode != commercial) { if (wbs->epsd > 2) @@ -1557,6 +1579,17 @@ static boolean WI_drawParTime (void) } } + // [crispy] DMAPINFO show par + if (dmapinfo.num_maps) + { + dmapinfo_map_t *d_map = DMAPINFO_GetMap(gameepisode, gamemap); + + if (d_map && d_map->par) + { + result = true; + } + } + return result; }