Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 1168-accessing-an-invalid-variable-in-ticcmd_t-crashes-the-game
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • batocera
  • blend-locking
  • blentran
  • blockmap-links
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • few-kart-lua-changes
  • ffloorclip
  • fix-1183
  • fix-cvar-conflicts
  • fix-opengl-shear-roll
  • fix-slope-plane-distortion
  • fix-sw-polyobject-interpolation
  • fix-table-key-archiving
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • font_drawer
  • frictionrefactor
  • fruits-clipper
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • gitlab-ci
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • lugstuff
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • map-components-signedness-fixes
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
141 results

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
  • voltybystorm/SRB2
  • ZenithNeko/srb-2-xp
  • Nep2Disk/SRB2
  • Cloudeon/SRB2
  • mushe/srb-2-ps-b
  • GlassCanonLover77/SRB2
  • PAS/SRB2
  • nothingjust752/SRB2
  • yusufali1009/srb-2-zintaru
125 results
Select Git revision
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2214-pre4
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • acs
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • clipmidtex
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • extra-textures
  • few-kart-lua-changes
  • ffloorclip
  • fix-167
  • fix-cvar-conflicts
  • fix-opengl-parameter-crash
  • fix-opengl-shear-roll
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • frictionrefactor
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-maxconditionsets
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • just-in-case
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • map-components-signedness-fixes
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.15
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
142 results
Show changes
......@@ -20,6 +20,7 @@
#include "g_game.h"
#include "p_local.h"
#include "p_setup.h" // levelflats for flat animation
#include "p_dialog.h"
#include "r_data.h"
#include "r_fps.h"
#include "r_textures.h"
......@@ -3594,14 +3595,14 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 459: // Control Text Prompt
// console player only
if (mo && mo->player && P_IsLocalPlayer(mo->player) && (!bot || bot != mo))
if (mo && mo->player && (!bot || bot != mo))
{
INT32 promptnum = max(0, line->args[0] - 1);
INT32 pagenum = max(0, line->args[1] - 1);
INT32 postexectag = abs(line->args[3]);
boolean closetextprompt = (line->args[2] & TMP_CLOSE);
//boolean allplayers = (line->args[2] & TMP_ALLPLAYERS);
boolean allplayers = (line->args[2] & TMP_ALLPLAYERS);
boolean runpostexec = (line->args[2] & TMP_RUNPOSTEXEC);
boolean blockcontrols = !(line->args[2] & TMP_KEEPCONTROLS);
boolean freezerealtime = !(line->args[2] & TMP_KEEPREALTIME);
......@@ -3609,12 +3610,12 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
boolean callbynamedtag = (line->args[2] & TMP_CALLBYNAME);
if (closetextprompt)
F_EndTextPrompt(false, false);
P_EndTextPrompt(mo->player, false, false);
else
{
if (callbynamedtag && line->stringargs[0] && line->stringargs[0][0])
F_GetPromptPageByNamedTag(line->stringargs[0], &promptnum, &pagenum);
F_StartTextPrompt(promptnum, pagenum, mo, runpostexec ? postexectag : 0, blockcontrols, freezerealtime);
P_GetPromptPageByNamedTag(line->stringargs[0], &promptnum, &pagenum);
P_StartTextPrompt(mo->player, promptnum, pagenum, runpostexec ? postexectag : 0, blockcontrols, freezerealtime, allplayers);
}
}
break;
......@@ -8420,6 +8421,7 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor
d->docollision = docollision;
d->doghostfade = doghostfade;
d->exactalpha = exactalpha;
d->dest_exc = NULL;
// find any existing thinkers and remove them, then replace with new data
P_ResetFakeFloorFader(rover, d, false);
......
......@@ -420,7 +420,7 @@ typedef enum
TMP_CALLBYNAME = 1<<2,
TMP_KEEPCONTROLS = 1<<3,
TMP_KEEPREALTIME = 1<<4,
//TMP_ALLPLAYERS = 1<<5,
TMP_ALLPLAYERS = 1<<5,
//TMP_FREEZETHINKERS = 1<<6,
} textmappromptflags_t;
......
......@@ -14,6 +14,7 @@
#include "doomstat.h"
#include "g_game.h"
#include "p_local.h"
#include "p_dialog.h"
#include "z_zone.h"
#include "s_sound.h"
#include "st_stuff.h"
......@@ -755,6 +756,23 @@ void P_Ticker(boolean run)
ps_lua_mobjhooks.value.i = 0;
ps_checkposition_calls.value.i = 0;
// Reassign the globaltextprompt player if they either quit, or became a spectator
if (globaltextprompt)
{
player_t *promptplayer = globaltextprompt->player;
if (!promptplayer || !playeringame[promptplayer-players] || promptplayer->spectator || promptplayer->quittime)
{
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !(players[i].spectator || players[i].quittime))
{
globaltextprompt->player = &players[i];
break;
}
}
}
}
PS_START_TIMING(ps_lua_prethinkframe_time);
LUA_HookPreThinkFrame();
PS_STOP_TIMING(ps_lua_prethinkframe_time);
......@@ -790,6 +808,11 @@ void P_Ticker(boolean run)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerAfterThink(&players[i]);
// Run text prompts
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
P_RunDialog(&players[i]);
PS_START_TIMING(ps_lua_thinkframe_time);
LUA_HookThinkFrame();
PS_STOP_TIMING(ps_lua_thinkframe_time);
......
......@@ -19,16 +19,11 @@
#include "hardware/hw_glob.h"
#endif
//
// Creates a patch.
// Assumes a PU_PATCH zone memory tag and no user, but can always be set later
//
patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest)
patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize)
{
patch_t *patch = (dest == NULL) ? Z_Calloc(sizeof(patch_t), PU_PATCH, NULL) : (patch_t *)(dest);
patch_t *patch = Z_Calloc(sizeof(patch_t), PU_PATCH, NULL);
if (source)
if (source && Picture_CheckIfDoomPatch(source, srcsize))
{
INT32 col, colsize;
size_t size = sizeof(INT32) * SHORT(source->width);
......
......@@ -18,7 +18,7 @@
#include "doomdef.h"
// Patch functions
patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest);
patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize);
void Patch_Free(patch_t *patch);
#define Patch_FreeTag(tagnum) Patch_FreeTags(tagnum, tagnum)
......
......@@ -354,7 +354,9 @@ void *Picture_PatchConvert(
if (Picture_IsInternalPatchFormat(outformat))
{
patch_t *converted = Patch_Create((softwarepatch_t *)img, size, NULL);
patch_t *converted = Patch_Create((softwarepatch_t *)img, size);
if (!converted)
return NULL;
#ifdef HWRENDER
Patch_CreateGL(converted);
......@@ -701,16 +703,13 @@ boolean Picture_IsFlatFormat(pictureformat_t format)
*/
boolean Picture_CheckIfDoomPatch(softwarepatch_t *patch, size_t size)
{
INT16 width, height;
boolean result;
// minimum length of a valid Doom patch
if (size < 13)
return false;
width = SHORT(patch->width);
height = SHORT(patch->height);
result = (height > 0 && height <= 16384 && width > 0 && width <= 16384);
INT16 width = SHORT(patch->width);
INT16 height = SHORT(patch->height);
boolean result = height > 0 && height <= 16384 && width > 0 && width <= 16384;
if (result)
{
......@@ -718,9 +717,7 @@ boolean Picture_CheckIfDoomPatch(softwarepatch_t *patch, size_t size)
// check the column directory for extra security. All columns
// must begin after the column directory, and none of them must
// point past the end of the patch.
INT16 x;
for (x = 0; x < width; x++)
for (INT16 x = 0; x < width; x++)
{
UINT32 ofs = LONG(patch->columnofs[x]);
......
......@@ -17,6 +17,7 @@
#include "z_zone.h"
#include "w_wad.h"
#include "m_tokenizer.h"
#include "m_misc.h"
#include <errno.h>
......@@ -528,35 +529,25 @@ void R_LoadParsedTranslations(void)
static boolean ExpectToken(tokenizer_t *sc, const char *expect)
{
return strcmp(sc->get(sc, 0), expect) == 0;
}
static boolean StringToNumber(const char *tkn, int *out)
{
char *endPos = NULL;
errno = 0;
int result = strtol(tkn, &endPos, 10);
if (endPos == tkn || *endPos != '\0')
return false;
if (errno == ERANGE)
const char *tkn = sc->get(sc, 0);
if (!tkn)
return false;
*out = result;
return true;
return strcmp(tkn, expect) == 0;
}
static boolean ParseNumber(tokenizer_t *sc, int *out)
{
return StringToNumber(sc->get(sc, 0), out);
const char *tkn = sc->get(sc, 0);
if (!tkn)
return false;
return M_StringToNumber(tkn, out);
}
static boolean ParseDecimal(tokenizer_t *sc, double *out)
{
const char *tkn = sc->get(sc, 0);
if (!tkn)
return false;
char *endPos = NULL;
......@@ -615,6 +606,9 @@ static struct PaletteRemapParseResult *PaletteRemap_ParseString(tokenizer_t *sc)
return ThrowError("expected '='");
const char *tkn = sc->get(sc, 0);
if (tkn == NULL)
return ThrowError("unexpected EOF");
if (strcmp(tkn, "[") == 0)
{
// translation using RGB values
......@@ -785,7 +779,7 @@ static struct PaletteRemapParseResult *PaletteRemap_ParseString(tokenizer_t *sc)
{
int pal1, pal2;
if (!StringToNumber(tkn, &pal1))
if (!M_StringToNumber(tkn, &pal1))
return ThrowError("expected a number for starting index");
if (!ExpectToken(sc, ":"))
return ThrowError("expected ':'");
......@@ -809,6 +803,13 @@ static struct PaletteRemapParseResult *PaletteRemap_ParseTranslation(const char
return result;
}
#define CHECK_EOF() \
if (!tkn) \
{ \
CONS_Alert(CONS_ERROR, "Error parsing translation '%s': Unexpected EOF\n", name); \
goto fail; \
}
void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum)
{
char *lumpData = (char *)W_CacheLumpNumPwad(wadNum, lumpnum, PU_STATIC);
......@@ -827,9 +828,11 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum)
char *name = Z_StrDup(tkn);
tkn = sc->get(sc, 0);
CHECK_EOF();
if (strcmp(tkn, ":") == 0)
{
tkn = sc->get(sc, 0);
CHECK_EOF();
base_translation = R_FindCustomTranslation(tkn);
if (base_translation == -1)
......@@ -839,6 +842,7 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum)
}
tkn = sc->get(sc, 0);
CHECK_EOF();
}
if (strcmp(tkn, "=") != 0)
......@@ -847,6 +851,15 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum)
goto fail;
}
tkn = sc->get(sc, 0);
CHECK_EOF();
if (strcmp(tkn, "\"") != 0)
{
CONS_Alert(CONS_ERROR, "Error parsing translation '%s': Expected '=', got '%s'\n", name, tkn);
goto fail;
}
tkn = sc->get(sc, 0);
CHECK_EOF();
struct PaletteRemapParseResult *result = NULL;
do {
......@@ -862,10 +875,14 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum)
if (!tkn)
break;
if (strcmp(tkn, ",") != 0)
break;
if (strcmp(tkn, "\"") != 0)
{
CONS_Alert(CONS_ERROR, "Error parsing translation '%s': Expected '=', got '%s'\n", name, tkn);
goto fail;
}
tkn = sc->get(sc, 0);
if (!tkn || strcmp(tkn, ",") != 0)
break;
} while (true);
// Allocate it and register it
......@@ -886,6 +903,8 @@ fail:
Z_Free(text);
}
#undef CHECK_EOF
typedef struct CustomTranslation
{
char *name;
......
......@@ -509,7 +509,7 @@ void SCR_ClosedCaptions(void)
if (gamestate == GS_LEVEL)
{
if (promptactive)
if (players[displayplayer].promptactive)
basey -= 42;
else if (splitscreen)
basey -= 8;
......@@ -611,6 +611,6 @@ void SCR_DisplayMarathonInfo(void)
V_DrawFill(BASEVIDWIDTH-((antisplice[1]/PRIMEV1)), BASEVIDHEIGHT-8, 1, 8, V_SNAPTOBOTTOM|V_SNAPTORIGHT|31);
#undef PRIMEV1
#undef PRIMEV2
V_DrawPromptBack(-8, cons_backcolor.value);
V_DrawPromptBack(-8, cons_backcolor.value, V_SNAPTOBOTTOM);
V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-8, flags, str);
}
......@@ -313,7 +313,8 @@
<ClInclude Include="..\netcode\server_connection.h" />
<ClInclude Include="..\netcode\tic_command.h" />
<ClInclude Include="..\p5prof.h" />
<ClInclude Include="..\p_haptic.h" />
<ClInclude Include="..\p_dialog.h" />
<ClInclude Include="..\p_dialogscript.h" />
<ClInclude Include="..\p_local.h" />
<ClInclude Include="..\p_maputl.h" />
<ClInclude Include="..\p_mobj.h" />
......@@ -351,6 +352,7 @@
<ClInclude Include="..\s_sound.h" />
<ClInclude Include="..\tables.h" />
<ClInclude Include="..\taglist.h" />
<ClInclude Include="..\usdf.h" />
<ClInclude Include="..\v_video.h" />
<ClInclude Include="..\w_wad.h" />
<ClInclude Include="..\y_inter.h" />
......@@ -473,6 +475,7 @@
<ClCompile Include="..\m_tokenizer.c" />
<ClCompile Include="..\m_perfstats.c" />
<ClCompile Include="..\m_queue.c" />
<ClCompile Include="..\m_writebuffer.c" />
<ClCompile Include="..\m_random.c" />
<ClCompile Include="..\netcode\client_connection.c" />
<ClCompile Include="..\netcode\commands.c" />
......@@ -491,9 +494,9 @@
<ClCompile Include="..\netcode\server_connection.c" />
<ClCompile Include="..\netcode\tic_command.c" />
<ClCompile Include="..\p_ceilng.c" />
<ClCompile Include="..\p_dialog.c" />
<ClCompile Include="..\p_enemy.c" />
<ClCompile Include="..\p_floor.c" />
<ClCompile Include="..\p_haptic.c" />
<ClCompile Include="..\p_inter.c" />
<ClCompile Include="..\p_lights.c" />
<ClCompile Include="..\p_map.c" />
......@@ -542,6 +545,7 @@
<ClCompile Include="..\s_sound.c" />
<ClCompile Include="..\tables.c" />
<ClCompile Include="..\taglist.c" />
<ClCompile Include="..\usdf.c" />
<ClCompile Include="..\t_facon.c">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
......
......@@ -348,6 +348,9 @@
<ClInclude Include="..\m_queue.h">
<Filter>M_Misc</Filter>
</ClInclude>
<ClInclude Include="..\m_writebuffer.h">
<Filter>M_Misc</Filter>
</ClInclude>
<ClInclude Include="..\m_random.h">
<Filter>M_Misc</Filter>
</ClInclude>
......@@ -555,8 +558,14 @@
<ClInclude Include="..\r_fps.h">
<Filter>R_Rend</Filter>
</ClInclude>
<ClInclude Include="..\p_haptic.h">
<Filter>P_Play</Filter>
<ClInclude Include="..\p_dialog.h">
<Filter>P_Dialog</Filter>
</ClInclude>
<ClInclude Include="..\p_dialogscript.h">
<Filter>P_Dialog</Filter>
</ClInclude>
<ClInclude Include="..\usdf.h">
<Filter>P_Dialog</Filter>
</ClInclude>
<ClInclude Include="..\m_easing.h">
<Filter>M_Misc</Filter>
......@@ -846,6 +855,9 @@
<ClCompile Include="..\m_queue.c">
<Filter>M_Misc</Filter>
</ClCompile>
<ClCompile Include="..\m_writebuffer.c">
<Filter>M_Misc</Filter>
</ClCompile>
<ClCompile Include="..\m_random.c">
<Filter>M_Misc</Filter>
</ClCompile>
......@@ -1108,8 +1120,14 @@
<ClCompile Include="..\r_fps.c">
<Filter>R_Rend</Filter>
</ClCompile>
<ClCompile Include="..\p_haptic.c">
<Filter>P_Play</Filter>
<ClCompile Include="..\p_dialog.c">
<Filter>P_Dialog</Filter>
</ClCompile>
<ClCompile Include="..\p_dialogscript.c">
<Filter>P_Dialog</Filter>
</ClCompile>
<ClCompile Include="..\usdf.c">
<Filter>P_Dialog</Filter>
</ClCompile>
<ClCompile Include="..\m_easing.c">
<Filter>M_Misc</Filter>
......
......@@ -31,6 +31,7 @@
#include "m_misc.h" // moviemode
#include "m_anigif.h" // cv_gif_downscale
#include "p_setup.h" // NiGHTS grading
#include "p_dialog.h"
//random index
#include "m_random.h"
......@@ -2821,6 +2822,9 @@ static void ST_overlayDrawer(void)
if (stagetitle && (!WipeInAction) && (!WipeStageTitle))
ST_drawTitleCard();
// Draw text prompt
F_TextPromptDrawer();
if (!hu_showscores && (netgame || multiplayer) && LUA_HudEnabled(hud_textspectator))
ST_drawTextHUD();
......@@ -2891,10 +2895,10 @@ void ST_Drawer(void)
st_translucency = cv_translucenthud.value;
stplyr = &players[displayplayer];
if (st_overlay)
{
// No deadview!
stplyr = &players[displayplayer];
ST_overlayDrawer();
if (splitscreen)
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file usdf.c
/// \brief USDF-SRB2 parsing
#include "usdf.h"
#include "doomstat.h"
#include "p_dialogscript.h"
#include "m_tokenizer.h"
#include "deh_soc.h"
#include "m_writebuffer.h"
#include "z_zone.h"
#include "w_wad.h"
#include <errno.h>
static INT32 P_FindTextPromptSlot(const char *name)
{
INT32 id = P_GetTextPromptByName(name);
if (id != -1)
return id;
for (INT32 i = 0; i < MAX_PROMPTS; i++)
{
if (!textprompts[i])
return i;
}
return -1;
}
INT32 P_ParsePromptBackColor(const char *color)
{
struct {
const char *name;
int id;
} all_colors[] = {
{ "white", 0 },
{ "gray", 1 },
{ "grey", 1 },
{ "black", 1 },
{ "sepia", 2 },
{ "brown", 3 },
{ "pink", 4 },
{ "raspberry", 5 },
{ "red", 6 },
{ "creamsicle", 7 },
{ "orange", 8 },
{ "gold", 9 },
{ "yellow", 10 },
{ "emerald", 11 },
{ "green", 12 },
{ "cyan", 13 },
{ "aqua", 13 },
{ "steel", 14 },
{ "periwinkle", 15 },
{ "blue", 16 },
{ "purple", 17 },
{ "lavender", 18 }
};
for (size_t i = 0; i < sizeof(all_colors) / sizeof(all_colors[0]); i++)
{
if (strcmp(color, all_colors[i].name) == 0)
return all_colors[i].id;
}
return -1;
}
void USDFParseError(int line, int alerttype, const char *format, ...)
{
char string[8192];
va_list argptr;
va_start(argptr, format);
vsnprintf(string, sizeof string, format, argptr);
va_end(argptr);
if (line >= 1)
CONS_Alert(alerttype, "While parsing DIALOGUE, line %d: %s\n", line, string);
else
CONS_Alert(alerttype, "%s\n", string);
}
#define GET_TOKEN() \
tkn = sc->get(sc, 0); \
if (!tkn) \
{ \
USDFParseError(sc->line, CONS_ERROR, "Unexpected EOF"); \
goto fail; \
}
#define IS_TOKEN(expected) \
if (!tkn || stricmp(tkn, expected) != 0) \
{ \
if (tkn) \
USDFParseError(sc->line, CONS_ERROR, "Expected '%s', got '%s'", expected, tkn); \
else \
USDFParseError(sc->line, CONS_ERROR, "Expected '%s', got EOF", expected); \
goto fail; \
}
#define EXPECT_TOKEN(expected) \
GET_TOKEN(); \
IS_TOKEN(expected)
#define CHECK_TOKEN(check) (stricmp(tkn, check) == 0)
#define EXPECT_NUMBER(what) \
int num = 0; \
if (!M_StringToNumber(tkn, &num)) \
{ \
USDFParseError(sc->line, CONS_ERROR, "In " what ": expected a number, got '%s'", tkn); \
goto fail; \
}
enum {
PARSE_STATUS_OK,
PARSE_STATUS_FAIL,
PARSE_STATUS_EOF
};
static int ExitBlock(tokenizer_t *sc, int bracket)
{
const char *tkn = sc->token[0];
if (!tkn)
return PARSE_STATUS_EOF;
else if (strcmp(tkn, "}") == 0)
return PARSE_STATUS_FAIL;
INT32 curbracket = bracket;
while (true)
{
if (strcmp(tkn, "{") == 0)
curbracket++;
else if (strcmp(tkn, "}") == 0)
{
curbracket--;
if (curbracket < bracket)
break;
}
tkn = sc->get(sc, 0);
if (!tkn)
return PARSE_STATUS_EOF;
}
return PARSE_STATUS_FAIL;
}
static int SkipBlock(tokenizer_t *sc)
{
const char *tkn = sc->token[0];
if (!tkn)
return PARSE_STATUS_EOF;
int bracket = 0;
while (true)
{
if (strcmp(tkn, "{") == 0)
bracket++;
else if (strcmp(tkn, "}") == 0)
{
bracket--;
if (bracket <= 0)
break;
}
tkn = sc->get(sc, 0);
if (!tkn)
return PARSE_STATUS_EOF;
}
return PARSE_STATUS_FAIL;
}
#define BUFWRITE(writechr) M_BufferWrite(&buf, (UINT8)(writechr))
static char *EscapeStringChars(const char *string, int tokenizer_line)
{
writebuffer_t buf;
M_BufferInit(&buf);
while (*string)
{
char chr = *string++;
if (chr == '\\')
{
chr = *string++;
switch (chr)
{
case 'n':
BUFWRITE('\n');
break;
case 't':
BUFWRITE('\t');
break;
case '\\':
BUFWRITE('\\');
break;
case '"':
BUFWRITE('\"');
break;
case '\'':
BUFWRITE('\'');
break;
case '{':
BUFWRITE('\\');
BUFWRITE('{');
break;
case 'x': {
int out = 0, c;
int i = 0;
chr = *string++;
for (i = 0; i < 5 && isxdigit(chr); i++)
{
c = ((chr <= '9') ? (chr - '0') : (tolower(chr) - 'a' + 10));
out = (out << 4) | c;
chr = *string++;
}
string--;
switch (i)
{
case 4:
BUFWRITE((out >> 8) & 0xFF);
/* FALLTHRU */
case 2:
BUFWRITE(out & 0xFF);
break;
default:
USDFParseError(tokenizer_line, CONS_WARNING, "In string: escape sequence has wrong size");
goto fail;
}
break;
}
default:
if (isdigit(chr))
{
int out = 0;
int i = 0;
do
{
out = 10*out + (chr - '0');
chr = *string++;
} while (++i < 3 && isdigit(chr));
string--;
if (out > 255)
{
USDFParseError(tokenizer_line, CONS_WARNING, "In string: escape sequence is too large");
goto fail;
}
BUFWRITE((char)out);
}
else
USDFParseError(tokenizer_line, CONS_WARNING, "In string: unknown escape sequence '\\%c'", chr);
break;
}
}
else
BUFWRITE(chr);
}
return (char*)buf.data;
fail:
M_BufferFree(&buf);
return NULL;
}
#undef BUFWRITE
#define WRITE_TEXTCHAR(writechr) M_BufferWrite(&buf, (UINT8)(writechr))
static char *ParseText(char *text, size_t *text_length, boolean parse_scripts, int tokenizer_line)
{
char *input = text;
writebuffer_t buf;
M_BufferInit(&buf);
while (*input)
{
unsigned char chr = *input;
if (chr == '\\')
{
unsigned char nextchar = input[1];
if (nextchar == '{')
{
WRITE_TEXTCHAR(nextchar);
input++;
}
else
WRITE_TEXTCHAR(chr);
}
else if (chr == '{')
{
input++;
if (parse_scripts)
P_ParseDialogScriptCommand(&input, &buf, tokenizer_line);
else
P_ParseDialogNonScriptCommand(&input, &buf, tokenizer_line);
}
else if (chr == 0xFF)
; // Just ignore it
else
WRITE_TEXTCHAR(chr);
input++;
}
*text_length = buf.pos;
return (char*)buf.data;
}
char *P_ConvertSOCPageDialog(char *text, size_t *text_length)
{
char *input = text;
writebuffer_t buf;
M_BufferInit(&buf);
while (*input)
{
unsigned char chr = *input;
if (!P_WriteDialogScriptForCutsceneTextCode((UINT8)chr, &buf))
{
if (chr != 0xFF)
WRITE_TEXTCHAR(chr);
}
input++;
}
WRITE_TEXTCHAR('\0');
*text_length = buf.pos;
return (char*)buf.data;
}
#undef WRITE_TEXTCHAR
#define IGNORE_FIELD() { \
GET_TOKEN(); \
if (CHECK_TOKEN("{")) { \
if (SkipBlock(sc) == PARSE_STATUS_EOF) \
return PARSE_STATUS_EOF; \
} else { \
if (CHECK_TOKEN("=")) {\
GET_TOKEN(); \
} \
} \
}
static int ParseChoice(textpage_t *page, tokenizer_t *sc, int bracket)
{
if (page->numchoices == MAX_PROMPT_CHOICES)
return PARSE_STATUS_FAIL;
page->numchoices++;
page->choices = Z_Realloc(page->choices, sizeof(promptchoice_t) * page->numchoices, PU_STATIC, NULL);
promptchoice_t *choice = &page->choices[page->numchoices - 1];
INT32 choiceid = page->numchoices;
const char *tkn;
writebuffer_t buf;
GET_TOKEN();
while (!CHECK_TOKEN("}"))
{
if (CHECK_TOKEN("text"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
M_BufferInit(&buf);
size_t total_length = 0;
Z_Free(choice->text);
choice->text = NULL;
while (true)
{
char *escaped = EscapeStringChars(tkn, sc->line);
if (escaped)
{
size_t parsed_length = 0;
char *parsed = ParseText(escaped, &parsed_length, false, sc->line);
M_BufferMemWrite(&buf, (UINT8 *)parsed, parsed_length);
total_length += parsed_length;
Z_Free(escaped);
}
EXPECT_TOKEN("\"");
GET_TOKEN();
if (CHECK_TOKEN(";"))
break;
else
{
IS_TOKEN("\"");
GET_TOKEN();
}
}
choice->text = Z_Realloc(buf.data, total_length + 1, PU_STATIC, NULL);
choice->text[total_length] = '\0';
buf.data = NULL;
}
else if (CHECK_TOKEN("nextpage"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("\""))
{
GET_TOKEN();
Z_Free(choice->nextpagename);
choice->nextpage = 0;
choice->nextpagename = Z_StrDup(tkn);
EXPECT_TOKEN("\"");
}
else
{
EXPECT_NUMBER("choice 'nextpage'");
Z_Free(choice->nextpagename);
choice->nextpage = num;
}
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("nextconversation"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("\""))
{
GET_TOKEN();
Z_Free(choice->nextpromptname);
choice->nextprompt = 0;
choice->nextpromptname = Z_StrDup(tkn);
EXPECT_TOKEN("\"");
}
else
{
EXPECT_NUMBER("choice 'nextconversation'");
Z_Free(choice->nextpromptname);
choice->nextprompt = num;
}
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("nexttag"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
strlcpy(choice->nexttag, tkn, sizeof(choice->nexttag));
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("executelinedef"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("choice 'executelinedef'");
choice->exectag = num;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("highlighted"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
page->startchoice = choiceid;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("nochoice"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
page->nochoice = choiceid;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("closedialog"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
choice->endprompt = true;
else if (CHECK_TOKEN("false"))
choice->endprompt = false;
EXPECT_TOKEN(";");
}
else
{
USDFParseError(sc->line, CONS_WARNING, "In choice: Unknown token '%s'", tkn);
IGNORE_FIELD();
}
GET_TOKEN();
}
return PARSE_STATUS_OK;
fail:
return ExitBlock(sc, bracket);
}
static int ParsePicture(textpage_t *page, tokenizer_t *sc, int bracket)
{
if (page->numpics == MAX_PROMPT_PICS)
return PARSE_STATUS_FAIL;
page->numpics++;
page->pics = Z_Realloc(page->pics, sizeof(cutscene_pic_t) * page->numpics, PU_STATIC, NULL);
cutscene_pic_t *pic = &page->pics[page->numpics - 1];
INT32 picid = page->numpics;
const char *tkn;
GET_TOKEN();
while (!CHECK_TOKEN("}"))
{
if (CHECK_TOKEN("name"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
strlcpy(pic->name, tkn, sizeof(pic->name));
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("x"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("picture 'x'");
pic->xcoord = num;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("y"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("picture 'y'");
pic->ycoord = num;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("duration"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("picture 'duration'");
if (num < 0)
num = 0;
pic->duration = num;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("hires"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
pic->hires = true;
else if (CHECK_TOKEN("false"))
pic->hires = false;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("start"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
page->pictostart = picid - 1;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("looppoint"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
page->pictoloop = picid;
EXPECT_TOKEN(";");
}
else
{
USDFParseError(sc->line, CONS_WARNING, "In picture: Unknown token '%s'", tkn);
IGNORE_FIELD();
}
GET_TOKEN();
}
return PARSE_STATUS_OK;
fail:
return ExitBlock(sc, bracket);
}
static int ParsePage(textprompt_t *prompt, tokenizer_t *sc, int bracket)
{
if (prompt->numpages == MAX_PAGES)
return PARSE_STATUS_FAIL;
textpage_t *page = &prompt->page[prompt->numpages];
prompt->numpages++;
P_InitTextPromptPage(page);
const char *tkn;
writebuffer_t buf;
GET_TOKEN();
while (!CHECK_TOKEN("}"))
{
if (CHECK_TOKEN("pagename"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
Z_Free(page->pagename);
page->pagename = Z_StrDup(tkn);
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("name"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
M_BufferInit(&buf);
size_t total_length = 0;
Z_Free(page->name);
page->name = NULL;
while (true)
{
char *escaped = EscapeStringChars(tkn, sc->line);
if (escaped)
{
size_t parsed_length = 0;
char *parsed = ParseText(escaped, &parsed_length, false, sc->line);
M_BufferMemWrite(&buf, (UINT8 *)parsed, parsed_length);
total_length += parsed_length;
Z_Free(escaped);
}
EXPECT_TOKEN("\"");
GET_TOKEN();
if (CHECK_TOKEN(";"))
break;
else
{
IS_TOKEN("\"");
GET_TOKEN();
}
}
page->name = Z_Realloc(buf.data, total_length + 1, PU_STATIC, NULL);
page->name[total_length] = '\0';
buf.data = NULL;
}
else if (CHECK_TOKEN("dialog"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
M_BufferInit(&buf);
size_t total_length = 0;
Z_Free(page->text);
page->text = NULL;
page->textlength = 0;
while (true)
{
char *escaped = EscapeStringChars(tkn, sc->line);
if (escaped)
{
size_t parsed_length = 0;
char *parsed = ParseText(escaped, &parsed_length, true, sc->line);
M_BufferMemWrite(&buf, (UINT8 *)parsed, parsed_length);
total_length += parsed_length;
Z_Free(escaped);
}
EXPECT_TOKEN("\"");
GET_TOKEN();
if (CHECK_TOKEN(";"))
break;
else
{
IS_TOKEN("\"");
GET_TOKEN();
}
}
page->text = Z_Realloc(buf.data, total_length + 1, PU_STATIC, NULL);
page->text[total_length] = '\0';
page->textlength = total_length;
buf.data = NULL;
}
else if (CHECK_TOKEN("icon"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
strlcpy(page->iconname, tkn, sizeof(page->iconname));
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("tag"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
strlcpy(page->tag, tkn, sizeof(page->tag));
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("textsound"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
page->textsfx = get_sfx(tkn);
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("nextpage"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("\""))
{
GET_TOKEN();
Z_Free(page->nextpagename);
page->nextpage = 0;
page->nextpagename = Z_StrDup(tkn);
EXPECT_TOKEN("\"");
}
else
{
EXPECT_NUMBER("page 'nextpage'");
Z_Free(page->nextpagename);
page->nextpage = num;
}
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("nextconversation"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("\""))
{
GET_TOKEN();
Z_Free(page->nextpromptname);
page->nextprompt = 0;
page->nextpromptname = Z_StrDup(tkn);
EXPECT_TOKEN("\"");
}
else
{
EXPECT_NUMBER("page 'nextconversation'");
Z_Free(page->nextpromptname);
page->nextprompt = num;
}
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("nexttag"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
strlcpy(page->nexttag, tkn, sizeof(page->nexttag));
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("duration"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("page 'duration'");
if (num < 0)
num = 0;
page->timetonext = num;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("textspeed"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("page 'textspeed'");
if (num < 1)
num = 1;
page->textspeed = num - 1;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("textlines"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("page 'textlines'");
if (num < 1)
num = 1;
page->lines = num;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("iconside"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("right"))
page->rightside = true;
else if (CHECK_TOKEN("left"))
page->rightside = false;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("flipicon"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
page->iconflip = true;
else if (CHECK_TOKEN("false"))
page->iconflip = false;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("displayhud"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
if (CHECK_TOKEN("show"))
page->hidehud = 0;
else if (CHECK_TOKEN("hide"))
page->hidehud = 1;
else if (CHECK_TOKEN("hideall"))
page->hidehud = 2;
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("backcolor"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
page->backcolor = P_ParsePromptBackColor(tkn);
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("choice"))
{
EXPECT_TOKEN("{");
if (page->numchoices == MAX_PROMPT_CHOICES)
{
while (!CHECK_TOKEN("}"))
{
GET_TOKEN();
}
}
else
{
if (ParseChoice(page, sc, bracket + 1) != PARSE_STATUS_OK)
{
page->numchoices--;
goto fail;
}
if (page->numchoices == MAX_PROMPT_CHOICES)
USDFParseError(sc->line, CONS_WARNING, "Conversation page exceeded max amount of choices; ignoring any more choices");
}
}
else if (CHECK_TOKEN("alignchoices"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
if (CHECK_TOKEN("left"))
page->choicesleftside = true;
else if (CHECK_TOKEN("right"))
page->choicesleftside = false;
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("picture"))
{
EXPECT_TOKEN("{");
if (page->numpics == MAX_PROMPT_PICS)
{
while (!CHECK_TOKEN("}"))
{
GET_TOKEN();
}
}
else
{
if (ParsePicture(page, sc, bracket + 1) != PARSE_STATUS_OK)
{
page->numpics--;
goto fail;
}
if (page->numpics == MAX_PROMPT_PICS)
USDFParseError(sc->line, CONS_WARNING, "Conversation page exceeded max amount of pictures; ignoring any more pictures");
}
}
else if (CHECK_TOKEN("picturesequence"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
if (CHECK_TOKEN("persist"))
page->picmode = 0;
else if (CHECK_TOKEN("loop"))
page->picmode = 1;
else if (CHECK_TOKEN("hide"))
page->picmode = 2;
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("music"))
{
EXPECT_TOKEN("=");
EXPECT_TOKEN("\"");
GET_TOKEN();
strlcpy(page->musswitch, tkn, sizeof(page->musswitch));
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("musictrack"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("page 'musictrack'");
if (num < 0)
num = 0;
page->musswitchflags = ((UINT16)num) & MUSIC_TRACKMASK;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("loopmusic"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
page->musicloop = 1;
else if (CHECK_TOKEN("false"))
page->musicloop = 0;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("executelinedef"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_NUMBER("page 'executelinedef'");
page->exectag = num;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("restoremusic"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
page->restoremusic = true;
else if (CHECK_TOKEN("false"))
page->restoremusic = false;
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("closedialog"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("true"))
page->endprompt = true;
else if (CHECK_TOKEN("false"))
page->endprompt = false;
EXPECT_TOKEN(";");
}
else
{
USDFParseError(sc->line, CONS_WARNING, "In page: Unknown token '%s'", tkn);
IGNORE_FIELD();
}
GET_TOKEN();
}
return PARSE_STATUS_OK;
fail:
M_BufferFree(&buf);
return ExitBlock(sc, bracket);
}
#undef IGNORE_FIELD
static int ParseConversation(tokenizer_t *sc, int bracket, int tokenizer_line)
{
int parse_status = PARSE_STATUS_OK;
INT32 id = 0;
char *name = NULL;
textprompt_t *prompt = NULL;
const char *tkn;
GET_TOKEN();
prompt = Z_Calloc(sizeof(textprompt_t), PU_STATIC, NULL);
while (!CHECK_TOKEN("}"))
{
if (CHECK_TOKEN("id"))
{
EXPECT_TOKEN("=");
GET_TOKEN();
if (CHECK_TOKEN("\""))
{
GET_TOKEN();
name = Z_StrDup(tkn);
EXPECT_TOKEN("\"");
}
else
{
EXPECT_NUMBER("conversation 'id'");
id = num;
}
EXPECT_TOKEN(";");
}
else if (CHECK_TOKEN("page"))
{
EXPECT_TOKEN("{");
if (prompt->numpages == MAX_PAGES)
{
while (!CHECK_TOKEN("}"))
{
GET_TOKEN();
}
}
else
{
if (ParsePage(prompt, sc, bracket + 1) != PARSE_STATUS_OK)
{
prompt->numpages--;
goto fail;
}
if (prompt->numpages == MAX_PAGES)
USDFParseError(sc->line, CONS_WARNING, "Conversation exceeded max amount of pages; ignoring any more pages");
}
}
else
{
USDFParseError(sc->line, CONS_WARNING, "In conversation: Unknown token '%s'", tkn);
GET_TOKEN();
if (CHECK_TOKEN("{"))
{
if (SkipBlock(sc) == PARSE_STATUS_EOF)
{
parse_status = PARSE_STATUS_EOF;
goto ignore;
}
}
else
{
EXPECT_TOKEN("=");
GET_TOKEN();
EXPECT_TOKEN(";");
}
}
GET_TOKEN();
}
// Now do some verifications
if (!prompt->numpages)
{
USDFParseError(tokenizer_line, CONS_WARNING, "Conversation has no pages");
goto ignore;
}
if (name)
{
id = P_FindTextPromptSlot(name);
if (id < 0)
{
CONS_Alert(CONS_WARNING, "No more free conversation slots\n");
goto ignore;
}
prompt->name = Z_StrDup(name);
P_FreeTextPrompt(textprompts[id]);
textprompts[id] = prompt;
return parse_status;
}
else if (id)
{
if (id <= 0 || id > MAX_PROMPTS)
{
CONS_Alert(CONS_WARNING, "Conversation ID %d out of range (1 - %d)\n", id, MAX_PROMPTS);
goto ignore;
}
--id;
P_FreeTextPrompt(textprompts[id]);
textprompts[id] = prompt;
return parse_status;
}
else
{
CONS_Alert(CONS_WARNING, "Conversation has missing ID\n");
goto ignore;
}
fail:
parse_status = ExitBlock(sc, bracket);
ignore:
Z_Free(prompt);
Z_Free(name);
return parse_status;
}
static void ParseDialogue(UINT16 wadNum, UINT16 lumpnum)
{
char *lumpData = (char *)W_CacheLumpNumPwad(wadNum, lumpnum, PU_STATIC);
size_t lumpLength = W_LumpLengthPwad(wadNum, lumpnum);
char *text = (char *)Z_Malloc((lumpLength + 1), PU_STATIC, NULL);
memmove(text, lumpData, lumpLength);
text[lumpLength] = '\0';
Z_Free(lumpData);
tokenizer_t *sc = Tokenizer_Open(text, 1);
const char *tkn = sc->get(sc, 0);
// Look for namespace at the beginning.
if (!CHECK_TOKEN("namespace"))
{
CONS_Alert(CONS_ERROR, "No namespace at beginning of DIALOGUE text!\n");
goto fail;
}
EXPECT_TOKEN("=");
// Check if namespace is valid.
EXPECT_TOKEN("\"");
GET_TOKEN();
if (strcmp(tkn, "srb2") != 0)
CONS_Alert(CONS_WARNING, "Invalid namespace '%s', only 'srb2' is supported.\n", tkn);
EXPECT_TOKEN("\"");
EXPECT_TOKEN(";");
GET_TOKEN();
while (tkn != NULL)
{
IS_TOKEN("conversation");
int tokenizer_line = sc->line;
EXPECT_TOKEN("{");
ParseConversation(sc, 1, tokenizer_line);
tkn = sc->get(sc, 0);
}
fail:
Tokenizer_Close(sc);
Z_Free(text);
}
#undef GET_TOKEN
#undef IS_TOKEN
#undef CHECK_TOKEN
#undef EXPECT_TOKEN
#undef EXPECT_NUMBER
void P_LoadDialogueLumps(UINT16 wadnum)
{
UINT16 lump = W_CheckNumForNamePwad("DIALOGUE", wadnum, 0);
while (lump != INT16_MAX)
{
char *name = W_GetFullLumpPathName(wadnum, lump);
CONS_Printf(M_GetText("Loading DIALOGUE from %s\n"), name);
free(name);
ParseDialogue(wadnum, lump);
lump = W_CheckNumForNamePwad("DIALOGUE", wadnum, lump + 1);
}
}
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2024 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file usdf.h
/// \brief USDF-SRB2 parsing
#ifndef __USDF_H__
#define __USDF_H__
#include "doomtype.h"
void P_LoadDialogueLumps(UINT16 wadnum);
char *P_ConvertSOCPageDialog(char *text, size_t *text_length);
INT32 P_ParsePromptBackColor(const char *color);
void USDFParseError(int line, int alerttype, const char *format, ...);
#endif
......@@ -518,7 +518,6 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
return;
#ifdef HWRENDER
//if (rendermode != render_soft && !con_startup) // Why?
if (rendermode == render_opengl)
{
HWR_DrawStretchyFixedPatch(patch, x, y, pscale, vscale, scrn, colormap);
......@@ -601,7 +600,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1));
fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
fdup >>= 1;
colfrac <<= 1;
x >>= 1;
......@@ -781,6 +780,283 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca
}
}
// Draws a texture scaled to arbitrary size.
void V_DrawTexture(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, INT32 texturenum)
{
UINT8 (*patchdrawfunc)(const UINT8*, const UINT8*, fixed_t);
UINT32 alphalevel = ((scrn & V_ALPHAMASK) >> V_ALPHASHIFT);
UINT32 blendmode = ((scrn & V_BLENDMASK) >> V_BLENDSHIFT);
fixed_t col, ofs, colfrac, rowfrac, fdup, vdup;
INT32 dup;
const column_t *column;
UINT8 *desttop, *dest, *deststart, *destend;
const UINT8 *source, *deststop;
fixed_t pwidth; // patch width
fixed_t offx = 0; // x offset
UINT8 perplayershuffle = 0;
if (rendermode == render_none || texturenum < 0 || texturenum >= numtextures)
return;
INT32 texwidth = textures[texturenum]->width;
INT32 texheight = textures[texturenum]->height;
#ifdef HWRENDER
if (rendermode == render_opengl)
{
HWR_DrawTexture(texturenum, x, y, pscale, vscale, scrn);
return;
}
#endif
patchdrawfunc = standardpdraw;
v_translevel = NULL;
if (alphalevel || blendmode)
{
if (alphalevel == 10) // V_HUDTRANSHALF
alphalevel = hudminusalpha[st_translucency];
else if (alphalevel == 11) // V_HUDTRANS
alphalevel = 10 - st_translucency;
else if (alphalevel == 12) // V_HUDTRANSDOUBLE
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
return; // invis
if (alphalevel || blendmode)
{
v_translevel = R_GetBlendTable(blendmode+1, alphalevel);
patchdrawfunc = translucentpdraw;
}
}
v_colormap = NULL;
dup = vid.dup;
if (scrn & V_SCALEPATCHMASK) switch (scrn & V_SCALEPATCHMASK)
{
case V_NOSCALEPATCH:
dup = 1;
break;
case V_SMALLSCALEPATCH:
dup = vid.smalldup;
break;
case V_MEDSCALEPATCH:
dup = vid.meddup;
break;
}
fdup = vdup = pscale * dup;
if (vscale != pscale)
vdup = vscale * dup;
colfrac = FixedDiv(FRACUNIT, fdup);
rowfrac = FixedDiv(FRACUNIT, vdup);
if (scrn & V_FLIP)
x -= FixedMul(texwidth<<FRACBITS, pscale) + 1;
if (splitscreen && (scrn & V_PERPLAYER))
{
fixed_t adjusty = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
vdup >>= 1;
rowfrac <<= 1;
y >>= 1;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((scrn & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)<<(FRACBITS-1);
fdup >>= 1;
colfrac <<= 1;
x >>= 1;
if (stplyr == &players[displayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
scrn &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
scrn &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
y += adjusty;
scrn &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[fourthdisplayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(scrn & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
y += adjusty;
scrn &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 1;
scrn &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(scrn & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle = 2;
y += adjusty;
scrn &= ~V_SNAPTOTOP;
}
}
}
desttop = screens[scrn&V_PARAMMASK];
if (!desttop)
return;
deststop = desttop + vid.rowbytes * vid.height;
if (scrn & V_NOSCALESTART)
{
x >>= FRACBITS;
y >>= FRACBITS;
desttop += (y*vid.width) + x;
}
else
{
x *= dup;
y *= dup;
x >>= FRACBITS;
y >>= FRACBITS;
// Center it if necessary
if (!(scrn & V_SCALEPATCHMASK))
{
if (vid.width != BASEVIDWIDTH * dup)
{
// dup adjustments pretend that screen width is BASEVIDWIDTH * dup,
// so center this imaginary screen
if (scrn & V_SNAPTORIGHT)
x += (vid.width - (BASEVIDWIDTH * dup));
else if (!(scrn & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * dup)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * dup)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * dup)) / 4;
}
if (vid.height != BASEVIDHEIGHT * dup)
{
// same thing here
if (scrn & V_SNAPTOBOTTOM)
y += (vid.height - (BASEVIDHEIGHT * dup));
else if (!(scrn & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * dup)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * dup)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * dup)) / 4;
}
}
desttop += (y*vid.width) + x;
}
if (pscale != FRACUNIT) // scale width properly
{
pwidth = texwidth<<FRACBITS;
pwidth = FixedMul(pwidth, pscale);
pwidth *= dup;
pwidth >>= FRACBITS;
}
else
pwidth = texwidth * dup;
deststart = desttop;
destend = desttop + pwidth;
R_CheckTextureCache(texturenum);
for (col = 0; (col>>FRACBITS) < texwidth; col += colfrac, ++offx, desttop++)
{
INT32 topdelta, prevdelta = -1;
if (scrn & V_FLIP) // offx is measured from right edge instead of left
{
if (x+pwidth-offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
break;
if (x+pwidth-offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
continue;
}
else
{
if (x+offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
continue;
if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
break;
}
if (textures[texturenum]->holes)
{
column = (const column_t *)((UINT8 *)R_GetColumn(texturenum, col>>FRACBITS) - 3);
while (column->topdelta != 0xff)
{
topdelta = column->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
source = (const UINT8 *)(column) + 3;
dest = desttop;
if (scrn & V_FLIP)
dest = deststart + (destend - desttop);
dest += FixedInt(FixedMul(topdelta<<FRACBITS,vdup))*vid.width;
for (ofs = 0; dest < deststop && (ofs>>FRACBITS) < column->length; ofs += rowfrac)
{
if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
}
}
}
else
{
column = (const column_t *)(R_GetColumn(texturenum, col>>FRACBITS));
source = (const UINT8 *)column;
dest = desttop;
if (scrn & V_FLIP)
dest = deststart + (destend - desttop);
for (ofs = 0; dest < deststop && (ofs>>FRACBITS) < texheight; ofs += rowfrac)
{
if (dest >= screens[scrn&V_PARAMMASK]) // don't draw off the top of the screen (CRASH PREVENTION)
*dest = patchdrawfunc(dest, source, ofs);
dest += vid.width;
}
}
}
}
// Draws a patch cropped and scaled to arbitrary size.
void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, patch_t *patch, const UINT8 *colormap, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h)
{
......@@ -801,7 +1077,6 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, IN
return;
#ifdef HWRENDER
//if (rendermode != render_soft && !con_startup) // Not this again
if (rendermode == render_opengl)
{
HWR_DrawCroppedPatch(patch,x,y,pscale,vscale,scrn,colormap,sx,sy,w,h);
......@@ -1188,9 +1463,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
v_translevel = R_GetBlendTable(blendmode+1, alphalevel);
}
#ifdef HWRENDER
//if (rendermode != render_soft && !con_startup) // Not this again
if (rendermode == render_opengl)
{
HWR_DrawFill(x, y, w, h, c);
......@@ -1198,8 +1471,6 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
}
#endif
if (splitscreen && (c & V_PERPLAYER))
{
fixed_t adjusty = ((c & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
......@@ -1334,7 +1605,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
c &= 255;
// borrowing this from jimitia's new hud drawing functions rq
// Draw translucent
if (alphalevel)
{
v_translevel += c<<8;
......@@ -1352,7 +1623,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
}
#ifdef HWRENDER
// This is now a function since it's otherwise repeated 2 times and honestly looks retarded:
// For OpenGL mode, returns a RGB value for the console back color
static UINT32 V_GetHWConsBackColor(void)
{
UINT8 r, g, b;
......@@ -1386,8 +1657,7 @@ static UINT32 V_GetHWConsBackColor(void)
#endif
// THANK YOU MPC!!!
// and thanks toaster for cleaning it up.
// thanks toaster for cleaning it up.
void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
{
......@@ -1549,16 +1819,17 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
c &= 255;
// Jimita (12-04-2018)
// Draw translucent
if (alphalevel)
{
fadetable = R_GetTranslucencyTable(alphalevel) + (c*256);
fadetable = R_GetTranslucencyTable(alphalevel);
for (;(--h >= 0) && dest < deststop; dest += vid.width)
{
u = 0;
while (u < w)
{
dest[u] = fadetable[consolebgmap[dest[u]]];
dest[u] = fadetable[(consolebgmap[dest[u]]<<8) + dest[u]];
u++;
}
}
......@@ -1877,28 +2148,9 @@ void V_DrawFadeConsBack(INT32 plines)
*buf = consolebgmap[*buf];
}
// Very similar to F_DrawFadeConsBack, except we draw from the middle(-ish) of the screen to the bottom.
void V_DrawPromptBack(INT32 boxheight, INT32 color)
{
UINT8 *deststop, *buf;
if (color >= 256 && color < 512)
{
if (boxheight < 0)
boxheight = -boxheight;
else // 4 lines of space plus gaps between and some leeway
boxheight = ((boxheight * 4) + (boxheight/2)*5);
V_DrawFill((BASEVIDWIDTH-(vid.width/vid.dup))/2, BASEVIDHEIGHT-boxheight, (vid.width/vid.dup),boxheight, (color-256)|V_SNAPTOBOTTOM);
return;
}
boxheight *= vid.dup;
if (color == INT32_MAX)
color = cons_backcolor.value;
#ifdef HWRENDER
if (rendermode == render_opengl)
// For OpenGL mode, returns a RGB value for the text prompt back color
static UINT32 V_GetHWPromptBackColor(INT32 color)
{
UINT32 hwcolor;
switch (color)
......@@ -1925,7 +2177,46 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color)
// Default green
default: hwcolor = 0x00800000; break;
}
HWR_DrawTutorialBack(hwcolor, boxheight);
return hwcolor;
}
#endif
// Very similar to F_DrawFadeConsBack, except we draw from the middle(-ish) of the screen to the bottom.
// TODO: Remove this and just use V_DrawPromptRect
void V_DrawPromptBack(INT32 boxheight, INT32 color, INT32 flags)
{
UINT8 *deststop, *buf;
boolean use_palette_color = color >= 256 && color < 512;
if ((flags & V_PERPLAYER) || use_palette_color)
{
if (boxheight < 0)
boxheight = -boxheight;
else // 4 lines of space plus gaps between and some leeway
boxheight = ((boxheight * 4) + (boxheight/2)*5);
INT32 x = (BASEVIDWIDTH-(vid.width / vid.dup)) / 2;
INT32 y = BASEVIDHEIGHT-boxheight;
INT32 w = vid.width / vid.dup;
INT32 h = boxheight;
if (use_palette_color)
V_DrawFill(x, y, w, h, (color-256)|flags);
else
V_DrawPromptRect(x, y, w, h, color, flags);
return;
}
boxheight *= vid.dup;
if (color == INT32_MAX)
color = cons_backcolor.value;
#ifdef HWRENDER
if (rendermode == render_opengl)
{
HWR_DrawTutorialBack(V_GetHWPromptBackColor(color), boxheight);
return;
}
#endif
......@@ -1943,6 +2234,205 @@ void V_DrawPromptBack(INT32 boxheight, INT32 color)
*buf = promptbgmap[*buf];
}
void V_DrawPromptRect(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, INT32 flags)
{
UINT8 *dest;
const UINT8 *deststop;
UINT32 alphalevel = 0;
UINT8 perplayershuffle = 0;
if (rendermode == render_none)
return;
flags &= ~255;
if (color >= 256 && color < 512)
{
V_DrawFill(x, y, w, h, (color-256)|flags);
return;
}
if (color == INT32_MAX)
color = cons_backcolor.value;
#ifdef HWRENDER
if (rendermode == render_opengl)
{
HWR_DrawConsoleFill(x, y, w, h, flags, V_GetHWPromptBackColor(color));
return;
}
#endif
CON_SetupBackColormapEx(color, true);
if ((alphalevel = ((flags & V_ALPHAMASK) >> V_ALPHASHIFT)))
{
if (alphalevel == 10) // V_HUDTRANSHALF
alphalevel = hudminusalpha[st_translucency];
else if (alphalevel == 11) // V_HUDTRANS
alphalevel = 10 - st_translucency;
else if (alphalevel == 12) // V_HUDTRANSDOUBLE
alphalevel = hudplusalpha[st_translucency];
if (alphalevel >= 10)
return; // invis
}
if (splitscreen && (flags & V_PERPLAYER))
{
fixed_t adjusty = ((flags & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
h >>= 1;
y >>= 1;
#ifdef QUADS
if (splitscreen > 1) // 3 or 4 players
{
fixed_t adjustx = ((flags & V_NOSCALESTART) ? vid.height : BASEVIDHEIGHT)>>1;
w >>= 1;
x >>= 1;
if (stplyr == &players[displayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(flags & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
flags &= ~V_SNAPTOBOTTOM|V_SNAPTORIGHT;
}
else if (stplyr == &players[secondarydisplayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
if (!(flags & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
flags &= ~V_SNAPTOBOTTOM|V_SNAPTOLEFT;
}
else if (stplyr == &players[thirddisplayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(flags & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 4;
y += adjusty;
flags &= ~V_SNAPTOTOP|V_SNAPTORIGHT;
}
else //if (stplyr == &players[fourthdisplayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
if (!(flags & (V_SNAPTOLEFT|V_SNAPTORIGHT)))
perplayershuffle |= 8;
x += adjustx;
y += adjusty;
flags &= ~V_SNAPTOTOP|V_SNAPTOLEFT;
}
}
else
#endif
// 2 players
{
if (stplyr == &players[displayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 1;
flags &= ~V_SNAPTOBOTTOM;
}
else //if (stplyr == &players[secondarydisplayplayer])
{
if (!(flags & (V_SNAPTOTOP|V_SNAPTOBOTTOM)))
perplayershuffle |= 2;
y += adjusty;
flags &= ~V_SNAPTOTOP;
}
}
}
if (!(flags & V_NOSCALESTART))
{
x *= vid.dup;
y *= vid.dup;
w *= vid.dup;
h *= vid.dup;
// Center it if necessary
if (vid.width != BASEVIDWIDTH * vid.dup)
{
// dup adjustments pretend that screen width is BASEVIDWIDTH * dup,
// so center this imaginary screen
if (flags & V_SNAPTORIGHT)
x += (vid.width - (BASEVIDWIDTH * vid.dup));
else if (!(flags & V_SNAPTOLEFT))
x += (vid.width - (BASEVIDWIDTH * vid.dup)) / 2;
if (perplayershuffle & 4)
x -= (vid.width - (BASEVIDWIDTH * vid.dup)) / 4;
else if (perplayershuffle & 8)
x += (vid.width - (BASEVIDWIDTH * vid.dup)) / 4;
}
if (vid.height != BASEVIDHEIGHT * vid.dup)
{
// same thing here
if (flags & V_SNAPTOBOTTOM)
y += (vid.height - (BASEVIDHEIGHT * vid.dup));
else if (!(flags & V_SNAPTOTOP))
y += (vid.height - (BASEVIDHEIGHT * vid.dup)) / 2;
if (perplayershuffle & 1)
y -= (vid.height - (BASEVIDHEIGHT * vid.dup)) / 4;
else if (perplayershuffle & 2)
y += (vid.height - (BASEVIDHEIGHT * vid.dup)) / 4;
}
}
if (x >= vid.width || y >= vid.height)
return; // off the screen
if (x < 0) {
w += x;
x = 0;
}
if (y < 0) {
h += y;
y = 0;
}
if (w <= 0 || h <= 0)
return; // zero width/height wouldn't draw anything
if (x + w > vid.width)
w = vid.width-x;
if (y + h > vid.height)
h = vid.height-y;
dest = screens[0] + y*vid.width + x;
deststop = screens[0] + vid.rowbytes * vid.height;
CON_SetupBackColormapEx(color, true);
// Draw translucent
if (alphalevel)
{
UINT8 *fadetable = R_GetTranslucencyTable(alphalevel);
for (;(--h >= 0) && dest < deststop; dest += vid.width)
{
INT32 u = 0;
while (u < w)
{
dest[u] = fadetable[(promptbgmap[dest[u]]<<8) + dest[u]];
u++;
}
}
}
else
{
for (;(--h >= 0) && dest < deststop; dest += vid.width)
{
INT32 u = 0;
while (u < w)
{
dest[u] = promptbgmap[dest[u]];
u++;
}
}
}
}
// Gets string colormap, used for 0x80 color codes
//
UINT8 *V_GetStringColormap(INT32 colorflags)
......@@ -2038,12 +2528,11 @@ void V_DrawChatCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, UI
// Precompile a wordwrapped string to any given width.
// This is a muuuch better method than V_WORDWRAP.
char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
void V_WordWrapInPlace(INT32 x, INT32 w, INT32 option, char *string)
{
int c;
size_t chw, i, lastusablespace = 0;
size_t slen;
char *newstring = Z_StrDup(string);
INT32 spacewidth = 4, charwidth = 0;
slen = strlen(string);
......@@ -2069,7 +2558,7 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
for (i = 0; i < slen; ++i)
{
c = newstring[i];
c = string[i];
if ((UINT8)c & 0x80) //color parsing! -Inuyasha 2.16.09
continue;
......@@ -2096,12 +2585,18 @@ char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
if (lastusablespace != 0 && x > w)
{
newstring[lastusablespace] = '\n';
string[lastusablespace] = '\n';
i = lastusablespace;
lastusablespace = 0;
x = 0;
}
}
}
char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string)
{
char *newstring = Z_StrDup(string);
V_WordWrapInPlace(x, w, option, newstring);
return newstring;
}
......
......@@ -181,6 +181,8 @@ void V_DrawBlock(INT32 x, INT32 y, INT32 scrn, INT32 width, INT32 height, const
// draw a pic_t, SCALED
void V_DrawScaledPic (INT32 px1, INT32 py1, INT32 scrn, INT32 lumpnum);
void V_DrawTexture(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 scrn, INT32 texturenum);
// fill a box with a single color
void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c);
void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c);
......@@ -193,7 +195,8 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength);
void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, UINT8 strength);
void V_DrawFadeConsBack(INT32 plines);
void V_DrawPromptBack(INT32 boxheight, INT32 color);
void V_DrawPromptBack(INT32 boxheight, INT32 color, INT32 flags);
void V_DrawPromptRect(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, INT32 flags);
// draw a single character
void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
......@@ -206,6 +209,7 @@ void V_DrawLevelTitle(INT32 x, INT32 y, INT32 option, const char *string);
// wordwrap a string using the hu_font
char *V_WordWrap(INT32 x, INT32 w, INT32 option, const char *string);
void V_WordWrapInPlace(INT32 x, INT32 w, INT32 option, char *string);
UINT8 *V_GetStringColormap(INT32 colorflags);
// draw a string using the hu_font
......
......@@ -201,6 +201,16 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors)
return handle;
}
char *W_GetFullLumpPathName(UINT16 wadnum, UINT16 lumpnum)
{
lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[lumpnum];
size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
char *name = malloc(length + 1);
snprintf(name, length + 1, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname);
name[length] = '\0';
return name;
}
// Look for all DEHACKED and Lua scripts inside a PK3 archive.
static void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile)
{
......@@ -229,11 +239,7 @@ static void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile)
for(; posStart < posEnd; posStart++)
{
lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart];
size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
char *name = malloc(length + 1);
sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname);
name[length] = '\0';
char *name = W_GetFullLumpPathName(wadnum, posStart);
CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
DEH_LoadDehackedLumpPwad(wadnum, posStart, mainfile);
free(name);
......@@ -258,12 +264,8 @@ static void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile)
lumpinfo_t *lump_p = wadfiles[wadnum]->lumpinfo;
for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump
{ // shameless copy+paste of code from LUA_LoadLump
size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
char *name = malloc(length + 1);
sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname);
name[length] = '\0';
{
char *name = W_GetFullLumpPathName(wadnum, lump);
CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
DEH_LoadDehackedLumpPwad(wadnum, lump, mainfile);
free(name);
......@@ -2063,7 +2065,7 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
if (!lumpcache[lump])
{
size_t len = W_LumpLengthPwad(wad, lump);
void *ptr, *dest, *lumpdata = Z_Malloc(len, PU_STATIC, NULL);
void *ptr, *lumpdata = Z_Malloc(len, PU_STATIC, NULL);
// read the lump in full
W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0);
......@@ -2074,8 +2076,9 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0);
#endif
dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]);
Patch_Create(ptr, len, dest);
patch_t *patch = Patch_Create(ptr, len);
Z_ChangeTag(patch, tag);
Z_SetUser(patch, &lumpcache[lump]);
Z_Free(ptr);
}
......@@ -2116,6 +2119,43 @@ void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag)
return W_CachePatchNumPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum),tag);
}
// Checks if a lump is a valid patch
boolean W_IsValidPatchNumPwad(UINT16 wad, UINT16 lump)
{
if (!TestValidLump(wad, lump))
return false;
// Must be, if it's already loaded
if (wadfiles[wad]->patchcache[lump])
return true;
size_t len = W_LumpLengthPwad(wad, lump);
#ifndef NO_PNG_LUMPS
UINT8 png_header[PNG_HEADER_SIZE];
if (!W_ReadLumpHeaderPwad(wad, lump, png_header, PNG_HEADER_SIZE, 0))
return false;
if (Picture_IsLumpPNG(png_header, len))
{
// Maybe it is?
return true;
}
#endif
void *lumpdata = W_CacheLumpNumPwad(wad, lump, PU_CACHE);
if (lumpdata)
return Picture_CheckIfDoomPatch(lumpdata, len);
return false;
}
boolean W_IsValidPatchNum(lumpnum_t lumpnum)
{
return W_IsValidPatchNumPwad(WADFILENUM(lumpnum), LUMPNUM(lumpnum));
}
void W_UnlockCachedPatch(void *patch)
{
if (!patch)
......
......@@ -168,6 +168,8 @@ void W_InitMultipleFiles(addfilelist_t *list);
INT32 W_IsPathToFolderValid(const char *path);
char *W_GetFullFolderPath(const char *path);
char *W_GetFullLumpPathName(UINT16 wadnum, UINT16 lumpnum);
const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
const char *W_CheckNameForNum(lumpnum_t lumpnum);
......@@ -225,6 +227,9 @@ void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag);
void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag);
void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag);
boolean W_IsValidPatchNumPwad(UINT16 wad, UINT16 lump);
boolean W_IsValidPatchNum(lumpnum_t lumpnum);
void W_UnlockCachedPatch(void *patch);
void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5);
......